I've got my angular app setup something like this:
<div class="main" ng-app="myApp">
<div class="sub" ng-controller="sub1">
...
</div>
<div class="sub" ng-controller="sub2">
...
</div>
<div class="sub" ng-controller="sub3">
...
</div>
</div>
And the controllers each on different js file so the file structure is like:
Templates
-> home.html
Controllers
-> sub1Controller
-> sub2Controller
-> sub3Controller
In each controller file, I add the controller to the app by doing
ngApp.controller("sub1", function($scope){ ... });
And in the html file I linked the scripts.
After a few takes on getting the got undefined error, I found out that I am creating a new app on every directive, because to get the ngApp I used angular.module("myApp", []), unlike angular.module("myApp") that would retrieve the module. So basically my question is, where should I define the module? Since doing angular.module("myApp") won't work before angular.module("myApp", []) is invoked I can't use the one without the brackets always. Is defining the module on the containing page a bad practice? Is separating the controllers to different files instead of all in the same one a bad practice?
Separating controllers out into separate files is definitely a good idea, and I commend you for doing so. I'd recommend adding additional file above the controllers directory to define the angular module.
templates
-> home.html
js
->
angular_config.js
controllers
-> sub1Controller
-> sub2Controller
-> sub3Controller
There is nothing wrong with having all your controllers in the same file but for simplicity and future complexity reasons it is better to store each controller in a separate file.
A good solution may be to put all your controllers in controller folder(what you are currently doing )
the second thing is load another file that you can call app.js which will link all the controllers and other stuff together for example
in your app.js in the the js folder you can write :
window.onload = function(){
var app = angular.module('mymodal',[]);
app.controller('sub1Controller',function(){});
app.controller('sub2Controller',function(){});
app.controller('sub2Controller',function(){});
};
and then in your index.* file load js files in the following order
<script src="js/controllers/sub1Controller.js"></script>
<script src="js/controllers/sub2Controller.js"></script>
<script src="js/controllers/sub3Controller.js"></script>
<script src="js/app.js"></script>
By the way you can concatenate all your controllers files in one single file using task runner tools like grunt or gulp.
Related
In the tutorial:
http://www.w3schools.com/angular/angular_modules.asp
"A module is created by using the AngularJS function angular.module."
However, the module is already existent in the div tag defined before
<div ng-app="myApp">...</div>
Then what is the significance of the quoted statement above?
Danke / Dhonnobad (I hope it doesn't get deleted :) )
angular.module in fact creates module - your app configuration, so when angular process html and found ng-app directive - it will instantiate your app using that configuration.
In terms of i.e. Java you can say angular.module creates Class,
when <div ng-app="myApp"> creates instance.
The module is a container for the application controllers and directives, in general.
Incase you mention in index.html as,
<div ng-app="myapp"> ..</div>
And you maintain a separate javascript file for controller codes and directive codes, to avoid messing up in html file in between script tags, consider in index.js, You give it as
var app=angular.module("myapp",[])
And then you can add controllers like ,
app.controller("mycontroller",function($scope){
//javascript code
});
This is how controller functions act upon module specified. Hope this suffice.
I am moving my controllers from one unique file containing my whole app to separate files and get that error : "Error: [ng:areq] Argument 'MainCtrl' is not a function, got undefined"
I used the setting method to define my app in app.js :
var app = angular.module('CMT', ['ui.router', 'angularCharts', 'uiSwitch']);
I then created a file MainCtrl.js with :
angular.module('CMT').controller('MainCtrl', [
'$scope', 'reviews', '$location',
function($scope, reviews, $location){
}]);
And I have included the files in index.html after including the angular source code :
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
<script src='library/d3.min.js' type='text/javascript'></script>
<script src='library/angular-charts.min.js' type='text/javascript'></script>
<script src="node_modules/angular-ui-switch/angular-ui-switch.min.js"></script>
<script src="app.js" type='text/javascript'></script>
<script src="MainCtrl.js" type='text/javascript'></script>
Any hint or solution ?
Try the following:
In your app.js, inject your MainCtrl.js, like:
var app = angular.module('CMT', ['ui.router', 'angularCharts', 'uiSwitch', 'CMT.MainCtrl']);
And in your MainCtrl.js:
angular.module('CMT.MainCtrl', [])
EDIT:
An AngularJS module is a container. In every Angularjs app, you have one "main" module, and typically many sub-modules. These sub-modules are useful for modularizing/separating your app into components, like controllers, services etc. Initially you had one main module, which also contained the code for your controller. When you decided to move your controller out of the main module, what you wanted to do was move it into a sub-module.
So there were two problems with what you did:
You named your controller module (which is your sub-module in this case) the same name 'CMT' as that of your app/main module. Your sub-modules need to have unique names, and it is good practice to use the . separator - see this Angular style guide.
You didn't "link" your controller module to your app module in an Angular way. Just adding the script to your html isn't enough. If you have a sub-module called CMT.MainCtrl, you need to inject it into your main CMT module.
Judging by your naming convention MainCtrl.js versus something like controllers.js, I'm guessing you're organising your code by feature, instead of by type? In any case, read Angular best practices for more info on Angular directory structure.
Specify all your services/controllers/filters/directives files before the app.js file
<script src="MainCtrl.js" type='text/javascript'></script>
<script src="app.js" type='text/javascript'></script>
Note: you don't need to care about these file orders if you bundle all your script files into single file
If I have a directive and a controller in the same file:
var app = angular.module('app.navigation', []);
app.controller('NavItemCtrl', [ ....])
app.directive('navItem', [
'ribbon', '$window', function (ribbon, $window) {
return {
require: ['^navigation', '^?navGroup'],
restrict: 'AE',
controller: 'NavItemCtrl',
...
}])
Everything is fine, but if I move the controller code to a different file, because the current file is becoming too clutered, using the same module, and referencing the new controller file in my index page, the directive screams
p0=NavItemCtrl&p1=not aNaNunction got undefined
My index page is like this:
<html>
<body>
....
<script app.js ...>
<script new controller file path .... >
<script original directive file path .... >
....
</body>
</html>
What am I missing here?
[Solution] Delta is right, I figured it out:
For good housing keeping, I think it may be wise to have one JS file, listed as a dependency in the main app.js, that instantiates all the modules you will use, assuming your project is becoming large, and then reuse that instantiate w/o having any dependencies.
As example:
(1) Main App:
angular.module('MainApp', ['ngRoute', 'ngAnimate', 'app.SubApp1', 'app.SubApp2', 'app.SubApp3' ...]
(2) Then as a repository, if you will, create a new js file, say repositoryApp.js, instantiating these sub apps, making sure that this file is referenced before all other files that will use these sub app modules:
angular.module('app.SubApp1', [xxx]);
angular.module('app.SubApp2', [xxx]);
angular.module('app.SubApp3', [xxx]);
(3) Then when creating a series of directives, controllers, or whatever pertaining to a particular sub app, merely reference that sub app in the respective file as:
angular.module('app.SubApp1').controller('foo') .....
angular.module('app.SubApp1').directive('bar') .....
Without the dependency brackets as that is what threw the error for me.
in your directive are you getting you app like this
var app = angular.module('app.navigation');
if you put the brackets after it like your first example you will just be replacing what you have currently instead of getting it.
This get a new module
var app = angular.module('app.navigation', []);
This gets an existing modules.
var app = angular.module('app.navigation');
Notice the exclusion of the brackets in the second example.
Good morning,
I am building an MVC5 application that includes a SPA (single page application) which runs in a small part of my bigger ASP.NET MVC5 application.
So here is my angular app setup:
var storeApp = angular.module('AngularStore', ['ngRoute']).
config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.
when('/shop', {
templateUrl: 'Templates/browse.html',
controller: storeController
}).
otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(true);
}]);
As you can see it loads browse.html which is an html template.
My _Layout.cshtml file has the angular app registered at the top:
<html lang="en" ng-app="AngularStore">
Inside here, as with any ASP.NET MVC application it also has the following:
#RenderBody()
ASP.NET Mvc loads an Index.cshtml into the render body.
Here is my Index.cshtml:
#{
ViewBag.Title = "Shop";
ViewBag.InitModule = "AngularStore";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section MyScripts
{
<script src="~/js/product.js" type="text/javascript"></script>
<script src="~/js/store.js" type="text/javascript"></script>
<script src="~/js/shoppingCart.js" type="text/javascript"></script>
<script src="~/js/app.js" type="text/javascript"></script>
<script src="~/js/controller.js" type="text/javascript"></script>
}
<div ng-view></div>
As you can see the div that has the ng-view angular attribute on it is where my browse.html template will get loaded.
This all works as expected but here is my puzzle.
My browse.html template is a list of products. You can click "add to cart" and angular adds the product to the cart.
The thing is I want the count of the things in the cart and the money value to appear on the _Layout.cshtml. So in essence the count and money will appear no matter what template angular loads.
So, I want to put some angular stuff inside the top part (header) of my _Layout.cshtml that will look at the cart and show the count and money value.
This is probably easy but i'm having trouble figuring out how to get it to work and also structure it the right way.
Maybe I need to use ng-contoller on a on my _Layout.cshtml?
Any pointers would be greatly appreciated.
If you live in Melbourne i'll buy you a beer!
thanks
Russ
I'm also building applications that are mainly MVC but have several pages that are using angularjs and are mini-SPA's. You're going to need a controller used at your _Layout level. You can do this simply by creating a div at that level and using ng-controller directive as mentioned in your question. You do not need to do anything with routes at all, ng-controller defines the controller to use, and actually I don't use angularjs routing in my miniSPA's (though I can see where you might want to if your url changes within a single page).
What I think would be more appropriate however is to have a Partial view (which you can render from your _Layout if you want it always to be there), and within that partial view use ng-controller so you can have one controller for your cart and another controller for your shop. You have a number of options to communicate between the controllers. You could use the $scope.$root, or store your products in your Session data.
Keep a root controller in the Layout which includes header HTML. Define count variable in root controller and bind it to any header HTML element to display the count value. Now you can access the scope of the root controller in your nested controller (in your case storeController). You can set the count variable (from root controller) value inside the storeController which will automatically display the value in header as it's binded to some header HTML element.
New to Angular. I feel like I'm missing something obvious: Shouldn't I easily be able to run to separate AngularJs apps (modules) in the same html page? Something like this:
<section ng-app="HelloWorldApp" ng-controller="HelloWorldController">
Hello {{name}}!
</section>
<br />
<section ng-app="MyNameIsApp" ng-controller="MyNameIsController">
My Name is {{FirstName}} {{LastName}}!
</section>
Javascript:
var HelloWorldApp = angular.module('HelloWorldApp', []);
HelloWorldApp.controller('HelloWorldController', function($scope) {
$scope.name = 'World';
});
var MyNameIsApp = angular.module('MyNameIsApp', []);
MyNameIsApp.controller('MyNameIsController', function($scope) {
$scope.FirstName = 'John';
$scope.LastName = 'Smith';
});
This only runs the first module, while the second doesn't appear to do anything. I want to do this so that I can build reusable, encapsulated directives for multiple pages that don't have to name their modules the same thing.
Live Example: http://plnkr.co/edit/cE6i3ouKz8SeQeA5h3VJ
We ended up building small hierarchy of modules, however my original question can done, with just a bit of work (see below).
It is possible, but it requires a little bit coding by hand. You need to bootstrap the angular apps on your own. Don't worry, it is not that complicated
Do not add ng-app attributes in your HTML
Make sure you can fetch the DOM elements holding the app
When DOM is loaded you need to start the apps on your own: angular.bootstrap( domElement, ['AppName']);
Fork of you plunker which works: http://plnkr.co/edit/c5zWOMoah2jHYhR5Cktp
According to the Angular docs for ngApp:
Use this directive to auto-bootstrap an application. Only one
directive can be used per HTML document. The directive designates the
root of the application and is typically placed at the root of the
page.
Seems it's by design.
You can specify any nested apps in the module def of the main one.
angular.module("myapp", ['statusapp', 'tickerapp']).controller(....
and in a separate file, you have the other apps defined. We're using a template engine which hides some of this, but you'll end up with HTML that contains nested ng-apps and javascript for each one that defines the module/controller. The code above is the trick to getting more than one bootstrapped.