我有2个指令,一个负责主元素<swapview>
,另一个负责其子元素<view>
。
但是,在加载子模板时,var views = $('view', elem);
已经执行,并在DOM中找到0 <view>
个元素。
我对这个问题缺乏经验,任何想法都会非常有用
HTML:
<swapview>
<view ng-repeat="view in views" templateurl="{{::view.template}}"></view>
</swapview>
JS
App.directive('view', function () {
return {
scope:{
templateurl: '@'
},
controller: function($scope) {
$scope.getTemplateUrl = function () {
return $scope.templateurl;
};
},
template: '<ng-include src="getTemplateUrl()"/>'
};
});
App.directive('swapview', ['$swipe',function ($swipe) {
//....
return {
link: function (scope, elem, attrs) {
var views = $('view', elem);
var count = views.length;
//......
},
require: 'view'
};
}]);
var ctrls = ang.module('controllers',[]);
ctrls.controller('myController', ['$scope', function ($scope) {
$scope.views = [
{template:'templates/viewI.html'},
{template:'templates/viewII.html'},
{template:'templates/viewIII.html'},
{template:'templates/viewIV.html'}
];
}]);
感谢您的帮助
答案 0 :(得分:3)
依赖于link
阶段期间存在的子DOM元素是一种非常脆弱的方法。
当元素已存在时,它会起作用:
<swapview>
<view templateUrl="view1.html"></view>
<view templateUrl="view2.html"></view>
</swapview>
如果您有ng-if
或ng-repeat
, 将无法正常工作,因为这两个指令会自行转换并仅评估是否自我渲染&#34;稍后&# 34;,所以在link
中你会看到一个占位符注释(即使`ng-if =&#34; true&#34;)代替:
<swapview>
<view ng-if="true" templateUrl="view1.html">
</swapview>
你可以以(hackish)$timeout
方法克服这个问题 - 它不会导致竞争条件 - 不是什么是黑客 - 并且实际上每次都会工作(即使有0个延迟),因为$timeout
将执行放在摘要周期的末尾:
console.log(element.find("view").length); // will output 0
$timeout(function(){
console.log(element.find("view").length); // will output 1
});
不过,这不是一个好的解决方案。如果指令的用户决定动态加载内容,例如使用ng-include
,则会中断。因此,如果需要下载模板,则即使使用$timeout
,以下也无效:
<swapview>
<div ng-include="'templateForViews.html`"></div>
<swapview>
那么,什么有效?
处理预期的子指令的正确方法是让子指令向父控制器注册require: "^parent"
的控制器:
.directive("swapview", function($timeout){
return {
controller: function(){
var childViewCtrls = [];
this.registerView = function(view, viewEl){
childViewCtrls.push({ctrl: view, elem: viewEl});
};
},
link: function(scope, element){
//
}
};
})
.directive("view", function($timeout){
return {
require: ["view", "^swapview"],
controller: function(){
// useful to expose an API
},
link: function(scope, element, attrs, ctrls){
var me = ctrls[0],
swapview = ctrls[1];
swapview.registerView(me, element);
}
};
});