Skip to content Skip to sidebar Skip to footer

Angular Ng-repeat Cache (avoid Re-rendering On State Change)

We have huge rendering spikes with ng-repeat in Angular application. Main page shows a huge list of cover images ('::' and 'track by' are in place). On first load it works acceptab

Solution 1:

Well if you disable the scope of the scope that the ng-repeat is on. Then it will no longer render. It essentially becomes static content. This allows you to actually control when it is rendered.

ux-datagrid actually uses this concept to turn off dom that is out of view so angular doesn't know about it and cannot render it. Then it hooks it back up when it is in view.

Each scope works on a digest cycle. In the digest cycle it processes the $watchers that are on the scope.

If you remove those watchers, it does not digest it or it's children.

These are the 2 methods that the ux-datagrid uses in it's code to activate and deactivate scopes. You could copy these to another object and use them for the same thing.

/**
 * ###<a name="deactivateScope">deactivateScope</a>###
 * One of the core features to the datagrid's performance is the ability to make only the scopes
 * that are in view to render. This deactivates a scope by removing its $$watchers that angular
 * uses to know that it needs to digest. Thus inactivating the row. We also remove all watchers from
 * child scopes recursively storing them on each child in a separate variable to activate later.
 * They need to be reactivated before being destroyed for proper cleanup.
 * $$childHead and $$nextSibling variables are also updated for angular so that it will not even iterate
 * over a scope that is deactivated. It becomes completely hidden from the digest.
 * @param {Scope} s
 * @param {number} index
 * @returns {boolean}
 */functiondeactivateScope(s, index) {
    // if the scope is not created yet. just skip.if (s && !isActive(s)) { // do not deactivate one that is already deactivated.
        s.$emit(exports.datagrid.events.ON_BEFORE_ROW_DEACTIVATE);
        s.$$$watchers = s.$$watchers;
        s.$$watchers = [];
        s.$$$listenerCount = s.$$listenerCount;
        s.$$listenerCount = angular.copy(s.$$$listenerCount);
        subtractEvents(s, s.$$$listenerCount);
        if (index >= 0) {
            s.$$nextSibling = null;
            s.$$prevSibling = null;
        }
        returntrue;
    }
    returnfalse;
}

/**
 * ###<a name="activateScope">activateScope</a>###
 * Taking a scope that is deactivated the watchers that it did have are now stored on $$$watchers and
 * can be put back to $$watchers so angular will pick up this scope on a digest. This is done recursively
 * though child scopes as well to activate them. It also updates the linking $$childHead and $$nextSiblings
 * to fully make sure the scope is as if it was before it was deactivated.
 * @param {Scope} s
 * @param {number} index
 * @returns {boolean}
 */functionactivateScope(s, index) {
    if (s && s.$$$watchers) { // do not activate one that is already active.
        s.$$watchers = s.$$$watchers;
        delete s.$$$watchers;
        addEvents(s, s.$$$listenerCount);
        delete s.$$$listenerCount;
        if (index >= 0) {
            s.$$nextSibling = scopes[index + 1];
            s.$$prevSibling = scopes[index - 1];
            s.$parent = scope;
        }
        s.$emit(exports.datagrid.events.ON_AFTER_ROW_ACTIVATE);
        returntrue;
    }
    return !!(s && !s.$$$watchers); // if it is active or not.
}

I am not sure this will fully answer your question because you are using UI-Router. If the view is recreated and not cached then it will still re-render it all in the compile. However, if not this does not just do a watch once, when you disable this scope, it disables all children of that scope as well. Essentially detaching it from the digest and all child nodes with it.

Re-enabling it adds them all back in. So you really turn off the ng-repeat and everything in it with one call to deactivate. It becomes static all of the way down until you re-enable it.

Post a Comment for "Angular Ng-repeat Cache (avoid Re-rendering On State Change)"