据我所知,Angular以先到先得的方式编译东西,这有点棘手。我制定了一个指令,将一些元素封装起来,我希望有一个链接属性来查找内容中的内容。
对于一个具体的用例:我正在制作一个输入标签指令,该指令查看第一个输入的内容内部,并将随机生成的id
添加到input
,将for
属性添加到label
这是代码:
// Find the first element with the attribute ng-label-target or the first input and links a label to it
app.directive('ngLabel', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
label: '@',
},
template: '<span class="ng-label">' +
'<label class="ng-label-text">{{label}}</label>' +
'<span class="ng-label-content" ng-transclude></span>' +
'</span>',
link: function (scope, element, attrs) {
scope.id = scope.id || 'random-id-' + Math.floor(Math.random() * 90000000);
angular.element(element[0].querySelector('.ng-label-text')).
attr({for:scope.id});
var target = angular.element(element[0].querySelector('[ng-label-target]'));
if (!target || target.length == 0) {
target = angular.element(element[0].querySelectorAll('input,select,textarea')[0]);
}
target.attr({id:scope.id});
},
};
});
示例用法:
<ng-label label="Text:">
<input type="text" ng-model="page.textColor" size="5" maxlength="7" placeholder="e.g. #000" required />
<input ng-label-target type="color" ng-model="page.textColor" required />
</ng-label>
这本身就很有魅力。
然而,现在我想自动生成几个输入,并使标签指向第一个。问题是,当我在ng-label
中执行ng-repeat
时,在处理指令后会生成ng-repeat
代码,所以实际上什么都找不到。
因此,我的问题是:是否有一种方法可以指定为angular来内外评估嵌套指令,而不是相反?
或者,有没有比我现在做的更好的方法?
我做了一把小提琴来举例说明评估东西的顺序。你可以看到外部指令的值比它的内容小或相等(不能低于微秒,所以我不得不重复一堆):
http://jsfiddle.net/YLM9P/
从角度文档:
优先级当在单个DOM元素上定义了多个指令时,有时需要指定应用指令的顺序。优先级用于在调用指令的编译函数之前对指令进行排序。优先级定义为一个数字。具有更高数字优先级的指令将首先编译。链接前功能也按优先级顺序运行,但链接后功能按相反顺序运行。具有相同优先级的指令的顺序未定义。默认优先级为0。
终端如果设置为true,则当前优先级将是将执行的最后一组指令(当前优先级的任何指令仍将执行,因为相同优先级的执行顺序未定义)。
因此,对于您的问题,我相信将终端属性设置为true将解决您的问题。
app.directive('ngLabel', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
....
....
terminal: true
});
这个问题和Angular中的许多其他问题一样,可以通过创建一个附加指令来解决:
app.directive('myLabelTarget', function() {
return {
require: '^myLabel',
link: function(scope, element, attrs, myLabelCtrl) {
myLabelCtrl.doIfFirst(function(id) {
attrs.$set('id', id);
});
}
};
});
使用require
属性,您可以访问DOM中更高级别的myLabel指令的控制器。
有关工作示例,请参阅此plnkr。
我认为,通过在父元素上添加一个函数表达式(可能传递一个参数),然后从ng repeat中的子元素调用该函数,可以极大地简化代码并消除querySelectorAll(不是非常的Angular风格)。该函数只需设置一个你将要使用的值,一旦设置好,你就知道你有了第一个值,其余的应该被忽略。如果您展示了ng重复输入字段的最终HTML应该是什么样子,我可以更具体一点。
您可以尝试注册一个MutationObserver,它监听添加到DOM中的元素。但这可能会给你的问题带来一点开销——你自己决定;)
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// you get notified about added DOM elements here
// check mutation.type if it was an insertion
// then you handle the first node specifically.
console.log(mutation.target.nodeName, mutation.type, mutation);
});
});
var config = {childList: true, attributes: false, characterData: false, subtree: false, attributeOldValue: false, characterDataOldValue: false};
observer.observe(element[0], config);
演示http://plnkr.co/h6kTtq文档https://developer.mozilla.org/en/docs/Web/API/MutationObserver浏览器支持http://caniuse.com/mutationobserver