James Allardice
James Allardice

Reputation: 165971

Can I stop AngularJS from completely rebuilding a repeated section of the DOM?

Given the following simple module and controller:

var t = angular.module("test", []);
t.controller("TestCtrl", function ($scope, $timeout) {

    $scope.arr = [
        "elem1",
        "elem2",
        "elem3"
    ];

    $scope.getDate = function () {
        return +new Date();
    };

    $timeout(function () {
        $scope.arr[2] = "< I should have a different timestamp to the two above me now";
    }, 2000);
});

And the following simple template:

<ul ng-app="test" ng-controller="TestCtrl">
    <li ng-repeat="x in arr">{{getDate()}} {{arr[$index]}}</li>
</ul>

Is there a way I can make the ng-repeat directive only update the necessary elements in the DOM, rather than rebuilding the entire set of li elements, when a single value in the arr property of the model changes?

I would like to be able to render that list so the timestamp against the first 2 elements does not change when the 3rd element is modified after the timeout.

Here's a fiddle containing the above example.

Edit: please note that the timestamp in this example is only there to demonstrate the issue. My real code is far more complex and is suffering from performance problems due to the number of DOM nodes Angular is recreating every time. Adding the timestamp to the model is not a solution in this case.

Upvotes: 3

Views: 568

Answers (2)

Jan
Jan

Reputation: 1000

If you include an expression in a watcher (a {{curly-brace}} expression is nothing but a watcher) that returns a different value (curly brace watchers user strict equality (===) to detect changes) every time it's called, you will always see them updated.

If you want to fix that you have to recompute these expressions outside of watcher expressions as a response to some more meaningful event.

Using your getDate() as an example, you would have to include them in your model somehow. You could for example have a separate array that stores the date for every index of the original array and update both arrays simultaneously.

Upvotes: 0

Chandermani
Chandermani

Reputation: 42669

One way to do it would be to make timestamp a model property.

Here is what i did

http://jsfiddle.net/vx2c3/2/

<ul ng-app="test" ng-controller="TestCtrl">
    <li ng-repeat="x in arr" ng-init="t=getDate()">{{getDate()}} and {{t}} {{arr[$index]}}</li>
</ul>

That is basically create a model property t

Upvotes: 1

Related Questions