In angular modules why the body is the last array element? - javascript

This is more of an architectural question.
One of the most common forms of defining an angular module is this:
angular.module('app', [])
.controller('Ctrl', ['$scope', function Ctrl($scope) {
//body...
}]);
But I don't find the syntax very intuitive. How about having the list of dependencies in an array like AMD:
angular.module('app', [])
.controller('Ctrl', ['$scope'],
function Ctrl($scope) {
//body...
});
This way the whole array will contain only string elements each of which refers to a module. The array matches the function parameters one by one. (kinda like arguments).
So my question is why Angular designers went for this convention?

It kind of does that in a sense. you can do this by using $inject.
function SomeCtrl ($scope) {
// do something with $scope
}
SomeCtrl.$inject = ['$scope'];
angular
.module('app', [])
.controller('SomeCtrl', SomeCtrl);
I am not a no Expert on this, but I did found a great post on how this process works and it might help answer your question: http://toddmotto.com/angular-js-dependency-injection-annotation-process/

Related

Whether to use: var app = angular.module... or simply: angular.module(

I'm new to Angular and am working through various tutorials (Codecademy, thinkster.io and so on) and have seen two ways of declaring the app container. Firstly:
var app = angular.module('myApp', [])
Or simply like this:
angular.module('myApp', [])
Is one better practice over the other or is it simply a different style without any major effect?
There'n no difference in how both the approach works except following
var app = angular.module('myApp', []) will add an extra global variable(If you're hyper conscious about global variables), however this will shorten your code, don't have to repeat angular.module('myApp') multiple times. You can use app instead of angular.module('myApp').xxx at many times.
You can chain the methods as follow, instead of adding a variable
angular.module('myApp', [])
.controller(.....)
.directive(.....)
.factory(.....);
angular.module supports a third parameter, config function. If you chain you can do more than one config, which may be useful if you have a lot of configurations.
angular.module('myModule', [])
.config(function(injectables) {
//config block 1
})
.config(function(injectables) {
//config block 2
});
Instead of:
angular.module('myModule', [], function(){
//only config
});
Also it eliminates risk of creating global variables when creating providers.
There is no difference, only the style and whatever you prefer, see this
angular.module('myApp', [])
.controller("xCtrl", ['$scope', function($scope){
}])
.controller("yCtrl", ['$scope', function($scope){
}])
.controller("zCtrl", ['$scope', function($scope){
}]);
In this case if you put the ; after y controll, z controller will not work. Means all will be treated as a single function. On the other way:
var app = angular.module('myApp', []);
app.controller("xCtrl", ['$scope', function($scope){
}]);
app.controller("yCtrl", ['$scope', function($scope){
}]);
app.controller("zCtrl", ['$scope', function($scope){
}]);
In it every function is independent.
The only reason for setting a global variable referring to your module, is if you want to separate it in to multiple files.
for example:
main.js:
var app = angular.module('myApp', [])
.controller('controller1',.....)
.controller('controller2',.....);
directives.js
app
.directive('directive1',.....)
.directive('directive2',.....);
although,you should know it is not so good to relay on global variables (app is global in this example), because they could get overridden by other librarys, and there are other ways to refer to your module in other files, like in this example:
main.js:
angular.module('myApp', [])
.controller('controller1',.....)
.controller('controller2',.....);
directives.js
angular.module('myApp')
.directive('directive1',.....)
.directive('directive2',.....);
and if it is a big and complex angular application, you might even want to separate it to multiple modules:
main.js:
angular.module('myApp', ['myApp.directives'])
.controller('controller1',.....)
.controller('controller2',.....);
directives.js
angular.module('myApp.directives', [])
.directive('directive1',.....)
.directive('directive2',.....);

Separating Controllers in AngularJS

Im trying to separate my Angular controllers into different files. Right now each one appears like this.
AddPropertyController.js
angular.module('myApp.controllers.addproperty', [])
.controller(...);
SearchController
angular.module('myApp.controllers.search', [])
.controller(...);
Now for each one of these I had to include them in the Angular myApp. via:
angular.module('myApp', [
'myApp.controllers.search',
'myApp.controllers.addproperty'
])
my question is, is there a way to just include them all at once instead of adding them individually? My first attempt was to name each module the same, angular.module('myApp.controllers',...) then just include myApp.controllers in the App. But that didn't seem to work... I guess Im asking is what is the best way to have separated controller files but in all in one module. Thanks for the help!
Check out the angularjs docs for info on controllers and adding them to app level modules...
For example for your code:
var myApp = angular.module('myApp',[]);
myApp.controller('SearchController', ['$scope', function($scope) {
$scope.search = 'Hola!';
}]);
myApp.controller('AddPropertiesController', ['$scope', function($scope) {
$scope.props = [];
}]);
You're basically attaching each controller to the myApp instance, so the app is aware of the controllers.
I would organize them like this:
MyController1.js
var MyController1 = ['$scope', function($scope) {
}];
MyController2.js
var MyController2 = ['$scope', function($scope) {
}];
MyModule.js
var app = angular.module('MyModule',[]);
app.controller({
MyController1: MyController1,
MyController2: MyController2,
etc
});
This is the similar to how the Angular source code is itself organized:
AngularPublic.js
ng Directives

Access a factory in the same module in AngularJS

I wonder why I can't access a factory within the same module.
As I think it is better to build a web app with different independent modules, I would like to group all methods (services, factories, directives, ...) within the same module.
What do I do wrong?
app = angular.module("MyGreatModuleProvider", []);
app.factory("MyFactory", function($rootScope, $scope) {
return {
myFunction: function() {
console.log("Hello World");
}
}
});
app.controller("myCtrl", function($scope, MyFactory) {
MyFactory.myFunction();
// This doesnt't work, unknown provider
});
Factories don't have a $scope
If you remove the $scope and only keep the $rootScope it works just fine
You can remove both $scope and $rootScope from the factory declaration. Here's a plunker.
Define your injected object names to let the Angular know what to inject into fields:
app.controller("myCtrl", ['$scope', 'MyFactory', function($scope, MyFactory) {
MyFactory.myFunction();
}]);
It's a good practice especially if you are going to compile your application.
Moreover as others pointed out: factories doesn't have $rootScope and $scope.

Yeoman Angularjs How to Implement Directive

I'm trying to get my feet off the ground with Yeoman + Angular and going through the tutorials, I can't get even the most basic directives to fire, even when I try them exactly the same as in the tutorials.
Could someone please lend some insight as to what I'm missing, I've been struggling with this for the past 2 days
HTML template - ng-resize is the intended directive
<body ng-app="mvmdApp">
....
<div ng-mousemove="onMouse($event)" ng-resize="" class="youtube-cover ng-scope">
<div class="youtube-unit"></div>
</div>
// controllers/youtube.js
'use strict';
angular.module('mvmdApp').controller('YoutubeCtrl', function($scope) {
console.log('hi');// fires
return $scope.onMouse = function(e) {}// fires
// directives/resize.js
'use strict';
angular.module('mvmdApp', []).directive('ngResize', function($window) {
return function(scope) {
return console.log('directive');// does not fire
};
});
The strange thing is that whenever I even call angular.module('mvmdApp', []) like so from the directive script, it blocks the view from rendering.
edit: Also I noticed that when I load the directive before all the other scripts, it doesn't block the html from rendering, but it still doesn't trigger the directive. I don't know if/how the load order of angular scripts matters as I don't know where to find that.
You are declaring the module multiple times. You can simplify this by doing the following:
In app.js:
'use strict';
var myApp = angular.module("mvmdApp", []);
myApp.config(function($routeProvider, $locationProvider) {
...
});
In youtube.js:
'use strict';
myApp.controller('YoutubeCtrl', function($scope) {
...
});
An in resize.js:
'use strict';
myApp.directive('resize', function($window) {
...
});
Updated plunker at http://plnkr.co/edit/Im4SpcyH4cIem6TDWZaG?p=preview. Also, I would refrain from calling the directive "ng-resize" as the ng prefix is usually used by the angular team. In this case, the directive is simply "resize".
This may not solve your issue but one mistake i see is
angular.module('mvmdApp', []) been declared at multiple places, resize.js and app.js. This format declaration creates a new module everytime with this name.
This should be called once only from app.js. In resize.js it should be angular.module('mvmdApp')

What is the purpose of square bracket usage in Angular?

I would like to understand the difference between the declaration of MyOtherService and MyOtherComplexService. Especially what is the purpose of square bracket part? When to use them and when not?
var myapp = angular.module('myapp', []);
myapp.factory('MyService', function($rootScope, $timeout) {
return {
foo: function() {
return "MyService";
}
}
});
myapp.factory('MyOtherService', function($rootScope, $timeout, MyService) {
return {
foo: function() {
return "MyOtherService";
}
}
});
myapp.factory('MyOtherComplexService', ['$rootScope', '$timeout', 'MyService', function($rootScope, $timeout, MyService) {
return {
foo: function() {
return "MyOtherComplexService";
}
}
}]);
myapp.controller('MyController', function($scope, MyOtherService, MyOtherComplexService) {
$scope.x = MyOtherService.foo();
$scope.y = MyOtherComplexService.foo();
});
It enables AngularJS code to be minified. AngularJS uses parameter names to inject the values to your controller function. In JavaScript minification process, these parameters are renamed to shorter strings. By telling which parameters are injected to the function with a string array, AngularJS can still inject the right values when the parameters are renamed.
To add to Ufuk's answer:
ngmin - compiles your standard modules to min-safe modules
Angular's min-safe square bracket notation is cleary less convenient, because you have to type every dependency twice and argument order matters. There is a tool called ngmin which compiles your standard modules to min-safe modules, so you don't have to manage all those things by hand.
Angular + CoffeeScript
If you're using CoffeeScript the situation is even worse. You may choose between ngmin, which will destroy your source map, or if you want to write it out all by yourself you'll have to wrap your entire code with square brackets, which is super ugly.
angular.module('whatever').controller 'MyCtrl', ['$scope', '$http' , ($scope, $http) ->
# wrapped code
]
In my opinion this is not a CoffeeScript flaw, but a poor design decision of the Angular team, because it's against all JS/CoffeeScript conventions not to have the function as the last argument. Enough ranting, here is a little helper function to work around it:
deps = (deps, fn) ->
deps.push fn
deps
This is a very simple function that accepts two arguments. The first one is an array of strings containing your dependencies, the second one is your module's function. You may use it like this:
angular.module('whatever').controller 'MyCtrl', deps ['$scope', '$http'] , ($scope, $http) ->
# unwrapped code \o/
Just to exemplify what was already said, if you use the following syntax:
myapp.factory('MyService', function($scope, $http, MyService) { ... });
most of the JS minifiers will change it to:
myapp.factory('MyService', function(a, b, c) { ... });
since functions argument names usually can be renamed for shorter names. This will break the Angular code.
In Angular, to get your code minifiable in all minifiers, you use the bracket syntax:
myapp.factory('MyService', ['$scope', '$http', 'MyService', function($scope, $http, MyService) { ... }]);
that will be minified to:
myapp.factory('MyService', ['$scope', '$http', 'MyService', function(a, b, c) { ... }]);
Note that minifiers do not touch on strings so Angular will see the minified code and match arguments in order:
$scope = a
$http = b
MyService = c
To avoid this ugly square bracket syntax, you should use smart minifiers like ng-annotate.
As of now, ng-min is deprecated.
Use ng-annotate instead.
It is good practice to use ng-annotate in your build job so you don't have to deal with the min-safe / bracket notation when developing, as it makes the code harder to read and maintain.
There is a grunt-plugin and a gulp plugin available on npm.

Categories