I started an angular project using angular-seed, and with index-async.html it uses angular-loader and script.js by default. I added two controllers to this project, each in two separate files.
The file for the first controller starts like this:
angular.module('myApp.controllers').controller('FirstCtrl', ...
The file for the second controller starts like this:
angular.module('myApp.controllers').controller('SecondCtrl', ...
And then in the main app.js file:
angular.module('myApp.controllers', []);
angular.module('myApp', [
'myApp.controllers'
])
All three files were added to script.js:
$script([
'bower_components/angular/angular.js',
'bower_components/angular-route/angular-route.js',
'js/app.js',
'js/controllers/first-ctrl.js',
'js/controllers/second-ctrl.js',
], function() {
angular.bootstrap(document, ['myApp']);
});
When I run the app, sometimes it works, and sometimes I get the errors:
Uncaught Error: [$injector:nomod] http://errors.angularjs.org/1.2.20/$injector/nomod?p0=myApp.controllers
Error: [ng:areq] Argument 'FirstCtrl' is not a function, got undefined
Note. I've left out routeprovider for brevity, but I go to the route with FirstCtrl first. I get similar issue if I go to route with SecondCtrl instead.
I don't think I've changed too much with angular-seed so am wondering if I'm doing it right with adding more controllers?
I've found that the $script.js v2 (not released yet) already support the parallel script loading but also preserve the order of execution.
You can try upgrading it by copy content in the below file and replace the old one in index-async.html.
https://github.com/ded/script.js/blob/v2/src/script.js
Related
I am working on an application, Where multiple ng-app are defined and used. Initially ng-app on different pages were not conflicting as all the pages were independent but now I have to include a header and header has its own ng-app defined.
I am using two different methods to avoid conflict of header app with other pages app.
First method:
Bootstrapping an app manually on each page:
angular.bootstrap($('#mycontact_container'),['contactsApp']);
OR
angular.element(document).ready(function() {
angular.bootstrap($('#topNavigation'),['headerApp']);
});
Second method:
angular.module("rootApp", ["headerApp", "contactsApp"]);
Where rootApp is an App defined in body tag that will include entire application within it. headerApp is an app defined on header of each page and contactsApp is app of one custom html page.
First method error:
Error: [$injector:modulerr]
http://errors.angularjs.org/1.4.8/$injector/modulerr?p0=headerApp&p1=%5B%24injector%3Amodulerr%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.4.8%2F%24injector%2Fmodulerr%3Fp0
Error on OR part of First method:
Error: [ng:btstrpd]
http://errors.angularjs.org/1.4.8/ng/btstrpd?p0=%26lt%3Bsection%20id%3D%22topNavigation%22%20class%3D%22top-navigation%20ng-scope%22%20ng-app%3D%22headerApp%22%26gt%3B
...f e?JSON.stringify(e):e;d+=c(e)}return Error(d)}}function
za(a){if(null==a||Xa(a...
i.e app is already bootstrapped.
Second Method issue:
No errors but when I try to use interpolate provide in one of my app which is included in header i.e it will be included throughout application using below code:
headerApp.config(['$interpolateProvider',
function($interpolateProvider) {
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
}
]);
app.controller('MainController', ['$scope', '$http',function MainController($scope, $http) {
$scope.first_name = "abc";
});
I get nothing printed using {$ first_name $} in my view. Ultimately my app is misbehaving. I have posted this issue in different post SO question
Can Anyone guide me what exactly I need to follow to correct the behaviour of my application with existing architecture.
I guess only angular experts can guide me well here.
Please let me know if more detailing is required.
Update
I was facing following error when I was manually bootstrapping app:
Error: [ng:btstrpd]
because I was using ng-app within html. When manually bootstrapping app then ng-app is not required.
Please note this is not a duplicate of:How to inject module and make it accesible to entrie angular app
I have a module (app.config) that I would like to inject into my entire app.
The module needs to be accessible within all other modules and submodules(modules inside modules) injected into myApp
For example, my app looks like this:
angular.module('myApp', [
'app.config',
'module#1',
'module#2',
'module#3',
'module#4'
])
.config...
/////////////////////////////////
Here's app.config
angular.module('app.config', []).
constant('NAME1', 'Name1').
constant('NAME2', 'Name2');
////////////////////
I want 'app.config' injected in such a way that it should be accesible in module#500 which is not directly a dependecy of 'myApp', but a dependecy of module#1 - which, in turn, is a dependecy of myApp.
module#1 is defined as such (as shown,module#500 is a dependecy of module#1):
angular.module('module#1', [
'module#500',
'module#501',
'module#502',
...
]);
Here's my problem:
angular.module('module#500', []).
service('serviceOne', serviceOne);
function ServiceOne($http, NAME1) {
var service = {
getMyProfile: function(){return $http.get('api/' + NAME1);}
};
return service;
}
Problem - I get an error-> Uncaught Error: [$injector:unpr] Unknown provider: NAME1Provider <-NAME1 <- serviceOne But I thought I injected it to the entire app???
I don't want to add module#500 directly as dependency to 'myApp' I wan't to leave module#500 as a dependecy of module#1. And I want to leave module#1 as a dependency of myApp
I don't want to individually inject app.config to each and every module either. Any other solutions?
I don't want to individually inject app.config to each and every
module either. Any other solutions?
I don't know what solution you could be expecting? With this line: angular.module('module#500', []). how is module#500 going to know about anything else, it has nothing given to it. Maybe I'm misunderstanding something here.
edit, as I've just read your post and comments from yesterday: I think you're not understanding dependency-injection properly. It only goes one way, module#1 has access to module#500, but module#500 doesn't have access to module#1. It has to be that way: How could you unit-test module#500 if it has some behavior that depends on module#1, which is not mentioned anywhere in its code?
I'm guessing your project doesn't really call for so many modules, if they all depend on the same config variables. Those factories and services that depend on the config variables should be in the same module with it. That is proper compartmentalization and will make your life easier in the long run.
If you don't want to make myApp dependent on app.config (though it would be the right thing to do because its submodules depend on it), you can load config module with manual bootstrapping
angular.bootstrap(document, ['myApp', 'app.config']);
instead of ng-app="myApp".
You forgot to inject NAME1 in your ServiceOne service.
eg: function ServiceOne($http, NAME1)
I'm having a really hard time trying to make modules working on an app I'm building.
This is the main file
main.js
'use strict';
angular.module('clientPortalPublic',[
'ngCookies',
'ngResource',
'ngAnimate',
'clientPortalPublic.components'
]);
angular.module('clientPortalPublic.components',[]);
And I have another file switch-login-effect.js
'use strict';
angular.module('clientPortalPublic.components').directive('switchLoginEffect',['$timeout', function($timeout){
//Content removed for clarification
}]);
The order that those files are being loaded is:
<script type="application/javascript" src="public/components/switch-login-effect.js"></script>
<script type="application/javascript" src="public/main.js"></script>
I know the switch-login-effect.js should be loaded later, since is requiring the main module, but it's being loaded dynamically and I don't control the order. BUT using manual bootstrapping shouldn't angular deal with it?
This is how I'm bootstrapping it
angular.element(document).ready(function() {
angular.bootstrap(document, ['clientPortalPublic']);
});
If I run the code above I get:
Error: [$injector:nomod] Module 'clientPortalPublic.components' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Thanks!
You are declaring a directive on a non-existant module when switch-login-effect.js loads first. It looks like you are trying to dynamically control what elements are included in the clientPortalPublic.components module simply by adding or removing scripts, but I don't think angular's dependencies are set up for that. A main reason to have those dependencies is to know exactly what you are getting.
The clientPortalPublic.components module should be defined in one script file if possible. If you have various components you can create different modules for each, but the definition of your application module should know what it is getting by the dependencies it requires. That would cause debugging headaches for one reason, "Why is my directive not working? I'm loading the components module..." (but you missed a script file you have no way to know that you need)
I really don't advise creating your app this way, but if you are dead-set you could catch the error and create the module at the start of each individual component file (and in your main.js in case you don't actually have any components but still want to require the module) so it doesn't matter which one is loaded first:
try {
angular.module('clientPortalPublic.components');
} catch (err) {
angular.module('clientPortalPublic.components',[]);
}
Or more simply just uses javascript to see if it's been executed:
var componentsModule = componentsModule ||
angular.module('clientPortalPublic.components',[]);
After reading some angular good practices and paying more attention to angular seed, I have it working.
THe thing is that they recommend to do the following when you have an structure similar to:
app/
app/components
app/components/component1
app/components/component2
app.js => angular.module('main',['main.components']);
app/components/components.js => angular.module('main.components',['main.components.component1', 'main.components.component2']);
app/components/component1.js => angular.module('main.components.component1',[]);
app/components/component2.js => angular.module('main.components.component2',[]);
Having that structure make sense and works perfectly.
:)
I've seen some projects keep all the "pieces" (controllers/services/directives) to a module in one file. angular-app does it like that.
example:
angular.module('myModule', ['depA', 'depB'])
.controller('MyController', function() {})
.service('myService', function() {});
However I've worked on teams in the past on large angular projects where individual controllers/services/directives were kept in their own files. I like the idea of keeping them in their own files to keep the files small among other reasons. The problem now is that I'm the one in charge of getting the beginning pieces and build process put together. All I had to do before was write application code and follow the standard on those projects.
In order to have separate files properly, I believe I would have to have one main module file.
example:
// file 1
angular.module('myModule', ['depA', 'depB']);
// file 2
angular.module('myModule')
.controller('MyController', function() {});
So my question is, what file loading order do I need to make sure happens? Do I only need to make sure that the main module file (file 1) is loaded before file 2?
That seems odd to me. If there was also a service file attached to the previously mentioned module and the controller file 2 was already loaded, but the service file wasn't yet, isn't it possible that angular could invoke that controller file and then eventually cause things to get out of whack?
Also, if you think I'm handling this the wrong way I would love to hear your suggestions.
Module Load Order
Just make sure that when you register a new module, by the time your application bootstraps, it's module dependencies should have already been loaded by the browser.
So anytime you do this:
angular.module('myApp', ['dep1', 'dep2', 'dep3']);
The files with dep1, dep2, and dep3 should have already been loaded by the time your application bootstraps.
If you are using <script> tags and automatic bootstrapping (the angular default) then the order of your <script> tags shouldn't matter. However, if using a library like requirejs make sure that all of your dependencies are loaded before manually bootstrapping.
Additional Considerations
As long as your modules are loaded in the correct order, then..
There is no need to worry about the order of controllers, directives, services, factories, providers, constants, or values
The order of run blocks may be important only as they relate to other run blocks since they are executed in the order in which they are registered (within a specific module).
The order of config blocks may be important only as they relate to other config blocks since they are executed in the order in which they are registered (within a specific module).
In regards to the prior 2 points, the order of dependencies (for example ['dep1', 'dep2', 'dep3'] vs ['dep2', 'dep3', 'dep1']) will also effect the order of execution of run blocks and config blocks. Angular will traverse the dependency tree twice and execute, in order, all config blocks followed by all run blocks.
Angular uses a post-order traversal to initialize modules and their associated config and run blocks. So if we represent our module dependencies as a tree:
The order of traversal is ACEDBHIGF
What I do on my projects, is keep everything separate in the developing environment, but then compile things down via gulp.js (grunt should work as well). That's a separate subject though, but here's an example of how to keep your angular code in different files.
The main file (must be loaded first) could be as follows. We will define our module, controllers, directives, repositories, or whatever else. Let's call it app.js:
// AngularJS Application File
var example = angular.module(
// ngApp name
'example',
// Default Dependencies
[
'exampleControllers',
'exampleRepositories',
'exampleDirectives'
]
);
var exampleControllers = angular.module('exampleControllers', []);
var exampleRepositories = angular.module('exampleRepositories', []);
var exampleDirectives = angular.module('exampleDirectives', []);
Now, we can access this exampleControllers, exampleRepositories, and exampleDirectives from within any javascript file that follows.
controllers.js file.
exampleControllers
// Main Controller
.controller('MainController',
[
'$scope',
'$log',
function ($scope, $log) {
$scope.hello = 'Hello World';
}
]
)
// Sub Page Controller
.controller('SubPageController',
[
'$scope',
'someService',
'$log',
function ($scope, sService, $log) {
$log.info($scope.hello);
}
]
);
anothercontroller.js file:
exampleControllers
// Another Controller
.controller('AnotherController',
[
'$scope',
'$log',
function ($scope, $log) {
$scope.helloagain = 'Hello World, from another controller';
}
]
)
And so forth.. Just make sure your app.js file gets loaded first so the example<whatever> variables are available.
I would definitely read up on gulp.js (http://gulpjs.com/). It's pretty awesome for automating work flows.
I'm new to AngularJS. In my efforts to learn, I've relied on the AngularJS tutorials. Now, I'm trying to build an app using the AngularSeed project template. I'm trying to make my project as modular as possible. For that reason, my controllers are broken out into several files. Currently, I have the following:
/app
index.html
login.html
home.html
javascript
app.js
loginCtrl.js
homeCtrl.js
my app.js file has the following:
'use strict';
var app = angular.module('site', ['ngRoute']);
app.config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/login', {templateUrl: 'app/login.html', controller:'loginCtrl'});
$routeProvider.when('/home', {templateUrl: 'app/home.html', controller:'homeCtrl'});
$routeProvider.otherwise({redirectTo: '/login'});
});
my loginCtrl.js file is very basic at the moment. It only has:
'use strict';
app.controller('loginCtrl',
function loginCtrl($scope) {
}
);
My homeCtrl.js is almost the same, except for the name. It looks like the following:
'use strict';
app.controller('homeCtrl',
function homeCtrl($scope) {
}
);
My index.html file is the angularSeed index-async.html file. However, when I load the dependencies, I have the following:
// load all of the dependencies asynchronously.
$script([
'http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular.min.js',
'http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular-route.min.js',
'javascript/app.js',
'javascript/loginCtrl.js',
'javascript/homeCtrl.js'
], function() {
// when all is done, execute bootstrap angular application
angular.bootstrap(document, ['site']);
});
My problem is, sometimes my app works and sometimes it doesn't. It's almost like something gets loaded before something else.
Occasionally, I receive this error. Other times, I get an error in the console window that says: 'Uncaught ReferenceError: app is not defined' in loginCtrl.js. Sometimes it happens with homeCtrl.js.
What am I doing wrong? It feels like I need to have my controllers in a module and pass that module in my app.config in the app.js file. However, a) I'm not sure if that allowed and b) I'm not sure how to do it.
angular-seed has had problems with an out of date loader.js (which handles $script) (issue: https://github.com/angular/angular-seed/pull/111). And this causes exactly the problem you're seeing.
Try getting the most recent loader.js (https://github.com/angular/angular.js/blob/master/src/loader.js)
And grab prefix https://github.com/angular/angular.js/blob/master/src/loader.prefix
and suffix https://github.com/angular/angular.js/blob/master/src/loader.suffix
Or you could use the regular <script> tag approach and just make sure everything is included in the right order (as #Chandermani details)
Well I am not sure how $script works, but if it's job is to load the js files async, then you cannot determine the order in which the files are loaded and executed.
In your case you some scripts have to be loaded before others. So the angular* scripts need to be loaded and executed before your app scripts are loaded. I think the order should be
Angular.min.js
angular-route.min.js
Then your script app.js
Then your controller\directives\services scripts in any order.