AngularJS - Why are dependencies with modules necessary? - javascript

Can you tell me why it is recommended to add dependency modules to the creation of a module?
I've tried to run the code without adding the modules TodoApp.controllers and TodoApp.services. Even though I removed them, everything ran perfectly .. (I call a service via those two files)
app.js
// Injects all the needed modules
var TodoApp = angular.module("TodoApp", [
"ngRoute",
"ngResource",
"TodoApp.controllers",
"TodoApp.services"
]).
config(function ($routeProvider) {
$routeProvider.
when('/', { controller: "listCtrl", templateUrl: 'list.html' }).
otherwise({ redirectTo: '/' });
});
Update
Thank you for your response! :)
Unfortunately, those files don't share a common variable:
That was actually the reason why I didn't understand the set of problem. For me, this code gets stored in nowhere. Could it be because of the dot notation in the naming?
controller.js
angular.module('TodoApp.controllers', []).
controller('listCtrl', function ($scope, $location, todoApiService) {
$scope.todos = todoApiService.getMyTodos().query();
});
services.js
angular.module('TodoApp.services', []).
factory('todoApiService', function ($resource) {
var todoApi = {};
todoApi.getMyTodos = function () {
return $resource('/api/todo/:id', { id: '#id' }, { update: { method: 'PUT' } });
};
return todoApi;
});

You do not need to inject controllers & services since they have to be part of a module anyway.
You could have them labeled like so in the other files:
TodoApp.controllers(/* ... */)
TodoApp.services(/* ... */)
They are already attaching themselves to the module because of the TodoApp variable (which in-turn is angular.module('TodoApp').
It looks like you call the module directly each time:
angular.module('TodoApp.controllers', []).
controller('listCtrl', /* etc etc */ );
Each way, you are simply adding more things (in typical dot notation) to your overall Module, and angular understand it's TodoApp since you are starting it with that.
But sometimes you'll see people inject other modules, in a way inheriting the modules controllers / directives / services / etc.
var HelperModule = angular.module('HelperModule', /*...*/);
HelperModule.directive('headerLinks', /*...*/);
HelperModule.factory('BaseFactory', /*...*/);
// etc etc
var TodoApp = angular.module("TodoApp", ["HelperModule"]); // <-- Module injected
// TodoApp now contains all the directives/etc from that module!
Hope that helps!

Related

How to separate a component's controller function into a different file?

I have been searching and searching, and maybe I have been using the wrong terms on my search, but I couldn't find exactly what I was looking for. I am using Angular 1.5 with components.
Say I have a component A:
var module = angular.module('myApp');
module.component('A', {
templateUrl: 'template.html',
controller: function(){}
});
Now this is very simple. I also know that I can do the following, as long as 'myControllerFunction' is in the same file.
var module = angular.module('myApp');
module.component('A', {
templateUrl: 'template.html',
controller: myControllerFunction
});
function myControllerFunction(){}
Now what do I do if I want to have a file only for 'myControllerFunction'? How do I access that function inside that file from within my component?
I know that using Node.js is easy to use exports and require(), but I am not quite familiar what to do using AngularJS.
Any help would be very much appreciated! Thank you!
you can refer the controller from your module like below :
module.component('A', {
templateUrl: 'template.html',
controller: 'YourController'
});
Then in the another file you can define controller with the method.
function() {
'use strict';
angular.module('app').controller('YourController',
YourController);
YourController.$inject = [ '$scope', '$http', '$window',
'$rootScope' ];
function YourController($scope, $http, $window, $rootScope) {
function yourcontrollerfunction() {
}
yourcontrollerfunction();
}
})();
yourcontrollerfunction function will automatically called when controller is loaded. Controller will be loaded when your module is loaded.

What is the meaning of the square brackets in “.module("modulename", […])” of AngularJS

I just saw an example of routing in AngularJS. I would like to know the relation ship between dependency 'ngRoute' and module mainApp, in synatx var mainApp = angular.module("mainApp", ['ngRoute']);.
Previously I've seen examples with empty square brackets in module declaration.
Below is the whole context of code:
var mainApp = angular.module("mainApp", ['ngRoute']);
mainApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/addStudent', {
templateUrl: 'addStudent.htm',
controller: 'AddStudentController'
}).
when('/viewStudents', {
templateUrl: 'viewStudents.htm',
controller: 'ViewStudentsController'
}).
otherwise({
redirectTo: '/addStudent'
});
}]);
In angular, when defining a module(creating it), you pass it the names of other modules it depends on as an array (in square brackets).
In your example, the mainApp-module depends on the ngRoute-module, making the components of ngRoute(directives, services, factories, values...) available for dependency injection for the components in mainApp. To define a module that does not depend on any other modules, you pass an empty array ([]) See the angular documentation for some more info on modules
[...] defines an array
In the angular case.
mainApp is a main module( main array) and ngRoute is a sub module(like array of object).
The sample is
var ngRoute=[];//{}
var mainApp=[ngRoute];// now the `mainApp` includes the `ngRoute`

