当插入指令属性时,如何避免启动时出现竞争条件



这个fiddle应该会让事情变得更清楚,但本质上我在它的指令中分配了元素的一些属性(比如它的id)参数:

myApp.directive('myDiv', function () {
return {
    restrict: 'E',
    replace: true,
    scope: {
        'elementId': '@',
        'displayName': '@',
    },
    transclude: true,
    template: '<div class="my-div" id="{{elementId}}">{{displayName}}<div ng-transclude></div></div>'
}

})

问题是,如果我在启动时立即执行一些操作,比如初始化其他指令,那么这些值(例如elementId)还没有插值。

换句话说,如果我获得对myDiv元素的引用并打印其id,则在启动时立即打印"{{elementId}}"。但是,如果我等待很短的时间(比如一秒钟),那么将打印作为值传递给元素id属性的值(正如我所期望的)。

如果你在观看Fiddle时打开控制台,你会看到的。

我在这里做错了什么?我该如何避免这种情况(除了在启动时出现很多非常糟糕的超时)?

您有几点不正确。这里有一个新的fiddle,您可以在其中看到显示正确值的"最初"日志:http://jsfiddle.net/0mq2xv8m/

1) 您应该在第二个的模板中包含内部元素。您已将transclude设置为true,因此它将替换您的节点。这也确保了第二个指令在第一个指令准备好之前不会绑定。也就是说,由于它与outter指令一起在DOM中,因此它可能与包装指令实例化不同步。

template: '<div class="my-div" id="elementId">{{displayName}}<div my-field></div></div>'

2) 执行id="elementId"而不是id="{{elementId}}"以通过引用而不是值

3) 通常,在父对象上查找属性是不好的做法,最好通过双向绑定将其传入。这在我使用过的任何面向显示列表的编程中都适用。

良好实践:

您应该为任何"init"步骤使用控制器或链接函数。在指令链接了所有属性/作用域之前,这些函数不会运行。按照您的方式,它在$scope创建期间的评估步骤中执行(目前还没有作用域)。链接函数和控制器等待$scope可用。可以使用控制器来代替链接功能(我认为它更清晰,更容易进行单元测试)。

angular.module('App').controller('someController',[], function() {
        var controller = {
            init:function(){
                console.log(elementId);
             }
        }
        controller.init();
        return controller;
});

myApp.directive('myDiv', function () {
return {
    restrict: 'E',
    replace: true,
    controller:'someController',
    scope: {
        'elementId': '@',
        'displayName': '@',
    },
    transclude: true,
    template: '<div class="my-div" id="{{elementId}}">{{displayName}}<div ng-transclude></div></div>'
}

最新更新