How can you detect when HTML rendering is completed in AngularJS

扶醉桌前 提交于 2019-12-02 06:05:52

问题


I've done extensive research on this subject, but no matter what I do, I find it extremely difficult to achieve this objective.

I want to execute code when all elements have been fully rendered in AngularJS web application. I think I found solution suggesting to use routers and views, but I could not make that work on my case, as it seems it requires certain configuration.

When you have ng-repeat and a lot of nested directives that will generate HTML/Content based on various conditions using ng-if, I noticed that HTML rendering continues even after document ready event is fired or view content have been loaded ie $viewContentLoaded event is triggered.

The closest idea I have is to use $watch over the length of the children of the element of a given directive. Every time the $watch is executed, increment counter renderCount. Then, in another timer event, check if the counter renderCount didn't change over the past say 3-5 seconds, then we can make an assumption that rendering is done.

The code to watch for the children, and check if no more rendering is taking place, could be as follows:

app.directive('whenRenderingDone',  function($interval, $parse){
    return {
        link: function (scope, el, attrs) {
            var renderingCount = 0;
            function watchForChildren() {
                scope.$watch(function(){
                    return $(':input', el).length;
                }, function(newVal, oldVal){
                    if (newVal) {
                        renderingCount++;
                    }
                })
            }
            watchForChildren();
            //Check counter every 3 seconds, if no change since last time, this means rendering is done.
            var checkRenderingDone = $interval(function(){
                var lastCount = lastCount || -1;
                if (lastCount === renderingCount) {
                    var func = $parse(attrs.whenRenderingDone);
                    $interval.cancel(checkRenderingDone);
                    func(scope);
                }
                lastCount = renderingCount || -1;
            }, 3000);
        }
    }
});

I will try to implement the above approach, and if you have feedback please let me know.

Tarek


回答1:


I developed the following directive which is working well under Chrome and IE11:

app.directive('whenRenderingDone',  function($timeout, $parse){
    return {
        link: function (scope, el, attrs) {
            var lastCount;
            var lastTimer = 5000; // Initial timeout
            //Check counter every few seconds, if no change since last time, this means rendering is done.
            var checkRenderingDone = function (){
                var mainPromiseResolved = scope.mainPromiseResolved;
                lastCount = lastCount || -1;
                if (lastCount === el.find('*').length && mainPromiseResolved) {
                    console.log('Rendering done, lastCount = %i', lastCount);
                    var func = $parse(attrs.whenRenderingDone);
                    func(scope);
                } else {
                    lastCount = el.find('*').length;
                    console.log('mainPromiseResolved = %s, lastCount %i', mainPromiseResolved, lastCount)
                    console.log('Rendering not yet done. Check again after %i seconds.', lastTimer/1000.00);
                    stopCheckRendering = $timeout(checkRenderingDone, lastTimer); 
                    lastTimer = lastTimer - 1000;
                    if (lastTimer <= 0) {
                        lastTimer = 1000;
                    }
                    return stopCheckRendering;
                }
            }
            var stopCheckRendering;
            stopCheckRendering = checkRenderingDone();
            el.on('$destroy', function() {
                if (stopCheckRendering) {
                    $timeout.cancel(stopCheckRendering);
                }
              });
        }
    }
});

I hope this will be of help to you, and if you have any comment to improve, please let me know. See this to give you an idea about how it is working.

Tarek




回答2:


You can use $$postDigest to run code after the digest cycle completes. You can read more about the scope lifecycle here

// Some $apply action here or simply entering the digest cycle
scope.$apply(function () { ... });
...
scope.$$postDigest(function () {
  // Run any code in here that will run after all the watches complete
  // in the digest cycle. Which means it runs once after all the 
  // watches manipulate the DOM and before the browser renders
});


来源:https://stackoverflow.com/questions/46691601/how-can-you-detect-when-html-rendering-is-completed-in-angularjs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!