0

I have the following code with custom directive 'my-repeater':

<div ng-controller="AngularCtrl">
  <div my-repeater='{{items}}'>Click here</div>
</div>​

Here is my custom directive:

myApp.directive('myRepeater', function($compile) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var myTemplate = "<div ng-click='updateRating({{item}});' ng-class='getRatingClass({{rating}});'>{{rating}}</div>";
            var items = scope.items;
            console.log('length: ' + items.length);
            for (var i = 0; i < items.length; i++) {
                var child = scope.$new(true);
                console.log(items[i].ratings);
                child.item = items[i];
                child.rating = items[i].ratings;                    
                var text = $compile(myTemplate)(child);
                element.append(text);
            }
   }
};

});

ng-click and ng-class bindings are not happening properly inside my custom directive. Can anyone help me with what i am doing wrong here?

Here is the JS Fiddle. http://jsfiddle.net/JSWorld/4Yrth/5/

Chubby Boy
  • 30,942
  • 19
  • 47
  • 47

2 Answers2

6

Hi I've updated your sample to what I think you want to do.

http://jsfiddle.net/46Get/2/

  • First, in directives like ng-click='updateRating({{item}});' that receive an expression you dont need to use '{{}}' because it is already executed in the scope.

  • Second, when you need to add siblings to your directive, you need to do it in the compilation phase and not the linking phase or just use ng-repeat for that matter

rseidi
  • 88
  • 6
  • 1
    Thanks rseidi! But i dont want to use ng-repeat. I am facing a issue with nested ng-repeats as it piles up heap memory. Hence i wanted to write my own custom directive for ng-repeat and hence i came up with that. Can you help me to get this binding without using ng-repeat? – Chubby Boy Dec 29 '12 at 11:44
  • Humm, I dont see where this aproach is gonna be better than using ngRepeat, How many items do you display at time? What you really wanna do? – rseidi Dec 29 '12 at 12:03
  • I have roughly around 150*150 items to display. so nested ng-repeat didn't work for me. so i have to go with writing custome one. please see this for reference. http://stackoverflow.com/questions/14065050/angular-js-consumes-more-browser-memory/ – Chubby Boy Dec 29 '12 at 12:15
  • I see, you could try something like this http://jsfiddle.net/46Get/3/, pre-generate the template dont create child scopes and reference every item by its index. This should lower the heap but you still creating a lot of watches. Otherwise I recommend you to encapsulate all this logic in a purely jquery widget and a directive just for integration. – rseidi Dec 29 '12 at 12:42
  • Awesome! This is exactly what i wanted! Thanks so much rseidi! – Chubby Boy Dec 29 '12 at 13:00
  • I think you should consider paginate this view, that's a lot of data to show at once, from UX perspective. – rseidi Dec 29 '12 at 13:02
  • A scope is being created for each item by the $compile service. See my answer for a workaround. – Mark Rajcok Dec 29 '12 at 19:19
  • Thanks much for your answer Mark! As I said, I have roughly around 150*150 items to display. so nested ng-repeat didn't work for me. so i have to go with writing custome one. Now with the current directive that i have, the memory usage is reduced to 90MB from around 300MB. But still if i remove 'ng-class' it is reduced to 69MB and if i remove 'ng-click' as well, it is reduced to 43MB. Why is that ng-class and ng-click consuming so much of memory? Also is there a known issue with using nested ng-repeats in angular? – Chubby Boy Dec 30 '12 at 06:28
  • With your answer of using an outer 'div' to avoid creation of scope, the memory usage **reduced to 90MB from 95MB**. so is there a way we can reduce it further by replacing **ng-click** (as it consumes around 26MB of memory) with **element.on('click')** or something else? – Chubby Boy Dec 30 '12 at 06:34
2

I added .ng-scope { border: 1px solid red; margin: 2px} to @rseidi's answer/fiddle, and I discovered that a scope is being created by the $compile service for each item in the template -- i.e., each <div>. Since you have so many items to display, I assume that fewer scopes will be much better. After trying a bunch of different things, I discovered that Angular seems to create a new scope for each "top level" element. So a solution is to create an outer div -- i.e., ensure there is only one "top level" element:

var mainTpl = '<div>';  // add this line
...
for(...) { }
mainTpl += '</div>';    // add this line

Fiddle

Now, only the outer div creates a scope, since there is only one "top level" element now, instead of one per item.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492