Angular controller is not instantiated after minification

My original source code looks like this:
(function(angular) {
'use strict';
/* #ngInject */
function config($stateProvider) {
$stateProvider
.state('bar.foo', {
url: '/foo',
templateUrl: 'foo-view.html',
controller: 'FooController',
controllerAs: 'vm'
});
}
/* #ngInject */
function FooController() {
window.alert('foo');
}
angular
.module('my.foo', [])
.config(config)
.controller('FooController', FooController);
}(angular));
It works fine this way.
Then I minify it using ngAnnotate and UglifyJS, and get this code (formatted to easier reading):
function (a) {
'use strict';
function b(a) {
a.state('bar.foo', {
url: '/foo',
templateUrl: 'foo-view.html',
controller: 'FooController',
controllerAs: 'vm'
})
}
function c() {
window.alert('foo')
}
b.$inject = ['$stateProvider'],
a.module('my.foo', [])
.config(b)
.controller('FooController', c)
}(angular),
And, it does not work. When I go to the state bar.foo the controller do not get called. Others controllers and router states works fine. This one seems to get muted, the code inside the controller function is not called.
The console do not show any errors.
I do not know what to do or where to look at.
The entire JavaScript is bigger and is a concatenation of several small files. The single minified JS file has controllers before and after this one that works fine.
Debugging the minified file shows that the JavaScript is issuing the module definition calls to AngularJS, so the module, config and controller methods of Angular are called.
What should I search or check in the code? Am I missing something?
My problem was that I'm also compiling Jade templates into HTML. And my build settings for production environment is a little different than for development. Jade were outputting <div ui-view="ui-view"> instead of an empty attribute, preventing the ui-router to load the template into the parent view, causing the controller to not being instantiated.
The minification of the JavaScript was not the problem. Sorry.
These questions helped me out:
ui-router nested route controller isn't being called
Grunt jade compiler filling out empty attributes

AngularJS seed: putting JavaScript into separate files (app.js, controllers.js, directives.js, filters.js, services.js)

