I've read tons regarding ng-include scope issue but none seem to address the simple thing I'm trying to do. Hope someone can clarify.
This is a simplified version of what I'm trying to do but encapsulates the issue .
Here's the main page
<!DOCTYPE html>
<html lang="en" ng-app="MyApp">
<head >
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/simple-sidebar.css" rel="stylesheet">
</head>
<body>
<script src="js/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/angular.min.js"></script>
<script>
var app = angular.module('MyApp', []);
</script>
<div ng-include="'/Menu.html'" ></div>
</body>
</html>
and here is Menu.html
<div id="sidebar-wrapper" ng-app="MyApp" ng-controller="MenuController">
<ul class="sidebar-nav">
<li class="sidebar-brand">
<a href="#">
Header
</a>
</li>
<li>
Sign In
</li>
<li ng-repeat="menuItem in MainMenu.Labels">
{{menuItem}}
</li>
</ul>
<script>
app.controller('MenuController', function($scope) {
$scope.MainMenu = {"Labels":["Status","Setup"]} // this code never executes
});
</script>
</div>
How can I create a variable for binding inside menu.html... I can do this outside , but our engine will be generating the menu when that file is requested..
The issue you are facing is not actually a scope issue in this case, but rather how you are setting up your angular app. By putting the code that initializes and assigns the controller to the app in the include, the MenuController is undefined when angular tries to compile the newly included view, and the code will never run, and actually should be throwing errors in the console. I would recommend one of the following:
Remove the angular script from the templates themselves and set them up in their own files with the entire app and its modules set up to be initialized before runtime.
While i don't fully understand what you mean by Engine generating the Menu - it sounds like you are trying to use a template language to actually generate the literal javascript between the script tags from a view model of sorts to set the values. If this is the case, I would advise against this and use an angular service and the $http provider to make an ajax call to set those values in memory.
If you must structure your app this way, you will have to look into lazy loading the controller with a library like this one - https://github.com/matys84pl/angularjs-requirejs-lazy-controllers. I have not used it but from a quick browse through the readme, it appears it might be able to solve your issue will maintaining the structure of your app.
Related
I'm working on a simple GitHub pages site using HTML and javascript. Since pages do not offer support for PHP or SSI includes for an HTML header from a separate HTML file, I need to write a script which will create the header images an establish the links in the menu ribbon.
Suppose for the sake of understanding this website is composed of three files whose paths are:
root/index.html
root/A/pageA.html
root/B/pageB.html
The header should have a link to each of these files.
The only solution I have been able to come up with is to use these in all files:
<a href='https://somewhere.something/index.html'>Index</a>
<a href='https://somewhere.something/A/pageA.html'>A</a>
<a href='https://somewhere.something/B/pageB.html'>B</a>
I just was unsure if this is good practice!
If there is a way to accomplish the same effect which is more conventional I would love to hear it.
Below SO snippet not works, but here is working example - click on left menu, look into page source)
async function load(url) {
let html = await (await fetch(url)).text();
pageBody.innerHTML = html;
}
let page = location.search.substr(1) || 'index';
load(page + '.html');
<h1>My site</h1>
<ul>
<li><a href="?index" >Main</a></li>
<li><a href="?A/pageA" >A</a></li>
<li><a href="?B/pageB" >B</a></li>
</ul>
<div id="pageBody">
You can make use of HTML Imports.
The <head> section that you place on each page would reference a single import file:
<head>
<link rel="import" href="/path/to/import.html">
</head>
With your import file containing what you want to load into each page's <head> section:
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
Note that the import file should not contain <head></head> tags itself, merely the contents.
I am trying to extend my knowledge of JS by learning angular or at the very least get an understanding of angular. I am trying to go through this tutorial but I can not get my downloaded version of angular to load.
I have tried replacing my copy of of the js file with the one included on the GitHub for the tutorial and that works but when I try and link to my local copy it breaks.
This code doesn't work but as soon as the angular file is replaced with one from the repo it works. The two copies of angular are in the same lib folder and I have double checked the names. I have also tried using Google's CDN but that doesn't work either.
Any thoughts on why angular would be acting up this way?
<!doctype html>
<html ng-app>
<head>
<title>Sample AngularJS Controller</title>
</head>
<body>
<div ng-controller="TestCtrl">
<h1>{{title}}</h1>
<input type="text" ng-model="title">
</div>
<script src="lib/jquery-v1.11.1.js"></script>
<script src="lib/angular.js"></script> <!--Fresh Download-->
<!--If I replace the angular.js link with this it works.-->
<!--<script src="lib/angular-v1.2.22.js"></script>-->
<script>
function TestCtrl($scope) {
$scope.title = "Example title! (Change or delete me)";
};
</script>
</body>
</html>
I am absolutly new in AngularJS and I am following a course that show a first example of AngularJS application and I have some doubt about how exactly works.
So it is composed by these two files:
1) index.htm:
<!DOCTYPE html>
<html lang="en-us" ng-app="angularApp">
<head>
<title>Introduction to AngularJS</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta charset="UTF-8">
<!-- load bootstrap and fontawesome via CDN -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
<style>
html, body
{
font-size: 1.1em;
}
</style>
<!-- load angular via CDN -->
<script src="//code.angularjs.org/1.3.0-rc.1/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<header>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">AngularJS</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><i class="fa fa-home"></i> Home</li>
</ul>
</div>
</nav>
</header>
<div class="container">
<!-- This div and its content is the view associated to the 'mainController': -->
<div ng-controller="mainController">
<h1>Hello world!</h1>
</div>
</div>
</body>
</html>
2) app.js:
/* MODULE: one signgle object in the global namespace.
Everything insise the element having ng-app="angularApp" custom attribute is connected to the angularApp variable into the
global namespace
*/
var angularApp = angular.module('angularApp', []);
// CONTROLLERS
angularApp.controller('mainController', ['$scope', function ($scope) {
}]);
So I have some doubt about how exactly it works.
From what I have understand into the app.js file it is defined a module that substantially is a single object defined into the global namespace of my application. But what exactly represent a module in AngularJS? I came from the Spring MVC framework (and some other classic MVC) where the module represent the data that have to be shown into a view.
In Angular what exactly represent?
So from what I have understand this module is bound with the entire index.htm page because in the HTML is declared:
<html lang="en-us" ng-app="angularApp">
so I think that the ng-app="angularApp" on the html page means that the angularApp module is related to what happen inside the index.html page. Is it my reasoning correct or it is wrong?
Then inside the app.js file it is also defined a controller:
// CONTROLLERS
angularApp.controller('mainController', ['$scope', function ($scope) {
}]);
This mainController controller (is it mainController the controller name?) is defined on the angularApp model object.
Ok, I am not so into JavaScript but I think that works in the following way:
The mainController variable is a JavaScript object and by the previous line I am adding a controller field named mainController and the controller logic is implemented by the function associated to this new field (because in JavaScript a function could be a field of an object).
Is it my reasoning true or am I missing something about the controller declaration?
Another doubt is related to the use of the '$scope' variable. What exactly means? and what is the meanining of the syntax ['$scope', function ($scope) { ....CONTROLLER LOGIC....}] ?
This controller is associated to a specific view that is represented by a specific section of the index.htm page, this one:
<!-- This div and its content is the view associated to the 'mainController': -->
<div ng-controller="mainController">
<h1>Hello world!</h1>
</div>
And this generate some confusion in me because it seems pretty different from what I see in other Java MVC implementations.
So differently from Java MVC implementations, in AngularJS a view is not an entire page (as in Java could be a .jsp page) but it is a section of an HTML page bound to a specific controller by the ng-controller="mainController" custom attribute. Is it true?
And also differently from Java MVC implementations, in AngularJS (or in the previous example) a model is not only an object that contain valorized fields to display into a view but it is an object in the global namespace of the application to which are associated the controllers (as model's fields) that perform the operation on the specified view.
Are my reasoning correct or am I missing something?
Everything is fine, your controller and your view is ok.
Next step, you need to create now a service to bind a server API and act like your model.
In fact, the angular 'controller' can act like the model but if you want to do only controller/listeners things in there, you need to create a real service like this:
exemple:
app.service('ContactService', function () {
//'var' act like private
var contacts = [{
id: 0,
name: 'hello world'
}];
//'this' act like public (cool for java dev, you should feel like home :) )
this.save = function (contact) {
//here connect to your api or stay offline
}
this.get = function (id) {
}
this.delete = function (id) {
}
this.list = function () {
return contacts;
}
});
your controller
angularApp.controller('mainController', ['$scope','ContactService', function ($scope,ContactService) {
$scope.contact = ContactService.get(0)
}]);
the view
<div ng-controller="mainController">
<h1>{{contact.name}}</h1>
</div>
I'm new to angular and I'm learnign it using phpStorm tool.
It looks like I've done everything right, but I still can't get the right result when I execute the following html and Javascript codes, I did lots of researches on this and made sure that I followed the solutions provided without getting a step ahead:
index.html
<!DOCTYPE html>
<html ng-app="myApp" >
<head >
<title>Ang Tut</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Groups</h1>
<div ng-controller="GroupController">
<ul>
<li ng-repeat="group in groups" ng-model="group.group_name">
{{group.group_name}}
</li>
</ul>
</div>
</body>
<script type="text/javascript" src="angular.min.js"></script>
<script type="text/javascript" src="app.js"></script>
</html>
and my app.js file:
var app = angular.module("myApp", []);
app.controller("GroupController", function($scope){
$scope.groups= [
{"id":"144","group_name":"new grouppp"},
{"id":"303","group_name":"Combination group"},
{"id":"323","group_name":"pcb"}
]
});
Same code is working, angular.min.js may not included properly, access your index.html file using http:// instead of file://
var app = angular.module("myApp", []);
app.controller("GroupController", function($scope){
$scope.groups= [
{"id":"144","group_name":"new grouppp"},
{"id":"303","group_name":"Combination group"},
{"id":"323","group_name":"pcb"}
]
});
<!DOCTYPE html>
<html ng-app="myApp" >
<head >
<title>Ang Tut</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Groups</h1>
<div ng-controller="GroupController">
<ul>
<li ng-repeat="group in groups" ng-model="group.group_name">
{{group.group_name}}
</li>
</ul>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</html>
I had to change the js file, so to include "function()" at the beginning of it, and also "()" at the end line. That solved the problem
You have to include ngRoute in your project.
<script src="angular-route.js"> You can get this file here.
And in your app.js
var app = angular.module("myApp", ['ngRoute']);
And it will start working correctly.
Now, the reason this works in jsFiddle but not locally.
That is because if you look at left pane in jsFiddle under Frameworks & Extensions, you will find the selected option to be no wrap - in <body>
Which means that the code you write in javascript block of js fiddle will be placed inside the body tag the the generated html and therefore, you don't need ngRoute.
But while running locally, I see you have your module initialization in different file viz. app.js that is where ngRoute comes into picture.
In older versions of angular ngRoute was included in angular itself. But in latest versions (not sure from which versions) the ngRoute module is provided separately.
I just started this HTML5 project where we decided to make it a single page architecture by leveraging jQuery $.load() method. Unfortunately, as soon as the JS started to grow, we quickly started running into issues where the modules loaded into the master dashboard have no knowledge of their parent.
The architecture looks like this:
dashboard.html (master file)
moduleA.html
moduleA.js
moduleB.html
moduleB.js
moduleC.html
moduleC.js
Since we decided to also keep the JS as separate files, we are having to load all JS files through dashboard.html in order to invoke them individually when modulex is loaded.
So when loading moduleA.html into the dashboard we have to call its corresponding JS. To do this we simply wrote the JS using a Module Pattern so we can easily invoke it by doing a function call, like:
<script>
moduleA
</script>
or this if we want to access a specific property of this member.
<script>
moduleA.someMethod();
</script>
Now, I know there are is gotta be a nicer way of doing this, right? I hate having to have script tags in the HTML modules in order to load its corresponding JS file.
Another limitation of this is the fact that we no longer can work on modules individually, since the scripts and CSS invocation happens on the parent (dashboard.html) so certainly when moduleA.html is loaded directly, it is pure HTML with no script or CSS.
I looked through the other questions but I didn't see anyone with the same problem.
I looked at AngularJS, EmberJS, KO.JS and BoilerPlateJS but none of them addresses what we are trying to accomplish. The only one that has a similar single page concept is jQuery Mobile but I don't know if you can switch from jQuery to jQuery Mobile and everything remains working.
Has anyone face this issue yet? Is there a solution or would I have to go with a custom solution.
Thanks!
I could argue about AngularJS with you. It is exactly what you need
dashboard.html is layout with some directives attached, but power lies in AngularJs if you use ng-view directive
here is example:
dashboard.js
var app = angular.module("modularApp",[]);
app.config(['$routeProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
controller:'HomeCtrl',
templateUrl:'templates/home.html'
});
$routeProvider.when('/moduleA', {
controller:'ModuleACtrl',
templateUrl:'templates/moduleA.html'
});
$routeProvider.when('/moduleB', {
controller:'ModuleBCtrl',
templateUrl:'templates/moduleB.html'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
templates/dashboard.html
<html ng-app="modularApp">
<head>
<!--.... include angular minified js file and what else you need...-->
<script type="text/javascript" src="dashboard.js"></script>
<script type="text/javascript" src="moduleACtrl.js"></script>
<script type="text/javascript" src="moduleBCtrl.js"></script>
</head>
<body>
<a ng-href="#/moduleA">Open Module A View</a>
<a ng-href="#/moduleB">Open Module B View</a>
<!-- Add widgets header menus .... -->
<ng-view></ng-view>
</body>
</html>
moduleACtrl.js
var app=angular.module("modularApp");
app.controller("ModuleACtrl",function($scope){
$scope.scopeValue="Hellow from view";
});
moduleBCtrl.js
var app=angular.module("modularApp");
app.controller("ModuleBCtrl",function($scope){
$scope.scopeValue="Hellow from another view";
});
templates/moduleA.html
<div>{{scopeValue}} in module A</div>
templates/moduleB.html
<div>{{scopeValue}} in module B</div>
You can do more complex things with angular then just this. All depends on your needs. Do you have any special requirements :)
Also, you could create your own directive, like ng-view and use your own $route service and $routeProvider so you can add css and javascript you want to dynamically load when some rute match url.
so instead of above routing table, you could have
app.config(['$myRouteProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
javascript:'javascript/dashboard.js',
templateUrl:'templates/dashboard.html',
cssfile: 'css/dashboard.css'
});
$routeProvider.when('/moduleA', {
javascript:'javascript/moduleA.js',
templateUrl:'templates/moduleA.html',
cssfile: 'css/moduleA.css'
});
$routeProvider.when('/moduleB', {
javascript:'javascript/moduleB.js',
templateUrl:'templates/moduleB.html',
cssfile: 'css/moduleB.css'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
But that is, pardon on my French, stup. There are couple libs I tried in ruby on rails to acheive similar, but backend is rendering content, or just part of content. But I'm not sure which backend you are using and are you interested to switch to rails anyway.
DomController in BoilerplateJS does what you need, without using any custom HTML attributes. Your dashboard.html can just have place holders where you want to inject your components. I'm just pulling out some html below from BoilerplateJS index.html to show how it works:
<body>
<section id="page-content">
<header>
<section class="theme"></section>
<section class="language"></section>
</header>
<aside>
<section class="main-menu"></section>
</aside>
</section>
</body>
theme, language and main-menu sections above are just place holders in to which relavant components would be injected by the DomController. The DomController can be now used to register the components with appropriate selectors as below:
//scoped DomController that will be effective only on $('#page-content')
var controller = new Boiler.DomController($('#page-content'));
//add routes with DOM node selector queries and relavant components
controller.addRoutes({
".main-menu" : new MainMenuRouteHandler(context),
".language" : new LanguageRouteHandler(context),
".theme" : new ThemeRouteHandler(context)
});
controller.start();
Above code is extracted from "/boilerplatejs/src/modules/baseModule/module.js"