Does ng-repeat recreate all child DOM elements when new data is appended to the array? - angularjs

I created a directive that handles infinity loading of blog posts as the user scrolls down.
I'm wondering how AngularJS handles the addition of new blog posts when the feed is rendered using ng-repeat.
For example
<article ng-repeat="post in posts">
// stuff...
</article>
Are all the articles recreated each time posts is updated with new posts? Assuming that only new posts are appended to the array.
Is ng-repeat smart enough to only create the new posts?
I worry that after the user has scrolled down for a long period the refresh rate will get slower as ng-repeat recreates all the blogs each time new ones are fetched from the server.

ng-repeat, by default, tracks the items of the collection by their $id(): angular associates an identity to every item, and if you add a node to the collection, the elements already associated to the existing items of the collection won't be recreated.
OTOH, if your strategy is to recreate a new collection of items every time you scroll down, the new items will have a different identity (even if they represent the same post as before), and angular will recreate all the DOM elements. That's what track by is for: it allows telling ng-repeat how to associate DOM elements with items of the collection. You could for example use track by id, and an element previously associated with an item with id 3 will be preserved by ng-repeat and be associated to the new item having the id 3.

Related

How to iterate over a collection of objects already filtered by ng-repeat filters

I have a collection of objects that AngularJS filters by a text search within a title property on each object.
After this filter has run, I am left with a set of items that matches this filter.
I would like to iterate over this subset of the list, after clicking a button, and change a property on the items that match this filter.
Is there an easy way to do this in AngularJS, or am I going to be doing this outside Angular and then updating the state manually in the controller?
When the user clicks the button you can get this values and make some change. But I think you need do it inside your controller.
It appears that within an ng-repeat you can do the following
item in items | filter:x as results will store the fragment of the repeated items as results, but only after the items have been processed through the filter.

angularJS is it possible to update model without updating the view

I'm integrating in an angularJS app a non angularJS module for dragging items in a list (or across several list items containers) and the lists themselves are bound to an object containing several arrays (the model) and an ng-repeat generates the items in each list.
When performing a drag across lists, the drag module does it job perfectly in the html but doesn't update the model so i had to try that in its "dragend" event but the problem was that the lists twinkle and i wish i could avoid that effect. I need the view to be generated initially according to the model then disconnect the model and the view.

ng-repeat v/s md-virtual-repeat

Difference between angular ng-repeat and angular material md-virtual-repeat?
When should i use one or another?
ng-repeat renders all elements in list, its less performant on large lists.
md-virtual-repeat renders list what is visible on viewport, it doesn't render all elements of list, when user scrolls in case of large lists it then seemlesly renders other elements, this way its performant and should be used when working with large lists.
Angular documentation tells it pretty clearly:
Virtual repeat is a limited substitute for ng-repeat that renders only enough dom nodes to fill the container and recycling them as the user scrolls. Arrays, but not objects are supported for iteration. Track by, as alias, and (key, value) syntax are not supported.
Source
md-virtual-repeat is similar to ng-repeat but it is very useful when you want to load large amount of data.
Consider you have to load a 100,000 records. In this case if it is ng-repeat then it will load all the data initially. So the user may get frustrated while it is loading. If the user wants the first 50 rows of data only, ng-repeat forces him to wait until all 100,000 records load!
To avoid this in material we have md-virtual-repeat. It loads the next set of data when there is a demand for it (the user scrolls for more data)
Ultimately, the loading time is optimized if you use md-virtual-repeat.
The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
Source
ng-repeat loads the entire data set before rendering to the UI. It is extremely useful when dealing with a smaller list. To ensure that it is most effective it is advisable to use track by and or limit to in the ng-repeat expression. A great md-data-table example that uses ng-repeat is Daniel Nagy's table
With a large list of records ng-repeat becomes very much slower. If it is slow the recommended usage is to switch to md-virtual-repeat
md-virtual-repeat specifies an element to repeat using virtual scrolling.
Virtual repeat is a limited substitute for ng-repeat that renders only enough DOM nodes to fill the container and recycling them as the user scrolls.
Source
md-virtual-repeat only loads the data on demand - the user scrolls. It loads the data much quicker when having a large result set. md-virtual-repeat becomes cumbersome when inserting it into a table.

ng-repeat Efficiency and Working

I am using ng-repeat for my Model render in angular ,
if i Push new Element in Model/Collection , Will angular only deal with Update or Loop through the whole model again.??
My experience (using Angular version 1.2.7) is such that whenever something changed in collection, the whole ng-repeat was repainted.
You can easily test it by modifying the generated DOM. For example by adding custom attributes like my-id="1", my-id="2" etc to the DOM elements.
Then change something in your collection, which will trigger new $digest cycle.
Angular will pick up the change and redraw the DOM -> your custom attributes will disappear.
So I would argue that Angular loops through the whole model.
In the documentation it is clearly mentioned:
ngRepeat
ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope
Angular associates an identity to every item, the elements already associated to the existing items of the collection won't be recreated.
Hence, only elements that are removed from the collection, are removed from the DOM. Furthermore, if an item moves within the collection it doesn’t need a new scope, but it needs to be moved in the DOM.

Does ng-repeat retain DOM elements or create all new ones when the collection changes?

I've seen a lot of questions about the order in which ng-repeat finishes compared to other directives or things going on in Angular land, but I haven't been able to find an answer to how exactly it accomplishes this.
I have two ideas of how it could work.
First Way:
When ng-repeat's watcher triggers, it removes all elements it created from the DOM then creates all new elements in their place, even if many of those elements are the same (e.g. in the case of 1 item added to the backing array).
Second way: Since ng-repeat already keeps track of which elements go with which items in its backing collection, it simply removes the items that no longer exist in the collection and creates new elements for items that are new to the collection.
Which is it and why?
It's the second way: Angular tries to be smart about creating/removing DOM elements:
The ngRepeat directive provides a way to render a collection of items given a template. To do this, AngularJS compiles the given template and then clones it for each unique item in the collection. As the collection is mutated by the Controller, AngularJS adds, removes, and updates the relevant DOM elements as needed.
But, how does AngularJS know which actions to perform when? If you start to test the rendering, you'll discover that AngularJS doesn't brute force DOM creation; that is, it doesn't recreate the DOM for every rendering. Instead, it only creates a new DOM element when a completely new item has been introduced to the collection. If an existing item has been updated, AngularJS merely updates the relevant DOM properties rather than creating a new DOM node.
This can still impact performance unnecessarily, i.e. when passing elements by-value in a collection (there's an excellent example of this in the blog post linked above). That's why Angular supports "track by" for ngRepeat since version 1.2: It's a way to help Angular decide when DOM creation is necessary:
With this association in place, AngularJS will not $destroy and re-create DOM nodes unnecessarily. This can have a huge performance and user experience benefit.
The official documentation states:
You can also provide an optional tracking function which can be used to associate the objects in the collection with the DOM elements. If no tracking function is specified the ng-repeat associates elements by identity in the collection.
For example: item in items track by item.id is a typical pattern when the items come from the database. In this case the object identity does not matter. Two objects are considered equivalent as long as their id property is same.

Resources