我有一个指令,正在抄袭它的内容。并且在被抄送的内容中是一个指令,它需要transcluding指令的控制器。如果我在transcluding指令中创建了一个transclude函数,则会引发错误。我认为这是因为当你提供一个transclude函数(https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L846)时,被克服的内容会被克隆。
我还有一个描述我问题的傻瓜:http://plnkr.co/edit/rRKWW6zfjZuUiw1BY4zs?p=preview
我想要做的是我想要转换内容并解析所有被转换的内容,然后将它放在DOM中的正确位置并自己编译。被抄送的内容实际上是我的指令的配置。
我还尝试清空我在转录函数中收到的克隆数组,因为我实际上并不需要自动转换内容。我只需要解析它并在稍后的时间点手动转换它。 Angular不需要对我的被抄送的内容做任何事情。但是这不起作用,因为在调用transcluding函数时已经识别出指令。所以当我清空数组时,我在这里收到错误(https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L961)。
亲切的问候,大安
答案 0 :(得分:9)
当您使用require: "^controller"
时,您告诉Angular该指令要求在运行链接函数时将controller
附加到祖先DOM元素。
当您在不使用ngTransclude指令的情况下进行转换时,您的父指令链接函数会传递一个transclude方法。 (你已经知道了;这只是为了完整性。)这个transclude方法执行以下操作:
cloneAttachFn
,请克隆内容并调用cloneAttachFn $compile()
来编译和链接内容(或克隆的内容)(默认为从指令作用域的$ parent继承的新作用域)。如果您调用transclude,并且最终没有将内容附加为具有所需控制器的元素的后代(或者根本不将内容添加到DOM),则内容将没有父级所需的控制器。因为它无法找到所需的控制器,所以会出错。
在您的示例中,如果将kmBar与require: "^kmFoo"
一起使用,则限制将已转换的内容添加到DOM节点,这些节点是具有kmFoo的节点的后代。
最简单的解决方法是继续将其附加到kmFoo的元素以用于$ compile()和链接,但立即detach。
Detach(与remove相对)维护点击处理程序等,因此如果稍后追加该元素,一切都将继续有效。如果您使用的是AngularJS的早期版本,则可能需要包含jQuery以进行分离,因为它不包含在早期版本的jqLite中。
这是我放在一起的Plunk的片段
app.directive('kmFoo', function() {
return {
restrict: 'A',
scope: true,
template: '<div></div>',
transclude: true,
controller: function() {
// ...
},
link: function(scope, $element, attrs, ctrl, transcludeFn) {
console.log('linking foo');
// We are going to temporarily add it to $element so it can be linked,
// but after it's linked, we detach it.
transcludeFn(scope, function(clone) {
console.log('transcluding foo');
$element.append(clone);
c = clone;
}).detach();// <- Immediately detach it
}
};
});
app.directive('kmBar', function() {
return {
restrict: 'A',
scope: true,
require: '^kmFoo',
link: function(scope, $element, attrs, fooCtrl) {
console.log('linking bar');
// Right now it's a child of the element containing kmFoo,
// but it won't be after this method is complete.
// You can defer adding this element to the DOM
// for as long as you want, and you can put it wherever you want.
}
};
});
答案 1 :(得分:0)
首先,为什么需要转换功能?这还不够吗?
app.directive('kmFoo', function() {
return {
'restrict': 'A',
'scope': true,
'controller': function() {
this.tryMe = function() { console.log("Success!") };
},
'link': function(scope, element, attrs, ctrl) {
console.log('linking foo');
var innerHtml = element.html();
// do something with innerHtml
element.html("<div>Empty</div>");
}
};
});
app.directive('kmBar', function() {
return {
'restrict': 'A',
'scope': true,
'require': '^kmFoo',
'link': function(scope, element, attrs, fooCtrl) {
fooCtrl.tryMe();
}
};
});
但是如果你真的想要访问fooController并在kmFoo中有一个transclude函数,你可以在完成所有链接并初始化所有控制器之后通过element.controller()
访问控制器。
app.directive('kmFoo', function() {
return {
'restrict': 'A',
'scope': true,
'template': '<div ng-transclude></div>',
'transclude': true,
'controller': function() {
this.tryMe = function() { console.log("Success!") };
},
'link': function(scope, $element, attrs, ctrl, transcludeFn) {
console.log('linking foo');
// when you put the transclude function in comments it won't throw an error
transcludeFn(scope, function(clone) {
console.log('transcluding foo');
});
}
};
});
app.directive('kmBar', function() {
return {
'restrict': 'A',
'scope': true,
'template': "<button ng-click='tryMe()'>Feeling lucky?</button>",
'link': function(scope, element, attrs) {
scope.getFooCtrl = function() {
return element.parent().controller('kmFoo');
};
console.log('linking bar');
console.log('parent not yet known: ' + element.parent().toString());
},
'controller': function($scope) {
$scope.tryMe = function() {
$scope.getFooCtrl().tryMe();
};
}
};
});
使用this plnkr查看此内容。
答案 2 :(得分:0)
要在不将其显示在DOM中的情况下执行此操作,您可以使用
transclude: 'element'
第二条指令。
这样可以避免使用一些技巧来获取所需的信息。
app.directive('kmFoo', function() {
return {
'restrict': 'A',
'scope': true,
'template': '<div ng-transclude></div>',
'transclude': true,
'controller': function() {
},
'link': function(scope, $element, attrs, ctrl, transcludeFn) {
console.log('linking foo');
// when you put the transclude function in comments it won't throw an error
//transcludeFn(scope, function(clone) {
// console.log('transcluding foo');
//});
}
};
});
app.directive('kmBar', function() {
return {
'restrict': 'A',
'scope': {},
'require': '^kmFoo',
'link': function(scope, $element, attrs, fooCtrl) {
console.log('linking bar');
}
};
});
app.directive('kmBarWithElement', function() {
return {
'restrict': 'A',
'scope': {},
'transclude': 'element',
'require': '^kmFoo',
'link': function(scope, $element, attrs, fooCtrl, transclude) {
transclude(function(clone) {
console.log('here the element: ', clone);
});
}
};
});
以下是一个工作示例:http://plnkr.co/edit/lbT7oz74Yz7IZvEKp77T?p=preview