Angular 属性表达式未在内部指令中求值
Angular attribute expression not evaluating inside directive
为什么 link 使用 link 属性计算指令内的表达式,而模板却没有?请注意,我在这里使用 'link' 只是为了 console.log 说明目的。
我的最终目标是通过其属性将数据传递到指令中,并将该数据作为其模板呈现。
index.html
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js@*" data-semver="1.3.7" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<my-directive text="{{data}}" />
</div>
</body>
</html>
app.js
angular.module("myApp", []).directive("myDirective", function () {
return {
restrict: "E",
scope: {
text: "@text",
},
link: function(scope, element, attrs){
console.log(attrs.text);
},
template: function(element, attrs){
console.log(attrs.text);
}
};
}).controller('myCtrl',function($scope){
$scope.data = 'test';
});
输出:
{{data}}
test
从指令访问控制器作用域的一种方法是使
scope: false
详细了解指令 here
HTH
所以我相信您混淆了您在这里处理的两个范围。通过使用像你在这里这样的隔离范围,你正在复制 text
属性的 插值 (在遇到指令时针对范围进行评估(控制器范围在您的示例中))到名为 'text' 的隔离范围上的 属性。因此,在您的指令模板中,您应该参考 text
来访问该值(在您的情况下为 "test")。
但是,根据您的评论,您确实希望能够传递要显示的指令的标记,就好像它是针对控制器范围的 运行 一样。这就是 transclusion 的用途——被嵌入的内容将被放置在指令模板中指定的位置,并根据控制器的范围进行评估,因此 {{data}}
将正确解析为 test
.
在这种情况下,您的标记将变为:
<my-directive>{{data}}</my-directive>
你的 JS 变成:
angular.module("myApp", []).directive("myDirective", function() {
return {
restrict: "E",
scope: {
// no need for scope bindings here
},
transclude: true,
link: function(scope, element, attrs) {
// nothing to do here for now
},
template: '<div ng-transclude></div>',
};
}).controller('myCtrl', function($scope) {
$scope.data = 'test';
});
我推荐 GregL 的答案,但为了完整起见:
从本质上讲,template
代码必须在 运行 之前得到 angular 编译你的代码(显然,因为模板是告诉 angular 它应该编译什么)。这就是结果与您在 link
函数中看到的结果不同的原因,后者发生在 编译之后。
如果您绝对必须执行手动插值,您可以使用 angular 提供的 $interpolate
服务。
为什么 link 使用 link 属性计算指令内的表达式,而模板却没有?请注意,我在这里使用 'link' 只是为了 console.log 说明目的。
我的最终目标是通过其属性将数据传递到指令中,并将该数据作为其模板呈现。
index.html
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js@*" data-semver="1.3.7" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<my-directive text="{{data}}" />
</div>
</body>
</html>
app.js
angular.module("myApp", []).directive("myDirective", function () {
return {
restrict: "E",
scope: {
text: "@text",
},
link: function(scope, element, attrs){
console.log(attrs.text);
},
template: function(element, attrs){
console.log(attrs.text);
}
};
}).controller('myCtrl',function($scope){
$scope.data = 'test';
});
输出:
{{data}}
test
从指令访问控制器作用域的一种方法是使
scope: false
详细了解指令 here
HTH
所以我相信您混淆了您在这里处理的两个范围。通过使用像你在这里这样的隔离范围,你正在复制 text
属性的 插值 (在遇到指令时针对范围进行评估(控制器范围在您的示例中))到名为 'text' 的隔离范围上的 属性。因此,在您的指令模板中,您应该参考 text
来访问该值(在您的情况下为 "test")。
但是,根据您的评论,您确实希望能够传递要显示的指令的标记,就好像它是针对控制器范围的 运行 一样。这就是 transclusion 的用途——被嵌入的内容将被放置在指令模板中指定的位置,并根据控制器的范围进行评估,因此 {{data}}
将正确解析为 test
.
在这种情况下,您的标记将变为:
<my-directive>{{data}}</my-directive>
你的 JS 变成:
angular.module("myApp", []).directive("myDirective", function() {
return {
restrict: "E",
scope: {
// no need for scope bindings here
},
transclude: true,
link: function(scope, element, attrs) {
// nothing to do here for now
},
template: '<div ng-transclude></div>',
};
}).controller('myCtrl', function($scope) {
$scope.data = 'test';
});
我推荐 GregL 的答案,但为了完整起见:
从本质上讲,template
代码必须在 运行 之前得到 angular 编译你的代码(显然,因为模板是告诉 angular 它应该编译什么)。这就是结果与您在 link
函数中看到的结果不同的原因,后者发生在 编译之后。
如果您绝对必须执行手动插值,您可以使用 angular 提供的 $interpolate
服务。