I'm using the angular-seed template to structure my application. Initially I put all my JavaScript code into a single file, main.js. This file contained my module declaration, controllers, directives, filters, and services. The application works fine like this, but I'm worried about scalability and maintainability as my application becomes more complex. I noticed that the angular-seed template has separate files for each of these, so I've attempted to distribute my code from the single main.js file into each of the other files mentioned in the title to this question and found in the app/js directory of the angular-seed template.
My question is: how do I manage the dependencies to get the application to work? The existing documentation found here isn't very clear in this regard since each of the examples given shows a single JavaScript source file.
An example of what I have is:
app.js
angular.module('myApp',
['myApp.filters',
'myApp.services',
'myApp.controllers']);
controllers.js
angular.module('myApp.controllers', []).
controller('AppCtrl', [function ($scope, $http, $filter, MyService) {
$scope.myService = MyService; // found in services.js
// other functions...
}
]);
filters.js
angular.module('myApp.filters', []).
filter('myFilter', [function (MyService) {
return function(value) {
if (MyService.data) { // test to ensure service is loaded
for (var i = 0; i < MyService.data.length; i++) {
// code to return appropriate value from MyService
}
}
}
}]
);
services.js
angular.module('myApp.services', []).
factory('MyService', function($http) {
var MyService = {};
$http.get('resources/data.json').success(function(response) {
MyService.data = response;
});
return MyService;
}
);
main.js
/* This is the single file I want to separate into the others */
var myApp = angular.module('myApp'), []);
myApp.factory('MyService', function($http) {
// same code as in services.js
}
myApp.filter('myFilter', function(MyService) {
// same code as in filters.js
}
function AppCtrl ($scope, $http, $filter, MyService) {
// same code as in app.js
}
How do I manage the dependencies?
The problem is caused from you "redeclaring" your application module in all your separate files.
This is what the app module declaration (not sure declaration is the right term) looks like:
angular.module('myApp', []).controller( //...
This is what assignment (not sure if assignment is the right term either) to your application module looks like:
angular.module('myApp').controller( //...
Notice the lack of square brackets.
So, the former version, one with the square brackets, should only be used once, usually in your app.js or main.js. All other associated files — controllers, directives, filters … — should use the latter version, the one without the square brackets.
I hope that makes sense. Cheers!
If you're wanting to put your different parts of your application (filters, services, controllers) in different physical files, there are two things you have to do:
Declare those namespaces (for lack of a better term) in your app.js or in each file;
Refer to those namespaces in each of the files.
So, your app.js would look like this:
angular.module('myApp', ['external-dependency-1', 'myApp.services', 'myApp.controllers'])
.run(function() {
//...
})
.config(function() {
//...
});
And in each individual file:
services.js
angular.module('myApp.services', []); //instantiates
angular.module('myApp.services') //gets
.factory('MyService', function() {
return {};
});
controllers.js
angular.module('myApp.controllers', []); //instantiates
angular.module('myApp.controllers') //gets
.controller('MyCtrl', function($scope) {
//snip...
})
.controller('AccountCtrl', function($scope) {
//snip...
});
All of this can be combined into one call:
controllers.js
angular.module('myApp.controllers', [])
.controller('MyCtrl', function($scope) {
//snip...
});
The important part is that you shouldn't redefine angular.module('myApp'); that would cause it to be overwritten when you instantiate your controllers, probably not what you want.
You get the error because you didn't define myApp.services yet. What I did so far is putting all the initial definitions in one file and then use them in another. Like for your example I would put in:
app.js
angular.module('myApp.services', []);
angular.module('myApp',
['myApp.services',
...]);
That should get rid of the error, though I think you should have a read on the article Eduard Gamonal mentioned in one of the comments.

How to split AngularJS application into smaller modules and handle routing correctly?

What would be the best way to split AngularJS application into smaller pieces/module? For example if I have a blog post and commenting enabled for that, I think I could break it down to modules like "posts" and "comments"(?) (maybe not the best example, but the idea is to split the application logic into separate modules rather than building a huge one-module-app).
I've tried to bootstrap both modules in the separate DOM nodes and use routing in both of the modules accordingly. There are few problems:
As a "single-page" application I'm bootstrapping comments module to be used even on the front page even though it's not used there.
Since I'm not able to use multiple ng-views inside ng-app, I'm forced to write all the wrappers for my modules in the index.html view and bootstrap them? Should it be like that? Seems a bit wrong. How/where should I bootstrap those?
Are there any tips for the routing? Should I spread those in the modules or should I combine them all together somehow? (creating one "blog" module to include "posts" and "comments" modules as dependencies would still make it hard to define for example the "/post/:id" routing..?)
index.html
<div class="post"><ng-view></ng-view></div>
<div class="comments"><ng-view></ng-view></div>
javascript.js
angular.module('posts', []).config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
'template': 'Showing all the posts',
'controller': 'postCtrl
})
.when('/post/:id', {
'template': 'Showing post :id',
'controller': 'postCtrl
});
}]);
angular.module('comments', []).config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/post/:id', {
'template': 'Showing post :id comments',
'controller': 'CommentsCtrl'
});
}]);
angular.bootstrap($('.post'), ['posts']);
angular.bootstrap($('.comments'), ['comments']);
I would divide the app in "view modules" and these sub modules.
Then I use the $routeProvider to switch between the views. I define the different routing config in each module.
If I need further submodules, I load these with ng-include.
/* App Module */
angular.module('MyApp', ['MyApp.home', 'MyApp.blog'])
.config( function myAppConfig ( $routeProvider ) {
'use strict';
$routeProvider.otherwise({ redirectTo: '/home' });
});
/* home Module */
angular.module('MyApp.home', [])
.config(['$routeProvider', function config( $routeProvider ) {
$routeProvider.when('/home', {
controller: 'HomeController',
template: '<p>This is my Home</p>'
});
}]);
I created a little repository on github to explain this.
You can define routes in the submodules:
angular.module('app', ['ngRoute', 'app.moduleX'])
.config(function($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
//Handle all exceptions
$routeProvider.otherwise({
redirectTo: '/home'
});
})
angular.module('app.moduleX', []).config(function($routeProvider) {
$routeProvider.when('/settings', {
templateUrl: 'partials/settings.html',
controller: 'SettingsCtrl'
});
})
I also wrote a blog post about this topic.
We're doing something similar with a portal app and sub-apps. A few things we've discovered:
Only one "app" can have routes and routeParams. Because of this, if the "sub-app" needs access to the $routeParams, you either have to go "old school" for URL parsing, or use an event service.
Speaking of events, there is no Angular service for the apps to communicate, so you'll need to roll your own event service talking to root scope for both apps and inject it into both apps.
I can't see where we used ng-view for the "sub-app". Apparently bootstrapping directly to an element works similarly.
Because only one app can have routes, the apps should be bootstrapped in order. So something like this:
$( function () {
$.when(angular.bootstrap($('.post'), ['posts'])).done( function() {
console.log('POSTS: bootstrapped');
//Manually add the controller to the comments element. (May or may not be
//necessary, but we were doing something that required it to work.)
$('.comments').attr('ng-controller', 'CommentsCtrl');
$.when(angular.bootstrap($('.comments'), ['comments'])).done( function() {
console.log('COMMENTS: bootstrapped');
});
});
});
I hope you can use "ui-router" routing module.
Here is good tutorial for this http://www.ng-newsletter.com/posts/angular-ui-router.html

Categories

Resources