我正在通过指令创建一个可重用的html位。 html会有一些我希望从原始范围传递的变量。通过在指令上声明属性,然后创建隔离范围并捕获它们,可以轻松完成此操作。问题是,对于大量变量,有更好的方法吗?我曾想过传递像{firstAttr: $scope.one, secondAttr: $scope.two...}
这样的物体并将这个物体分开以获得每件物品。这是第一次工作,但双向数据绑定不起作用(即使使用'=')。
问题在于绑定的是对象,而不是对象的每个部分。我可以使用指令中的compile函数将每个属性添加到元素中吗?这样:
<mydirective databinding="{one:'first one', two:'second one'}">
将被翻译成:
<mydirective one="first one" two="second one">
通过捕获指令中的属性,我的数据绑定将按预期工作。我将如何完成该设计,还是完全有另一种方法来完成这项工作?
答案 0 :(得分:15)
数据绑定指令的想法是一个有趣的,但它不是我会这样做的,因为我相信你会遇到指令优先级问题,加上它非常非标准并且会使你的代码难以理解未来的程序员。有几种方法可以做到这一点,所以我将讨论我用过的3种不同的解决方案。
解决方案1
如果您只需要单向数据绑定,最简单的解决方案是使用angular的范围。使用{{}}在其上插入任何简单范围变量后,对指令内对象的字符串表示形式使用$ eval函数。字符串表示甚至不必是有效的JSON,因为在下面的示例中您将注意到我没有在对象键周围包含引号。
在视图中:
<div databinding="{one:'first', two:{{scopeVar}}, complex:[1,2, "Hi"]}"></div>
在javascript中:
app.directive('databinding', function () {
return{
link: function (scope, elm, attrs) {
console.debug(scope.$eval(attrs['databinding']));
}
}
});
解决方案2
另一种单向数据绑定解决方案是在控制器内创建一个选项对象,并使用“@”(甚至“=”)将其传递给指令:
在控制器中:
$scope.options = {one: "first, two: "second"};
在视图中:
<div databinding="options"></div>
在javascript中:
app.directive('databinding', function () {
return{
scope: {
options: "@" //Can also use = here
},
link: function (scope, elm, attrs) {
console.log(scope.options);
}
}
});
解决方案3
如果你确实需要双向数据绑定,那么你大部分都不走运,因为没有优雅的方法可以做到这一点。但是,如果您是市场上的hackish解决方案,您可以使用与解决方案2非常相似的方法完成双向数据绑定,但是可以更改选项对象。
不是声明包含简单原始数据类型(如字符串)的选项对象,而是在选项对象中创建一个虚拟对象,然后在其中声明变量。这样做,控制器中范围变量的更改也将在指令内实现,如超时所示。
控制器:
$scope.someScopeVar = "Declared in controller"
$scope.options = {
dummy: {
one: $scope.someScopeVar,
two: "second"
}
}
window.setTimeout(function(){
$scope.someScopeVar = "Changed in controller";
}, 2000)
查看:
<div databinding="options"></div>
指令:
app.directive('databinding', function () {
return{
scope: {
options: "=" //You need to use = with this solution
},
link: function (scope, elm, attrs) {
console.log(scope.options.dummy.one); //Outputs "Declared in controller"
window.setTimeout(function(){
console.log(scope.options.dummy.one) //Outputs "Changed in controller"
}, 5000)
}
}
});
此方法有效,因为javascript通过引用传递对象,而基元被复制。通过在对象中嵌套对象,可以保留数据绑定。
答案 1 :(得分:1)
您可以在指令中更改范围,如下所示
.('mydirective ', function(){
var linker = function(scope, element){
console.log(scope.one, scope.two);
}
return {
link: linker,
scope: {one:"=", two:"="}
}
});
答案 2 :(得分:0)
问题是,对于大量变量,有更好的方法吗?
我不这么认为。正如您已经发现的那样,尝试将它们作为一个对象传递会导致对象被数据绑定,而不是单个部分。
即使你可以使用$ compile工作,对其他人来说,阅读代码的内容也不会很明显。
另一种选择是要么不创建范围(scope: false
,这是指令的默认值),要么创建一个新的子范围(scope: true
),但要求调用范围必须使用某些范围范围属性名称以使用该指令。然后您不必指定任何属性。这使得指令的使用更具限制性,但我认为这是您的两个选择:指定多个属性,或者需要某些范围属性名称。