127

How do I use underscore library inside angularjs controllers?

On this post: AngularJS limitTo by last 2 records somebody suggested to assign an _ variable to the rootScope so that the library will be available to all the scopes within the app.

But I'm not clear where to do it. I mean should it go on the app module declaration? i.e:

var myapp = angular.module('offersApp', [])
            .config(['$rootScope', function($rootScope) { }

But then where do I load underscore lib? I just have on my index page the ng-app directive and script reference to both the angular-js and underscore libs?

index.html:

<head>
</head>
<body ng-app="offersApp">
...
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="scripts/vendor/angular.js"></script>
<script src="scripts/vendor/underscore.js"></script>
...  

How do I achieve this?

Community
  • 1
  • 1
Pablo
  • 3,433
  • 7
  • 44
  • 62
  • well what did you try and did not work ? – mpm Feb 19 '13 at 22:01
  • Well, I don't know where to start. How do I link any king of – Pablo Feb 19 '13 at 22:03
  • just declare the proper script tag with underscore in your html file , like you did with angular or jquery. – mpm Feb 19 '13 at 22:05
  • Will it be available automatically under the _ character?? How?? – Pablo Feb 19 '13 at 22:11

6 Answers6

232

When you include Underscore, it attaches itself to the window object, and so is available globally.

So you can use it from Angular code as-is.

You can also wrap it up in a service or a factory, if you'd like it to be injected:

var underscore = angular.module('underscore', []);
underscore.factory('_', ['$window', function($window) {
  return $window._; // assumes underscore has already been loaded on the page
}]);

And then you can ask for the _ in your app's module:

// Declare it as a dependency of your module
var app = angular.module('app', ['underscore']);

// And then inject it where you need it
app.controller('Ctrl', function($scope, _) {
  // do stuff
});
TWright
  • 1,853
  • 18
  • 25
satchmorun
  • 12,487
  • 2
  • 41
  • 27
  • 27
    I don't understand why you would inject it when it is already in the global window scope. – Walter Stabosz Apr 07 '13 at 13:32
  • 36
    Probably for the same reasons you inject anything, instead of putting everything in the global scope. However, since you're a lot less likely to want to substitute out your underscore library during testing than some other more specific dependency it's understandable that it doesn't seem necessary. – fess . Jun 02 '13 at 03:13
  • 50
    its necessary when you add 'use strict' to your file. Since underscore/lodash isn't defined it will throw ReferenceError: _ is not defined... you have to inject it, or use window._ – Shanimal Jun 06 '13 at 19:37
  • 23
    Ha! I wanted to do the injecting because it's cool, thanks for giving me a real reason, @Shanimal. – Aditya M P Jun 28 '13 at 16:34
  • 10
    you might also want to inject _ for the sake of testing. How would you go about bringing the underscore dependency into a test suite environment – sunwukung Jul 18 '13 at 22:44
  • Couldn't you also just do `var _ = window._;` at the top of your controller? – zakdances Nov 02 '13 at 07:10
  • 7
    @Shanimal that's not true. It works by just accessing _ (as a global) in strict mode as well. – holographic-principle Dec 01 '13 at 08:27
  • Angular already provides $window that can be injected into controllers, which is just a reference to the global window object. Then you can access $window._ in the controller, without accessing the global scope directly. – Michal Charemza Dec 05 '13 at 21:55
  • 3
    I agree with @MichalCharemza, try to avoid using global window object in your service. The above example rewritten to use $window would look more or less like this: `angular.module('underscore', []);` `angular.module('underscore').factory('_', ['$window', function ($window) { return $window._; }]);` – Jan Molak Jan 30 '14 at 13:54
  • 8
    @Shanimal despite its many upvotes, your comment is nonsense; `"use strict";` prevents globals from being *implicitly declared*, by assigning to a name that hasn't been declared with `var` or otherwise created in a visible scope. It *does not* require you to *access* existing, declared globals as `window` properties. You can simply access them as variables, which they are. `window` *itself* is a global variable, for goodness' sake; if what you were saying were true, all globals would be strictly inaccessible by any means whatsoever. – Mark Amery Feb 13 '15 at 16:07
  • 1
    You should use `$window` instead of `window.` – Michał Miszczyszyn Mar 12 '15 at 07:31
  • 1
    I would think that underscore is more of a service than a factory (based on this http://stackoverflow.com/a/21900284/1766230) Why use `factory` instead of `service`? – Luke Jul 23 '15 at 19:20
34

I have implemented @satchmorun's suggestion here: https://github.com/andresesfm/angular-underscore-module

To use it:

  1. Make sure you have included underscore.js in your project

    <script src="bower_components/underscore/underscore.js">
    
  2. Get it:

    bower install angular-underscore-module
    
  3. Add angular-underscore-module.js to your main file (index.html)

    <script src="bower_components/angular-underscore-module/angular-underscore-module.js"></script>
    
  4. Add the module as a dependency in your App definition

    var myapp = angular.module('MyApp', ['underscore'])
    
  5. To use, add as an injected dependency to your Controller/Service and it is ready to use

    angular.module('MyApp').controller('MyCtrl', function ($scope, _) {
    ...
    //Use underscore
    _.each(...);
    ...
    
unify
  • 6,161
  • 4
  • 33
  • 34
  • Does not appear to work. I get an undefined error: `Uncaught ReferenceError: _ is not defined` – chovy Jun 05 '14 at 09:19
  • I added the clarification: you need to include underscore.js. This connector only helps you to use it in a service. See @satchmorun's answer – unify Jun 05 '14 at 15:10
31

I use this:

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._;
  });

See https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection about halfway for some more info on run.

wires
  • 4,718
  • 2
  • 35
  • 31
  • this looks good but do you have an example? I need to change all uppercase to upper on first character only using _.capitalize() – Nate Aug 26 '14 at 21:28
  • 2
    I think this should work `

    {{ _.capitalize('lalala') }}

    ` ?
    – wires Aug 30 '14 at 16:47
  • 1
    @LVarayut I don't know, why not try it? (I have since moved to ReactJS) – wires Feb 18 '15 at 10:18
  • Please use service instead. Avoid adding stuff to your $rootScope will help you to have better performance. – Tim Hong Jun 12 '15 at 11:36
  • Not sure what I did wrong but I could not get the "use in views" part to work. But passing the service to the controller and then to the tpl through $ctrl works. – Olivvv Apr 18 '17 at 13:16
3

You can also take a look at this module for angular

https://github.com/floydsoft/angular-underscore

Paul Sheldrake
  • 7,505
  • 10
  • 38
  • 50
1

If you don't mind using lodash try out https://github.com/rockabox/ng-lodash it wraps lodash completely so it is the only dependency and you don't need to load any other script files such as lodash.

Lodash is completely off of the window scope and no "hoping" that it's been loaded prior to your module.

Nick White
  • 1,602
  • 4
  • 20
  • 35
-2

you can use this module -> https://github.com/jiahut/ng.lodash

this is for lodash so does underscore

jiahut
  • 1,451
  • 15
  • 14