ng-if反转ng-repeat渲染顺序

时间:2015-02-21 17:24:01

标签: angularjs

我刚刚碰到过这个,我想知道它是不是一个错误或预期的行为?这只是一个显示问题的小例子。以下代码用于两个示例:

<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'
            }
        ];
    }
}

第一个示例有这个item-directive.html,它按照预期的正确顺序呈现

<div>

    <span>{{::item.title}}</span>

</div>

Plunkr without ng-if

但是第二个例子 - 它有以下item-directive.html - 包含一个ng-if,导致列表以相反的顺序呈现?

<div ng-if="item.type == 'test'">

    <span>{{::item.title}}</span>

</div>

Plunkr with ng-if


--------更新----------

我刚刚注意到(这与@squiroid的回答中提到的问题有关),隔离范围在这个例子中实际上并不起作用。它似乎是,但是item范围内item-directive范围(或者更确切地说是范围)可以使ng-repeat可用,而不是隔离范围。如果您尝试在隔离范围上设置任何其他值,即使它们显示在传递给指令的链接和控制器功能的范围内(可以在plnkr的控制台输出中看到),它们&#39 ;不可用于模板。除非您删除replace

Plunkr showing broken isolate scope

Plunkr showing fixed isolate scope when replace:false


---更新2 ---

我已更新了两个示例,以便在删除隔离范围后显示问题仍然存在

Plunkr without ng-if and no isolate scope

Plunkr with ng-if and no isolate scope

还有一个新版本显示了从templateUrl到模板的更改 - 正如@Manube所建议的那样 - 显示了按预期工作的行为

Plunkr with ng-if and no isolate scope using template instead of templateUrl

3 个答案:

答案 0 :(得分:1)

它与templateUrl有关,它是异步的;

如果您用

替换templateUrl
 template:'<div ng-if="item.type === \'test\'"><span>{{::item.title}}</span></div>'

它将按预期工作:see plunker with template instead of templateUrl


当范围准备好并且已获取templateUrl时,将执行测试<div ng-if="item.type === 'test'">

由于获取模板的方式是异步的,无论哪个模板首先执行测试,都会显示该项目。

现在的问题是:为什么它总是最后一个模板?

答案 1 :(得分:1)

在指令的根元素上使用ng-if并使用replace:true创建一个损坏的范围

ISSUE

组合使用replace:'true'和ng-if在根元素上。

确保templateUrl中html的内容只有一个根元素。

如果你把ng-if放在span

<div >

    <span ng-if="item.type == 'test'">{{::item.title}}</span>

</div>

现在为什么会发生这种情况,因为ngIf指令基于{expression}删除或重新创建DOM树的一部分。如果分配给ngIf的表达式求值为false值,则从DOM中删除该元素,否则将元素的克隆重新插入DOM中。

在渲染时可能导致templateUrl上没有根元素,从而导致不必要的行为。

答案 2 :(得分:0)

第二个以相反的顺序显示由于使用item-directive name定义的自定义指令,但由于使用了replace = true而没有呈现为DOM。

如需更多参考,请参阅this link