This 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}}”。但是如果我等待一小段时间(比如说,一秒钟),则会打印作为element-id属性的值传递的值(正如我所期望的那样)。
如果您在查看小提琴时打开控制台,您会看到。
我在这里做错了什么?我怎样才能避免这种情况(除了启动时很多非常丑陋的超时)?
答案 0 :(得分:2)
你有几件事不正确。这是一个新的小提琴,你可以看到'at first'日志显示正确的值:http://jsfiddle.net/0mq2xv8m/
1)您应该在第二个模板中包含内部元素。您已将transclude设置为true,因此它将替换您的节点。这也确保第二个指令在第一个指令准备好之前不会绑定。即因为它与DOM指令一起位于DOM中,所以它可能与包装指令不一致地实例化。
template: '<div class="my-div" id="elementId">{{displayName}}<div my-field></div></div>'
2)执行id="elementId"
代替id="{{elementId}}"
传递而不是值
3)通常在父母身上捕捉属性是不好的做法,最好通过双向绑定传递它。在我使用过的任何面向显示列表的编程中都是如此。
良好做法:
您应该使用控制器或链接功能进行任何“初始化”步骤。在指令将其所有属性/范围链接起来之前,这些都不会运行。你拥有它的方式,它是在$ 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>'
}