Does Angular use DOM diffing or must it "re-render" every list item?
There is quite a bit of confusion regarding this topic, mostly because it's not a simplistic "angular re-renders everything" type answer.
The basis of angular data binding (in 1.x releases) surrounds around the concept of a $digest
loop and $scope
. $scope
is a special object which "self tracks" it's properties, and creates a JavaScript event listener for each property, using the method $scope.$watch()
. These listeners monitor changes to the changeable input elements in HTML, and to the $scope
properties.
Whenever any JavaScript listener fires, the $digest
loop cycles through every item under $watch
and updates the values appropriately. You also can call $scope.$apply()
to manually execute a $digest
loop. This loop can execute multiple times, as changes to one value can affect another value under $watch
which triggers another $digest
. The $digest
loop does have an iteration cap to ensure it stops on circular references, however.
The rub comes in when you are dealing with arrays of objects, and the special directive ng-repeat
. By default, the $watch()
function only checks object reference equality. Within each $digest
, AngularJS will check to see if the new and old values are the same "physical" object, and will only invoke its handler if you actually change the underlying object reference.
To counter this, ng-repeat
creates it's own unique scope
. This allows for a unique $watch
for every element in the array. The challenge here is that if the array itself changes, then this unique scope
is regenerated, along with all the $watch
elements. Pushing, Popping, Splicing an array can create many $watch
values.
Angular provides a few ways to deal with this issue.
The new Bind Once syntax added in 1.3 allows for Listeners which only exist until the expression is evaluated. ng-repeat="element in ::elements"
Will iterate through the array, populate the DOM, then destroy the Event Listener. This is ideal for situations where the DOM element does not change once evaluated.
It is also possible to aggressively track elements, using track by
. ng-repeat="element in elements track by $id"
will create a $watch
on the unique $id
value, rather than the element's position in the array. This allows for more stable $watch
propagation, and is ideal in cases where the value of the element may change.
As to why the changes you made in the console were not lost: Firstly, changes in the developer console are not going to trigger any Event Listeners. Secondly, the specific DOM element you changed would only be modified if the $watch
detected a change. This is not really a 'Diff' of the HTML, however; Angular isn't "watching the HTML", it is "watching the data", so to speak.