I've just come across this and am wondering if it's a bug or expected behaviour? This is just a small example to show the issue. The code below is used in both examples:
<body ng-app="app" ng-controller="AppCtrl">
<item-directive ng-repeat="item in ::items" item="item"></item-directive>
</body>
angular
.module('app', [])
.controller('AppCtrl', AppCtrl)
.directive('itemDirective', itemDirective)
.factory('model', model);
function AppCtrl($scope, model) {
$scope.items = model.getItems();
}
function itemDirective() {
return {
restrict: 'E',
replace: true,
scope: {
item: '='
},
templateUrl: 'item-directive.html'
};
}
function model() {
return {
getItems: getItems
}
function getItems() {
return [
{
type: 'test',
title: 'test 1'
},
{
type: 'test',
title: 'test 2'
},
{
type: 'test',
title: 'test 3'
}
];
}
}
The first example has this item-directive.html which gets rendered in the correct order as expected
<div>
<span>{{::item.title}}</span>
</div>
Plunkr without ng-if
But the second example - which has the below item-directive.html - incorporates an ng-if
, which is causing the list to get rendered in reverse order?
<div ng-if="item.type == 'test'">
<span>{{::item.title}}</span>
</div>
Plunkr with ng-if
-------- UPDATE ----------
I've just noticed (which relates to the issue noted in @squiroid's answer) that the isolate scope isn't actually working in this example. It appears to be, but item
is being made available to the item-directive
scope (or rather the scope it ends up with) by the ng-repeat
, not the isolate scope. If you try to set any other values on the isolate scope, even though they show up on the scope passed to the directive's link and controller functions (as can be seen in the console output for the plnkr), they're not available to the template. Unless you remove replace
.
Plunkr showing broken isolate scope
Plunkr showing fixed isolate scope when replace:false
--- UPDATE 2 ---
I've updated both of the examples to show the issue persisting once the the isolate scope is removed
Plunkr without ng-if and no isolate scope
Plunkr with ng-if and no isolate scope
And also a new version showing the change from templateUrl to template - as suggested by @Manube - that shows the behaviour working as expected
Plunkr with ng-if and no isolate scope using template instead of templateUrl
ISSUE
This is happening with the combination of replace:'true' and ng-if on the root element.
Make sure the contents of your html in the templateUrl has exactly one root element.
If you place ng-if on span
<div >
<span ng-if="item.type == 'test'">{{::item.title}}</span>
</div>
Now why it is happening,it is happening because The ngIf directive removes or recreates a portion of the DOM tree based on an {expression}. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
which may lead to no root element on the templateUrl while rendering and thus leads to unwanted behaviour.
It is to do with templateUrl, which is asynchronous;
If you replace templateUrl by
template:'<div ng-if="item.type === \'test\'"><span>{{::item.title}}</span></div>'
it will work as expected: see plunker with template instead of templateUrl
the test <div ng-if="item.type === 'test'">
will execute when scope is ready and the templateUrl has been fetched.
As the way the template is fetched is asynchronous, whichever template comes back first executes the test, and displays the item.
Now the question is: why is it always the last template that comes back first?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With