AngularJS $ timeout does not wait for UI-Router to finish rendering before calculating values

I use angularJS and requirejs through angularAMD to combine a complex application.

In one of my conditions there are two simple types:

  $stateProvider .state("common", { url: "/", views: { "view1": { templateUrl: "view1.tpl.html" }, "view2": { templateUrl: "view2.tpl.html" } } }); 

HTML

 <div ui-view="view1"></div> <div ui-view="view2"></div> 

View1 has the directive:

  .directive('checkViewOneBoxWidth', function ($timeout) { return { restrict: 'A', link: function (scope, elem, attrs) { var linkFunctionAfterDomComplete = function () { console.log(elem[0].scrollWidth); } $timeout(linkFunctionAfterDomComplete, 0); } } }) 

And view2 has a stylesheet that applies some styles to the page, including changing the height and width in the View1 container.

I want the linkFunctionAfterDomComplete function linkFunctionAfterDomComplete calculate the height and width elements of the property after the DOM has been changed by the stylesheet in view2 , so I wrapped the linkFunctionAfterDomComplete function in $timeout() .

console.log from checkViewOneBoxWidth here reports the size of this element before the style from the stylesheet in view2 changes the size of this element, even though we expect $timeout call the linkFunctionAfterDomComplete function to calculate the size of this element after styling from view2 and the DOM is applied completed.

How can I get linkFunctionAfterDomComplete to calculate the properties of an element that reflect those that reflect the true state of the element after it has been fully displayed and all styles have been applied?

http://plnkr.co/edit/WjGogh?p=preview

+6
source share
1 answer

You need to pass the function $timeout :

 $timeout(function() { console.log('timeout: view 1 linked') }, 0); 

Or:

 var fn = function () { console.log('timeout: view 1 linked'); }; $timeout(fn, 0); 

Following:

 $timeout(console.log('timeout: view 1 linked'), 0); 

Run console.log instantly, then pass the return value ( undefined ) as the first argument to $timeout .

Demo: http://plnkr.co/edit/zWgoJihcMH693fWfUp09?p=preview

Not sure if you have the same problem in your real application, but I thought I should post this anyway.


New answer based on editing

The problem is that your link element is in the view template, not in index.html.

If you move it to index.html, it will work as you expect (in which case you will not need $timeout , unless your real application adds custom HTML from the directive):

Demo: http://plnkr.co/edit/m3sriF2YYH5T8y42R5Lr?p=preview

If you save the link in the view template and save the timeout, this basically happens:

  • Angular will perform its compilation function to prepare all the bindings and views.
  • HTML from the views will be inserted into the DOM, directives will be executed, and console.log will be added to the timeout queue.
  • The link element is now pasted into the DOM and the browser will start retrieving CSS. Console.log is console.log in the wait queue.

Please note that CSS fetching is asynchronous, and console.log from the timeout queue will be executed until CSS fetching and parsing is complete.

Also note that in different browsers you can see different types of behavior.

There are solutions, but it can get really dirty.

To learn more about this:

When is the stylesheet really loaded?

I would recommend just moving the link to index.html.

+4
source

All Articles