AngularJS:无法将属性从第一个指令插入到第二个指令。 (w/ plunker 示例)
AngularJS: Cannot interpolate attribute from first directive to a second. (w/ plunker example)
参考
参考插件:http://plnkr.co/edit/otv5mVVQ36iPi3Mp0FYw?p=preview
问题说明
假设我们有两个指令,first-directive
和 second-directive
。现在假设我们只能访问 first-directive
,我们希望用它包装 second-directive
并将我们自己的操作属性传递给它。
app.directive('firstDirective', function() {
return {
scope: true,
priority: 1000,
transclude: true,
template: function(element,attributes){
console.log('template')
return '<second-directive two="{{one}}"></second-directive>'
},
compile: function(element,attributes) {
console.log('compile')
return {
pre: function(scope){
scope.one = 'foo'
console.log('cpre')
},
post: function(scope){
scope.one = 'foo'
console.log('cpost')
},
}
},
controller: ['$scope','$attrs',function($scope,$attrs){
console.log('controller');
$scope.one = 'foo';
}],
}
})
app.directive('secondDirective',function(){
return {
template: function (element,attributes){
console.log(attributes.two) //{{one}} not 'foo' or 'test'
return 'Hello {{two}}'
}
}
});
first-directive
被调用如下:
<first-directive one='test'></first-directive>
console.log输出如下:
template
compile
{{one}}
controller
cpre
cpost
所以从这里我了解到模板在编译之前被调用。这是我新手眼中的一个奇特之处,因为无论如何都无法通过编译、控制器、预或 post link!
来操纵模板函数传回的值
问题是这样的:
如何使用我想要的动态属性值调用 second-directive
?请记住 second-directive
是完全独立的,我们不能在那里添加代码。
PS -
我有一个可能的想法是调用第二指令如下:
template: function(element,attributes){
console.log('template')
var explicit = ???? /* how to access scope? */
return '<second-directive two="'+ explicit +'"></second-directive>'
},
或者
template: function(element,attributes){
console.log('template')
return $interpolate('<second-directive two="{{one}}"></second-directive>')(scopeObj) /* how does one access scopeObj with current scope values here? */
},
然而,我再次不确定如何在调用任何其他函数之前获取传递给第一指令的值。控制器可以访问 $scope,它被称为 AFTER template。
非常感谢您的建议。
第二个指令是你写的吗?
<second-directive two="'+ explicit +'"></second-directive>
要使上述代码正常工作,您需要在第二个指令中设置隔离范围对象,请查看下面的插件。
我正在使用你的问题来学习,但我找到了这个,它可能对你有用:
app.directive("tryThis", function($compile){
return{
scope: {
one: '@',
},
link: function(scope, element){
var template = '<second-directive two="'+scope.one+'"></second-directive>';
var linkFn = $compile(template);
var content = linkFn(scope);
element.append(content);
}
}
});
Plunkr 是 here,请注意 test
现在已登录到控制台,而不是 {{one}}
。如果给 secondDirective 一个独立的作用域,test
将显示在屏幕上。
这个 link 还帮助我从概念上理解了您面临的问题,为 'no scope during compile' 步骤的问题提供了一些背景信息 - 我不确定是否有解决此问题的方法。
好吧,如果您只想将数据从第一个指令传递到第二个指令模板,那么您可以使用
在第一个指令控制器中添加动态属性
this.fromFirstDir = "you can pass from here"
第一个指令控制器:
controller: ['$scope','$attrs',function($scope,$attrs){
console.log('controller');
$scope.one = 'foo';
this.fromFirstDir = "you can pass from here"
}],
}
然后在第一个指令控制器的secondDirective中使用require属性,你可以从link访问这个动态属性使用传递给 link 函数的控制器的 secondDirective 指令的函数。最后将这些属性分配给传递给 link 函数的局部范围。
app.directive('secondDirective',function(){
return {
scope: {twoData : '@twoData'},
require : '^firstDirective',
template: function (element,attributes){
console.log(attributes.two) //{{one}} not 'foo' or 'test'
return 'Hello <b>{{fromFirstDir}}</b>'
},
link : function(scope,element,attr,firstDirCtrl){
console.log("===",firstDirCtrl.fromFirstDir)
scope.fromFirstDir = firstDirCtrl.fromFirstDir;
}
}
});
这样,您的第二个指令就可以使用那些动态属性了。
这是最后的fiddle。
希望对您有所帮助。
您不能(不能)访问模板内的范围(因为此时没有范围)。该模板用于创建一个或多个元素,然后将它们链接到一个范围(在实例化它们的控制器之后 - 如果有的话)。
在指令之间传递值的方法有很多种,每一种都最适合特定用途。最简单的(但不一定是最好的,具体取决于您的用例详细信息)是在包装器指令的范围内分配一个值,并让内部指令从范围内读取它:
<!-- HTML -->
<one for-two="{{test}}"></one>
// JS
angular.
module('myApp', []).
directive('one', oneDirective).
directive('two', twoDirective);
function oneDirective() {
return {
restrict: 'E',
scope: true,
link: function onePostLink(scope, elem, attrs) {
scope.two = attrs.forTwo;
},
template: '<two></two>'
};
}
function twoDirective() {
return {
restrict: 'E',
template: 'Hello, {{two}} !'
};
}
您有 transclude: true
但没有在模板中使用它。你不能只使用这个标记并让第一个指令使用的模板 <ng-transclude>
吗?您有 scope: true
,因此您可以从 parent/controller 操作 属性,更改将传播到两个指令。
标记
<first-directive one="test">
<second-directive two="test"></second-directive>
</first-directive>
第一指令模板
template: `<div>
my first directive content
<ng-transclude></ng-transclude>
</div>`;
参考
参考插件:http://plnkr.co/edit/otv5mVVQ36iPi3Mp0FYw?p=preview
问题说明
假设我们有两个指令,first-directive
和 second-directive
。现在假设我们只能访问 first-directive
,我们希望用它包装 second-directive
并将我们自己的操作属性传递给它。
app.directive('firstDirective', function() {
return {
scope: true,
priority: 1000,
transclude: true,
template: function(element,attributes){
console.log('template')
return '<second-directive two="{{one}}"></second-directive>'
},
compile: function(element,attributes) {
console.log('compile')
return {
pre: function(scope){
scope.one = 'foo'
console.log('cpre')
},
post: function(scope){
scope.one = 'foo'
console.log('cpost')
},
}
},
controller: ['$scope','$attrs',function($scope,$attrs){
console.log('controller');
$scope.one = 'foo';
}],
}
})
app.directive('secondDirective',function(){
return {
template: function (element,attributes){
console.log(attributes.two) //{{one}} not 'foo' or 'test'
return 'Hello {{two}}'
}
}
});
first-directive
被调用如下:
<first-directive one='test'></first-directive>
console.log输出如下:
template
compile
{{one}}
controller
cpre
cpost
所以从这里我了解到模板在编译之前被调用。这是我新手眼中的一个奇特之处,因为无论如何都无法通过编译、控制器、预或 post link!
来操纵模板函数传回的值问题是这样的:
如何使用我想要的动态属性值调用 second-directive
?请记住 second-directive
是完全独立的,我们不能在那里添加代码。
PS - 我有一个可能的想法是调用第二指令如下:
template: function(element,attributes){
console.log('template')
var explicit = ???? /* how to access scope? */
return '<second-directive two="'+ explicit +'"></second-directive>'
},
或者
template: function(element,attributes){
console.log('template')
return $interpolate('<second-directive two="{{one}}"></second-directive>')(scopeObj) /* how does one access scopeObj with current scope values here? */
},
然而,我再次不确定如何在调用任何其他函数之前获取传递给第一指令的值。控制器可以访问 $scope,它被称为 AFTER template。
非常感谢您的建议。
第二个指令是你写的吗?
<second-directive two="'+ explicit +'"></second-directive>
要使上述代码正常工作,您需要在第二个指令中设置隔离范围对象,请查看下面的插件。
我正在使用你的问题来学习,但我找到了这个,它可能对你有用:
app.directive("tryThis", function($compile){
return{
scope: {
one: '@',
},
link: function(scope, element){
var template = '<second-directive two="'+scope.one+'"></second-directive>';
var linkFn = $compile(template);
var content = linkFn(scope);
element.append(content);
}
}
});
Plunkr 是 here,请注意 test
现在已登录到控制台,而不是 {{one}}
。如果给 secondDirective 一个独立的作用域,test
将显示在屏幕上。
这个 link 还帮助我从概念上理解了您面临的问题,为 'no scope during compile' 步骤的问题提供了一些背景信息 - 我不确定是否有解决此问题的方法。
好吧,如果您只想将数据从第一个指令传递到第二个指令模板,那么您可以使用
在第一个指令控制器中添加动态属性
this.fromFirstDir = "you can pass from here"
第一个指令控制器:
controller: ['$scope','$attrs',function($scope,$attrs){
console.log('controller');
$scope.one = 'foo';
this.fromFirstDir = "you can pass from here"
}],
}
然后在第一个指令控制器的secondDirective中使用require属性,你可以从link访问这个动态属性使用传递给 link 函数的控制器的 secondDirective 指令的函数。最后将这些属性分配给传递给 link 函数的局部范围。
app.directive('secondDirective',function(){
return {
scope: {twoData : '@twoData'},
require : '^firstDirective',
template: function (element,attributes){
console.log(attributes.two) //{{one}} not 'foo' or 'test'
return 'Hello <b>{{fromFirstDir}}</b>'
},
link : function(scope,element,attr,firstDirCtrl){
console.log("===",firstDirCtrl.fromFirstDir)
scope.fromFirstDir = firstDirCtrl.fromFirstDir;
}
}
});
这样,您的第二个指令就可以使用那些动态属性了。
这是最后的fiddle。
希望对您有所帮助。
您不能(不能)访问模板内的范围(因为此时没有范围)。该模板用于创建一个或多个元素,然后将它们链接到一个范围(在实例化它们的控制器之后 - 如果有的话)。
在指令之间传递值的方法有很多种,每一种都最适合特定用途。最简单的(但不一定是最好的,具体取决于您的用例详细信息)是在包装器指令的范围内分配一个值,并让内部指令从范围内读取它:
<!-- HTML -->
<one for-two="{{test}}"></one>
// JS
angular.
module('myApp', []).
directive('one', oneDirective).
directive('two', twoDirective);
function oneDirective() {
return {
restrict: 'E',
scope: true,
link: function onePostLink(scope, elem, attrs) {
scope.two = attrs.forTwo;
},
template: '<two></two>'
};
}
function twoDirective() {
return {
restrict: 'E',
template: 'Hello, {{two}} !'
};
}
您有 transclude: true
但没有在模板中使用它。你不能只使用这个标记并让第一个指令使用的模板 <ng-transclude>
吗?您有 scope: true
,因此您可以从 parent/controller 操作 属性,更改将传播到两个指令。
标记
<first-directive one="test">
<second-directive two="test"></second-directive>
</first-directive>
第一指令模板
template: `<div>
my first directive content
<ng-transclude></ng-transclude>
</div>`;