I'm using angularJS
and requirejs
via angularAMD
to wire together a complex application.
One of my states has two simple views like so:
$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 a 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 styling to the page, including changing the height
and width
of the view1
container.
I want the function linkFunctionAfterDomComplete
to compute the element's height
and width
properties after the DOM has been modified by the stylesheet in view2
, so I wrapped the linkFunctionAfterDomComplete
function in a $timeout()
.
The console.log
from checkViewOneBoxWidth
here is reporting the size of this element, before the styling from the stylesheet in view2
modified the size of this element, despite the fact that we would expect the $timeout
to cause the linkFunctionAfterDomComplete
function to calculate the size of this element after styling from view2
is applied and the DOM is complete.
How can I get linkFunctionAfterDomComplete
to calculate element properties that reflect those which reflect the true state of the element after it had been fully rendered and all styling has been applied?
You need to pass a function to $timeout
:
$timeout(function() {
console.log('timeout: view 1 linked')
}, 0);
Or:
var fn = function () {
console.log('timeout: view 1 linked');
};
$timeout(fn, 0);
The following:
$timeout(console.log('timeout: view 1 linked'), 0);
Will execute the 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 thought I should post this anyway.
The problem is that your link element is located in the view template instead of in the index.html.
If you move it to index.html it will work as you expect (and you don't need the $timeout
in this case, unless your real application adds custom HTML from the directive):
Demo: http://plnkr.co/edit/m3sriF2YYH5T8y42R5Lr?p=preview
If you keep the link in the view template and keep the timeout, this is basically what happens:
console.log
will be added to the timeout queue.console.log
in the timeout queue will execute.Note that the fetching of the CSS is asynchronous and the console.log
from the timeout queue will execute before the fetching and parsing of the CSS has finished.
Also note that you might see different behaviors in different browsers.
There are solutions, but it might get really messy.
To read more about it:
When is a stylesheet really loaded?
I would recommend to just move the link to the index.html.