How to make lodash work with Angular JS? - javascript

I'm trying to use lodash use it at ng-repeat directives, in this way:
<div ng-controller="GridController" ng-repeat="n in _.range(5)">
<div>Hello {{n}}</div>
</div>
Being GridController:
IndexModule.controller('GridController', function () {
this._ = _
})
However is not working and so, nothing being repeated. If I change the directive to ng-repeat="i in [1,2,3,4,5]" it'll work.
lodash is already included via <script> at <header> before angular. How can I make it work?

I prefer to introduce '_' globally and injectable for tests, see my answer to this question
Use underscore inside controllers
var myapp = angular.module('myApp', [])
// allow DI for use in controllers, unit tests
.constant('_', window._)
// use in views, ng-repeat="x in _.range(3)"
.run(function ($rootScope) {
$rootScope._ = window._;
});

I just wanted to add some clarification to #beret's and #wires's answer. They definitely helped and got the jist of it but getting the whole process in order might suit someone. This is how I set up my angular environment with lodash and got it working with yeoman gulp-angular to serve properly
bower install lodash --save (This adds to bower and a saves to bower json)
modify bower json to have lodash load before angular does. (This helps if you're using gulp inject and don't want to manually put it into index.html. otherwise put it into the index.html before the angular link)
Make a new constant per #wires's direction.
'use strict';
angular.module('stackSample')
// lodash support
.constant('_', window._);
Inject into any angular service, filter, or controller as you would anything else:
.filter('coffeeFilter', ['_', function(_) {...}]);
To throw it into some angular html view just inject it into the controller and assign a scope variable to it:
.controller('SnesController', function ($scope, _) {
$scope._ = _;
})
Hope this helps someone set up their site. :)

ng-repeat requires an Angular expression, which has access to Angular scope variables. So instead assigning _ to this, assign it to the $scope object you inject into the controller:
IndexModule.controller('GridController', function ($scope) {
$scope._ = _;
})
Demo

I am not sure what version of Angular you are using. Looks like you should have just used the 'Controller as' syntax when you use 'this' to access variables in the dom.
Here is the solution with this and not using scope.
http://plnkr.co/edit/9IybWRrBhlgQAOdAc6fs?p=info
<body ng-app="myApp" ng-controller="GridController as grid">
<div ng-repeat="n in grid._.range(5)">
<div>Hello {{n}}</div>
</div>
</body>

Related

How to Integrate two modules in AngularJS

I have two modules as follows.
var module1 = angular.module('myApp',['ngAnimate','ngTouch']
.controller('MainCtrl', function ($scope)){
});
var module2 = angular.module('myApp',[]);
module2.controller('NameCtrl',function($scope)){
});
And Html here
<body ng-app='myApp'>
<div ng-controller='MainCtrl'> //Code here</div>
<div ng-controller='NameCtrl'>//Code here</div>
</body>
But this throws error like this.
'NameCtrl' is not existing
Please let me know how to fix this.
Thanks in advance
Proper structure would look like this...
var myApp = angular.module('myApp', ['ngAnimate','ngTouch']);
myApp.controller('MainCtrl', function($scope){
});
myApp.controller('NameCtrl', function($scope){
});
Remember
Each module is like a separate app. Each module has to be a unique name, each module can have things like their own configuration, controllers, services etc.
You don't need 2 modules.
module1.controller('NameCtrl',function($scope)){
});
is what you want
You are declaring two different modules with the same name. You can't do it.
the angular.module method is a jQuery-like getter and setter. If you call'it with just one parameter it works as a getter, if you call it with two or more parameters, then, it works as a setter.
So, if you need (as seems) to register just another recipe (controller, service, ecc.) but not a new module, you need to do angular.module('ngApp').controller.
Otherwise, if you need for a new module, you need to assign it a different name and bootstrap it manually via angular.bootstrap
You don't need to create two modules.
You could implement what you need as follows.
var myComponent = angular.module('myComponent',[]);
myComponent.controller('MainCtrl',function($scope)){
};
myComponent.controller('NameCtrl',function($scope)){
};
This is one you looking for ?
var modules = angular.module('myApp',['ngAnimate','ngTouch']
.controller('MainCtrl', function ($scope)){
});
modules.controller('NameCtrl',function($scope)){
});
You cannot have two modules with the same name.
In case your project is structured in a way, that truly prevents you from using just one module, you could to this.
var module2 = angular.module('myModule2',[]);
module2.controller('NameCtrl',function($scope) {...});
var module1 = angular.module('myApp',['ngAnimate','ngTouch', 'myModule2']
.controller('MainCtrl', function($scope){...});
To decompose your application into multiple modules you need to name the app and the component(s) something different and make your app depend on your component(s).
var myComponent = angular.module('myComponent',[]);
myComponent.controller('NameCtrl',function($scope)){});
var anotherComponent = angular.module('anotherComponent',[]);
anotherComponent.controller('NameCtrl',function($scope)){});
var myApp = angular.module('myApp',['ngAnimate','ngTouch', 'myComponent', 'anotherComponent']);
myApp.controller('MainCtrl', function ($scope)){});
That's a bit confusing, because, according to docs, by declaring module2 you are overwriting already existing myApp module, which should lead to MainCtrl to be not existing one. Consider trying what Wainage suggested, or, if you really need two separate modules, to do something like this:
var module1 = angular.module('myApp.module1', []);
module1.controller('NameCtrl',function($scope){
$scope.value = 'Name controller value';
});
var myApp = angular.module('myApp', [/*Other dependencies*/'myApp.module1']);
myApp.controller('MainCtrl', function ($scope){
$scope.value = 'Main value';
});
You can't declare two module with same name. you can use different controller, service, directive, factory etc in same module so you may no need to use different module for simple app.
If need different controller in same module then use like
var myModule = angular.module('myApp',['ngAnimate','ngTouch']);
myModule .controller('MainCtrl', function ($scope){
//code
});
myModule .controller('NameCtrl', function($scope){
//code
});
If need different module then need different name. Can use different module for those application that are module based application.

