Description
My team has recently faced an issue with controllers being instantiated twice on route transition. While trying to find the reason for this, I've recognized that even the corresponding views got rendered twice, which was rather... unlikely.
This problem was detected in v0.2.7 - 20fcbf8 thus I considered moving to v0.2.8 - f9ce4dd should solve this. But it did not.
Information
Angular-version: 1.2.11
The relevant routes look like this (I cannot post everything, since it's part of a closed project):
$stateProvider
.state('1ColumnLayout', {
'abstract': true,
url: "/1",
templateUrl: "1ColumnLayout.html"
})
.state('login', {
parent: "1ColumnLayout",
url: "/login",
views: {
"screen-above": {template: ""},
"screen": { templateUrl: "login.html", controller: "loginController"}
}
})
.state('plantDetails', {
parent: "2ColumnLayout",
url: "/plantDetails?plantId",
views: {
"screen-above": { templateUrl: "userInfoAndNavigation.html"},
"screen-left": { templateUrl: "details.left.html", controller: "detailsLeftController"},
"screen-right": { templateUrl: "details.right.html", controller: "detailsRightController"}
},
resolve: {
currentId: getId(false)
}
})
While using this template in 1ColumnLayout.html...
<div id="screen-above" class="clearfix" ui-view="screen-above"></div>
<div class="screen1Column clearfix" id="screen-below">
<div class="s1cContent" ui-view="screen"></div>
</div>
...and this one in 2ColumnLayout.html
<div id="screen-above" class="clearfix" ui-view="screen-above"></div>
<div class="screen2Column clearfix" id="screen-below">
<div id="screen-right" ui-view="screen-right"></div>
<div id="screen-left" ui-view="screen-left"></div>
</div>
In a more-or-less long debugging session, I was able to drag down the issue to the following line in viewDirective.js (in v0.2.7):
initialView = transclude(scope);
The call stack mentioned that by calling transclude(...), the compile function is called again, building up the entire view, including controller instantiation. Afterwards, the function went ahead as expected, but destroyed the previously built view completely, building it up once more.
In v0.2.8, this line of code has changed to
anchor = angular.element($document[0].createComment(' ui-view-anchor ')),
which seems more intuitive. However, moving to v0.2.8 did not fix the issue - seems to be broken on another part.
The curious thing...
... is primarily related to the sometimes in the topic: After performing all potential route transitions at least once, all views got rendered only once - as expected.
Workaround
Anyway, just for testing, I've changed
initialView = transclude(scope);
in v0.2.7 to
initialView = angular.element($document[0].createComment(' ui-view-anchor '));
(picked from v0.2.8), and injected $document as well. Result: Everything worked as expected (I've added my diff so that the whole change is visible), which is... interesting.
diff --git a/public/lib/angular-ui-router/src/viewDirective.js b/public/lib/angular-ui-router/src/viewDirective.js
index efc8930..5e0a9ed 100644
--- a/public/lib/angular-ui-router/src/viewDirective.js
+++ b/public/lib/angular-ui-router/src/viewDirective.js
@@ -1,6 +1,6 @@
-$ViewDirective.$inject = ['$state', '$compile', '$controller', '$injector', '$anchorScroll'];
-function $ViewDirective( $state, $compile, $controller, $injector, $anchorScroll) {
+$ViewDirective.$inject = ['$state', '$compile', '$controller', '$injector', '$anchorScroll', '$document'];
+function $ViewDirective($state, $compile, $controller, $injector, $anchorScroll, $document) {
var $animator = $injector.has('$animator') ? $injector.get('$animator') : false;
var viewIsUpdating = false;
@@ -15,7 +15,8 @@ function $ViewDirective( $state, $compile, $controller, $injector, $an
name = attr[directive.name] || attr.name || '',
onloadExp = attr.onload || '',
animate = $animator && $animator(scope, attr),
- initialView = transclude(scope);
+ initialView = angular.element($document[0].createComment(' ui-view-anchor '));
+
// Returns a set of DOM manipulation functions based on whether animation
// should be performed
Even worse, I was not able to reproduce this issue using v0.2.8 with a more simple example, and I'm not sure why it still occurs - wasn't that easy to drag down to a particular line as in v0.2.7 ;)
Maybe some of you have a clue what may cause this, or may check this in a more complex project - rendering views twice, including controller instantiation, is rather unlikely when it comes to performance, or possible side-effects that come along with init-functions.
For the moment, this appears to be a blocking issue in our case which prevents us from moving to v0.2.8 and, as a result, from other fixes / improvements.