67

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?

diegoaguilar
  • 8,179
  • 14
  • 80
  • 129

4 Answers4

113

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._;
  });
wires
  • 4,718
  • 2
  • 35
  • 31
  • 4
    will '_' be available in isolate scopes, too? – cipak Aug 25 '15 at 14:19
  • I don't understand ... the constant is defined, but then the "global" underscore instance `window._` is referenced by the `$rootScope`? Doesn't it make unnecessary the constant? On the other way, shouldn't an explicit `$inject` reference be preferred than using an attribute on the angular-wise-global `$rootscope`? – Gerardo Lima May 12 '16 at 09:36
  • 2
    Isn't it better to use $window instead of window? – Ashish May 26 '16 at 18:53
  • @Ashish: yes, probably and then maybe you need to inject it too – wires May 27 '16 at 18:00
  • 6
    Yep, this is what I used, I created a service called '_' and injected it in every controller where I needed it: ```.factory('_', function($window) { return $window._; // assumes underscore has already been loaded on the page })``` – Ashish May 29 '16 at 06:38
  • 1
    Beautiful. Exactly what I needed to use lodash inside a ng-template. – Kon Jul 26 '16 at 17:59
61

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. :)

ThinkBonobo
  • 15,487
  • 9
  • 65
  • 80
  • Some one made that a module: https://github.com/kmc059000/angular-lodash-module Now, you can bower install it. – jgomo3 Aug 12 '15 at 01:41
  • 1
    I saw that suggestion before and it is definitely a good one, but I still prefer the tiny 'manual' way that I have it because then I don't have to depend on the module maintainer to keep up with the latest lodash. That said, I think there's some weird edge cases where the way I suggested doesn't work and in that case, go for the module. – ThinkBonobo Aug 12 '15 at 16:31
  • 1
    Reviewing it's code, keeping up with the lastest lodash wouldn't be the problem as it's bower.json sets lodash to lastest version. But setting an specific lodash version as dependency is a problem. – jgomo3 Aug 13 '15 at 13:52
  • 1
    @ThinkBonobo I just want to make sure I am getting things here. In your controller example, you actually didn't inject lodash, right? or am i missing something. – defaultcheckbox Sep 21 '16 at 15:02
  • 1
    Old but gold! I think that should be the answer as it is complete and step-by-step. Worked pretty well for me. – ramires.cabral Apr 27 '18 at 18:07
29

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

Marc Kline
  • 9,399
  • 1
  • 33
  • 36
2

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>
magizh
  • 41
  • 5