Which is the preferred way of defining an AngularJS controller?

As an example, we have this index.html code:
<!DOCTYPE html>
<html ng-app="sample">
<head>
...
</head>
<body>
<div ng-controller="myController">
...
<script src="js/modules/app.js"></script>
</div>
</body>
</html>
and in app.js we have a module and a controller:
var app = angular.module('sample', []);
// controller here
So my question is that, I have seen controllers defined in two types, as a controller, and as a plain function:
app.controller('myController', function(args){
...
});
or
var myController = function(args){
...
};
Which one should be used and why? I have mostly seen the first one used in Angular-based code, but even in tutorials I have come across the second. I personally don't use the second, as I have read it 'pollutes the global namespace'.
Another question I have is that I have seen this kind of usage for a controller:
app.controller('myController', ['$scope', '$http', function($scope, $http) {
...
}]);
Why do we need the array? Can't we make do with just the arguments?
According to the Angular the array annotation based dependency injection or definition is the preferred way:
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
// ...
}]);
See Inline Array Annotation
This is the preferred way to annotate application components. This is
how the examples in the documentation are written.
While at the other hand, the simplest way to get hold of the dependencies is to assume that the function parameter names are the names of the dependencies (which is not preferred for like production app).
someModule.controller('MyController', function($scope, greeter) {
// ...
});
The Angular can infer the names of the services to inject by examining the function declaration and extracting the parameter names. In the above example, $scope and greeter are two services which need to be injected into the function.
However this method will not work with JavaScript minifiers/obfuscators because of how they rename parameters.
The resulting code after minification will be like this:
someModule.controller('MyController', function(a, b) {
// ...
});
So now, the Angular does not know what is the dependency a & b while if you use the array annotation based, the output will be:
someModule.controller('MyController',['$scope','greeter', function(a,b) {
// ...
}]);
So, now Angular can map a with $scope and b with greeter and will be able to resolve the dependency.
app.controller('myController', ['$scope', '$http', function($scope, $http) {
This is done to prevent JS minifiers from breaking your code, because angular relies on names for dependency resolutions.
As for the two styles of controller
app.controller('myController', function(args){
...
});
vs
var myController = function(args){
...
};
app.controller('myController', myController);
It's a matter of personal taste. There's no functional difference.
The first question is mostly about style, since both methods are correct.
There might be arguments about both ways of defining controllers and other Angular modules. But as it is with every language in Software Development: Find a coding style and stick to it. Inconsistencies are the real problem.
Here's a good style guide to stick to: https://github.com/johnpapa/angular-styleguide
The second question has to do with minification. Please read this article: http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/
Syntax for Controllers
The most preferred way for Angular 1.x version is to use Controller As syntax. Please see code below:
(function () {
'use strict';
angular.module('app.controllers')
.controller('HeadController', HeadController);
HeadController.$inject = ['someService'];
function HeadController(someService) {
/* jshint validthis: true */
var vm = this;
vm.logout = action;
function action() {
someService.doSomeAction();
}
}
})();
In your html it will be used like this:
<div ng-controller="HeadController as vm">
<a href ng-click="vm.logout();" id="item-btn-logout"><i class="icon-off">
</div>
I prefer this syntax. This will let you not to use scope in your views.
Take a look at John Papa AngularJS guide - it is good!
If you are still thinking that it's too complicated and you ain't gonna need it - refer to this article that explains how to avoid Scope Soup in Angular.
Why do we need the array?
Array with plain text is used during injection of dependencies. This will let you minify your code easily and not to lose dependency names during initialization process. If you are not going to do this and minify your code - you are risking that your code won't work.

How does implicit/inline/$inject dependency injection work in AngularJS?

I'm new to AngularJS and I would like to understand more about the dependencies that are being injected by default. While reading through code I've noticed that sometimes dependencies are explicitly declared beforehand, and sometimes they aren't. For example:
someModule.controller('MyController', ['$scope', 'someService', function($scope, someService) {
// ...
}]);
Gives the same results as:
someModule.controller('MyController', function($scope, someService) {
// ...
});
How does this work? Is Angular assuming that the modules being injected are named the same as the variables in the parameters?
Also, strangely enough, if you do specify the dependencies that are going to be injected, you must specify all of them and in the right order, otherwise nothing will work. For example, this is broken code:
someModule.controller('MyController', ['someService', '$scope', function($scope, someService) {
// Won't give us any errors, but also won't load the dependencies properly
}]);
Can someone clarify to me how is this whole process working? Thank you very much!!
Yes, dependency injection in Angular works via the names of the components you (and Angular - for the internal ones) registered.
Below is an example showing how a service is registered and injected into a controller using several different annotations. Please note that dependency injection always works the same in Angular, i.e. it doesn't matter if you are injecting something into a controller, a directive or a service.
app.service('myService', function () {
// registering a component - in this case a service
// the name is 'myService' and is used to inject this
// service into other components
});
Two use (inject) this component in other components, there are three different annotations I am aware of:
1. Implicit Annotation
You can either specify a constructor function which takes as parameters all the dependencies. And yes, the names need to be the same as when these components were registered:
app.controller('MyController', function ($http, myService) {
// ..
});
2. Inline Array Annotation
Or you can use a notation using an array, where the last parameter is the constructor function with all the injectables (variable names do not matter in this case). The other values in the array need to be strings that match the names of the injectables. Angular can this way detect the order of the injectables and do so appropriately.
app.controller('MyController', ['$http', 'myService', function ($h, m) {
/* Now here you can use all properties of $http by name of $h & myService by m */
// Example
$h.x="Putting some value"; // $h will be $http for angular app
}]);
3. $inject Property Annotation
A third option is to specify the $inject-property on the constructor function:
function MyController($http, myService) {
// ..
}
MyController.$inject = ['$http', 'myService'];
app.controller('MyController', MyController);
The reason why the last two options are available, at least as far as I know, is due to issues which occured when minifying the JavaScript files which led to the names of the parameters being renamed. Angular then wasn't able to detect what to inject anymore. In the second two cases the injectables are defined as strings, which are not touched during minification.
I would recommend to use version 2 or 3, as version 1 won't work with minification/obfuscation. I prefer version 3 as from my point of view it is the most explicit.
You can find some more detailed information in the internet, e.g. on the Angular Developer Guide.
Just to provide a different sort of answer, as to the how inline/implicit dependencies work in AngularJS. Angular does a toString on the provided function and parses the parameter names from the string which is produced. Example:
function foo(bar) {}
foo.toString() === "function foo(bar) {}"
References:
source code
AngularJS Dependency Injection - Demystified

Should I use the array notation in Angular?

I learnt to write angular dependencies needed using the array notation, that way:
var app = angular.module('MyApp', []);
app.controller('MyCtrl', ['$scope', function($scope) {
$scope.stuff = 'stuff';
}]);
The Angular doc follows this notation, but I see more and more tutorials not using the array notation and just directly passing the controller the function($scope).
Is there any differences between the two ways to do? Or maybe one was implemented in the version two?
You should be using the Array notation
say Tomorrow if you wish to minify your data using a uglify say, it minifies your big variable names but doesn't touch your strings so your statement
from
Case 1 with array notation
original
app.controller('MyCtrl', ['$scope', function($scope) {
minified
x.controller('MyCtrl', ['$scope', function(a) {
Here controller knows exactly knows that variable a is $scope
Case 2 without array notation (whereas if you choose not to use it)
original
app.controller('MyCtrl', function($scope) {
minified
x.controller('MyCtrl', function(a){
Now your controller doesn't know what to do with a variable its not $scope for sure
The array notation is important if you plan to minify your code, which you should be doing in production anyway. Stick to using it.
If you're planning to mini your app, yes you MUST use the array notation.
This is because the variables are renamed, so the injector no longer knows what dependencies you're intending to inject.
For example if $scope was renamed a on minification it wouldn't work.
Obviously this means you have to write and maintain more code. Luckily, you can automate this in your build process.
On my project I use grunt and angular-templates.
https://www.npmjs.com/package/grunt-angular-templates
Yes there is a difference. I would recommend continuing to use array notation since not using it will break your dependency references if the application is minified. For more details, read https://docs.angularjs.org/tutorial/step_05 .
Basically you can rename the variables without affecting angulars ability to inject. As others have said, specifically for minification.
var app = angular.module('MyApp', []);
app.controller('MyCtrl', ['$scope', function(s) {
s.stuff = 'stuff';
}]);
Array notation is used for injecting the dependencies. Difference between this two is if u do not include array notation means u do not need any dependencies.
Best practice is to use [] notation so that u can include dependencies any time in you application.
In a nutshell there are two ways how you can use dependency injection in angular: implicit or explicit.
Implicit DI is .controller('MyCtrl', function(scope, dep1, dep2){
It does not give instructions to $injector on what to include, it bvasically doing something like a reflection to figure it out. If you minify your code it will turn into
`.controller('MyCtrl', function(a, b, c){ `
That is why we are using explicit DI. There are several ways to do so:
use array : .controller('MyCtrl', ['$scope','dep1','dep2', function($scope, dep1, dep2){
use $inject:
.controller('MyCtrl', myCtrl)
myCtrl.$inject = ['$scope', 'dep1', 'dep2']
function myCtrl($scope, dep1, dep2) {}
In both ways, even if minification renamed function parameters to something, $injector will know what it is expected to inject, as it has original names in the string literals ( which are not affected by minification)
You can also use comment annotations that will tell compiler/transpiler how to handle angular DI , ie it will turn implicit DI into explicit for you, see ng-annotate
I personally prefer second way with .$inject
DI helps you while minifying the code, Also other answer does explained how both the DI injection techniques work. Basically none of DI injection technique is bad.
But I'll prefer to do not worry about this thing because other will take care of this DI thing. Use ng-annotate directive, that will give you facility to use dependency inside a function directly
If you wrote code like this
angular.module("MyMod").controller("MyCtrl", function($scope, $timeout) {
//awesome code here
});
When you send this code to minifier it does add the array annotation of dependency on the angular component while
angular.module("MyMod").controller("MyCtrl", ["$scope", "$timeout",
function($scope, $timeout) {
//code here
}
]);
From Docs
ng-annotate works by using static analysis to identify common code
patterns. There are patterns it does not and never will understand and
for those you can use an explicit ngInject annotation instead, see
section further down.

Originzational MVC and Angular keeping from injecting what I don't need

My problem is I have one ng-app. Does that mean I have to do dependency injection for plugins I may not be using on that given view? Example I bring in ngTagsInput does that mean I have to do it even when the view doesn't call for it? That would mean I have to include that js for every view even if it doesn't use ngTagsInput.
I have a very large MVC .NET application and I am trying to figure out what is he best way to handle bringing in external plugins.
I have some code like so in our Main _Layout template:
<html ng-app="ourApp">
<head>
<!-- all of our includes are here -->
</head>
<body>
<directive></directive>
<anotherdirective></anotherdirective>
#RenderBody()
</body>
</html>
RenderBody is where MVC slides in our views from our mvc routing.That view may look like so:
<script src="~/Scripts/HomeAngular.js"></script>
<div ng-controller="HomeCtrl">
<directive3></directive3>
</div>
App JS:
var app = angular.module('ourApp', ['ngTagsInput']);
IS there a way I can get around having to inject ngTagsInput on every view page even if i don't need it?
There are several different ways to handle Dependency Injection (DI) in angular. In this first example, you simply define ngTagsInput before declaring the controller. If ngTagsInput is a service, for example, you'll need to return an object with methods that allow you to access the data inside of that service.
For example:
app.service('ngTagsInput', function($scope) {
var data = {};
return {
getData = function() {
return data;
},
setData = function(val) {
data = val;
}
};
});
app.controller('HomeCtrl', function($scope, ngTagsInput) {
// ...
$scope.tags = ngTagsInput; // whatever you want to do with it
});
However, there's a problem...
In the example above, if you run that code through a minifier, you'll get $scope turned into some variable (a, b, x, etc...) and angular wont know what to do with that.
In this method, we use an array. The last item in your array is your lambda function for the controller, which takes 1 argument for each previous item in the array:
app.controller('HomeCtrl', ['$scope', 'ngTagsInput', function(scp, ngTagIn) {
// ...
}]);
This code can be run through a minifier just fine, since the dependencies are strings in the array and can be renamed to anything you want inside the function's parameters.
DI also works in directives, factories, filters, and services with the same syntax; not just controllers and modules.
app.directive('HomeCtrl', ['$scope', 'ngTagsInput', function(scp, ngTagIn) {
// ...
}]);
Couldn't you break down your application further into smaller modules instead of just one. Then you can inject the smaller modules into the app module and only inject the ngTagsInput dependency on the modules that actually need it. That's how I typically break up my application by function or area.

Categories

Resources