This is in relation with my question - Angular JS ng-repeat consumes more browser memory
My problem here is I need nested ng-repeats and the nested ng-repeats consumes more memory because of more watches being registered.
<table>
<thead><td>Id</td><td>Name</td><td>Ratings</td></thead>
<tbody>
<tr ng-repeat="user in users | orderBy:'name' | limitTo:display_limit">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td><div ng-repeat="item in items | orderBy:'rating' | limitTo:inner_display_limit">{{item.rating}}</div></td>
</tr>
</tbody>
</table>
Here in my case, the number of objects that outer ng-repeat and inner ng-repeat operates on can go upto 1000. And as #Liviu pointed in the answer,each of the outer ng-repeat registers watch on the inner ng-repeat and that leads to consumable amount of memory being used. Is there a way we can avoid the outer ng-repeat from registering watches on inner ones by writing our own custom directive?
My case is in both inner and outer ng-repeats, I display the initial 50 items and on scroll, if the scroll reaches the end of the corresponding DOM, I update the limit by 50, so that the next 50 items gets displayed.
Any help is much appreciated!
You could write a directive that takes both users and items as bindings attributes (especially because it seems like your inner loop is independant from the outer one), then manually nest two loops that would add content to the DOM, plus adding a scroll listener to each element. It's more hard-way coding but a lot less watchers.
Related
What is the effect of using the native bindonce on an ng-repeat object? For example:
ng-repeat="data in ::stuff"
Does this mean every item in 'stuff' has the watcher removed? Or do you still need to apply bindonce to every child bind in the repeat like this?
<div ng-repeat="data in ::stuff">
<span ng-bind="::data.thing"></span>
</div>
For data in ::stuff, the array is bound once and a $watcher is not created after bound the first time, and therefore any changes to that array will not update your ng-repeat's view.
However, unless you have ::data.thing changes to individual objects will still be registered. Those watchers belong to the object itself and not the shallow contents of the array.
See my plunkr below.
<iframe src="http://embed.plnkr.co/3gbmI2kqd3rT7z0GEyK7/"></iframe>
We are in the process of upgrading our application to Angular 1.3.0. In doing so, we ran into a few issues, most of which seem to boil down to the behavior of ngTransclude inside of ngRepeat.
We have a directive that repeats a bunch of items, with a container around them, but does not own the children of that container. For instance, here is a simplified example:
<div ng-controller="myController">
There are {{items.length}} items.
<div my-directive items="items">
This item's name is {{item.name}}
</div>
</div>
Internally, the directive contains <li ng-repeat="item in items" ng-transclude></li>, among other things.
Prior to the update, this worked fine. The repeated, transcluded elements are in a scope that inherits from the scope created by ngRepeat. As of the update, the items are in a scope that inherits from the controller, and as far as I can tell, there is no way to access the scope created by ngRepeat.
Here are two JS Bin examples:
Old (1.3.0-beta.1) behavior: http://jsbin.com/kalutu/1/edit
New (1.3.0) behavior: http://jsbin.com/gufunu/1/edit
How can I achieve the old behavior, or some semblance of it, in Angular 1.3.0? If this is the intended behavior of ngTransclude, how can I repeat a bunch of child nodes without knowing what they are?
https://github.com/angular/angular.js/issues/8182
It was decided for 1.3 that ng-trasclude would not pull scope from the directive. There is a work-around on the linked pages,
https://github.com/angular/angular.js/issues/7874
https://github.com/angular/angular.js/issues/7874#issuecomment-47647528
This is the expected behavior.
I am creating rows using ng-repeatand each row has expandable section in which details are shown. i fetch data on row click and populate detail area by two way binding. but here is the problem, all details sections are bidden to common scope variables.
Can someone guide me how to tackle this problem?
One solution in my mind is to maintain map structure for every detail. But do not know will it be a good idea or there is any better solution for this problem
Thanks in advance
EDIT
Angular.js version : 1.0.8
I think your problem is that you are binding the "ng-open" of your details tag to a boolean in the parent scope of your ng-repeat, instead of binding it to an attribute of the ng-repeat iteration itself (each loop of ng-repeat creates a child scope of your actual scope).
Here is an example:
<tr ng-repeat="thing in things">
<td ng-click="showContent = !showContent">
<details id="details" ng-open="showContent">
<summary><em>Details</em></summary>
<p ng-bind="thing.info"></p>
</details>
</td>
</tr>
On each loop of your repeat, it will create a child scope, and each of those scopes will contain a "private" showContent attribute that your ng-open directive will be attached to.
Hope this is your problem and this helps you.
--Edit--
(Of course that you have to be sure that the "showContent" attribute isn't declared on your scope controller)
I'm having difficulties understanding how the track by expression of ng-repeat in angularjs works. The documentation is very scarce: http://docs.angularjs.org/api/ng/directive/ngRepeat
Can you explain what the difference between those two snippets of code is in terms of databinding and other relevant aspects?
with: track by $index
<!--names is an array-->
<div ng-repeat="(key, value) in names track by $index">
<input ng-model="value[key]">
</div>
without (same output)
<!--names is an array-->
<div ng-repeat="(key, value) in names">
<input ng-model="value[key]">
</div>
You can track by $index if your data source has duplicate identifiers
e.g.: $scope.dataSource: [{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}]
You can't iterate this collection while using 'id' as identifier (duplicate id:1).
WON'T WORK:
<element ng-repeat="item.id as item.name for item in dataSource">
// something with item ...
</element>
but you can, if using track by $index:
<element ng-repeat="item in dataSource track by $index">
// something with item ...
</element>
a short summary:
track by is used in order to link your data with the DOM generation (and mainly re-generation) made by ng-repeat.
when you add track by you basically tell angular to generate a single DOM element per data object in the given collection
this could be useful when paging and filtering, or any case where objects are added or removed from ng-repeat list.
usually, without track by angular will link the DOM objects with the collection by injecting an expando property - $$hashKey - into your JavaScript objects, and will regenerate it (and re-associate a DOM object) with every change.
full explanation:
http://www.bennadel.com/blog/2556-using-track-by-with-ngrepeat-in-angularjs-1-2.htm
a more practical guide:
http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/
(track by is available in angular > 1.2 )
If you are working with objects track by the identifier(e.g. $index) instead of the whole object and you reload your data later, ngRepeat will not rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones.
There is fiddle
var app = angular.module( 'myApp', [] );.....
I need to find out the number of list item , which is under editing or bluring to manipulate by it as I need.
How to do it ?
What about replacing this part of your jsFiddle:
<li ng-repeat="contact in contacts">
{{contact.name}}
</li>
with this:
<li ng-repeat="contact in contacts">
<edit-in-place value="contact.name"></edit-in-place>
</li>
That way you don't have to know the index of item as edit-in-place directive will take place after ng-repeat kicks in.
Priority of ng-repeat directive is 1000 and default directive priority (if you don't specify it) is 0.
More abourt directive's priorities from AngulaJS docs:
When there are multiple directives defined on a single DOM element,
sometimes it is necessary to specify the order in which the directives
are applied. The priority is used to sort the directives before their
compile functions get called. Priority is defined as a number.
Directives with greater numerical priority are compiled first.
Pre-link functions are also run in priority order, but post-link
functions are run in reverse order. The order of directives with the
same priority is undefined. The default priority is 0.
There is working jsFiddle.