为什么我不能像这样覆盖变量的值?
Why can't I overwrite the value of a variable like this?
我想弄清楚为什么我无法覆盖通过隔离范围 (@
) 传递给 angularJS 指令的值。我尝试用以下内容覆盖 vm.index
的值:
vm.index = parseInt(vm.index, 10)
但是,由于某些原因,它不起作用。
如果我把它改成:
vm.newIndex = parseInt(vm.index, 10)
有效。此外,在 $scope
上分配值也有效。
为什么第一种方法不起作用?
我创建了这个 example plunker 以供参考。
显然它与范围 index
值的单向绑定有关。所以 Angular 不会更新 scope.index
(或 this.index
,如果是 bindToController: true
),因为范围配置为
scope: {
index: '@'
},
如果将其更改为双向绑定,例如:
scope: {
index: '='
},
它将起作用:
<some-directive index="$index"></some-directive>
演示: http://plnkr.co/edit/kq16cpk7gyw8IE7HiaQL?p=preview
UPD。 @pankajparkar 提出了一个很好的观点,即在下一个摘要中更新值解决了这个问题。这种解决问题的方法比我在这个答案中所做的更接近。
正如您在此处使用的 @
一样,它需要来自具有 {{}}
插值指令的属性的值。似乎指令首先被加载,然后 vm.index
值被评估。因此,更改不会发生在当前的摘要周期中。如果你想让那些被反映出来,你需要 运行 使用 $timeout 以更安全的方式消化循环。
$timeout(function(){
vm.index = parseInt(vm.index, 10)
})
以上是确保将值转换为十进制值。添加将发生在指令 html <h2>Item {{ vm.index + 1 }}</h2>
上
这背后的可能原因
根据@dsfq 和我的讨论,我们经历了 angular $compile
API, & found that their is one method call initializeDirectiveBindings
,只有当我们在具有隔离范围的指令中使用 controllerAs
时才会调用它。在这个函数中有各种绑定 @
,=
和 &
的切换案例,所以当你使用 @
时,这意味着调用切换案例代码后的一种绑定方式.
代码
case '@':
if (!optional && !hasOwnProperty.call(attrs, attrName)) {
destination[scopeName] = attrs[attrName] = void 0;
}
attrs.$observe(attrName, function(value) {
if (isString(value)) {
destination[scopeName] = value;
}
});
attrs.$$observers[attrName].$$scope = scope;
if (isString(attrs[attrName])) {
// If the attribute has been provided then we trigger an interpolation to ensure
// the value is there for use in the link fn
destination[scopeName] = $interpolate(attrs[attrName])(scope);
}
break;
在上面的代码中,您可以清楚地看到他们放置了 attrs.$observe
,这是一种观察者,通常在值带有插值时使用,就像在我们的例子中一样 {{index}}
,这意味着这个 $observe
在摘要循环 运行 时得到评估,这就是为什么你需要在 index
值作为 decimal
.[=33= 时放置 $timeout
]
@dsfq 的回答之所以有效,是因为他使用 =
提供了两种绑定方式,代码不会让观察者直接从隔离范围 here is the code 中获取值。因此,如果没有摘要循环,该值就会更新。
我想弄清楚为什么我无法覆盖通过隔离范围 (@
) 传递给 angularJS 指令的值。我尝试用以下内容覆盖 vm.index
的值:
vm.index = parseInt(vm.index, 10)
但是,由于某些原因,它不起作用。
如果我把它改成:
vm.newIndex = parseInt(vm.index, 10)
有效。此外,在 $scope
上分配值也有效。
为什么第一种方法不起作用?
我创建了这个 example plunker 以供参考。
显然它与范围 index
值的单向绑定有关。所以 Angular 不会更新 scope.index
(或 this.index
,如果是 bindToController: true
),因为范围配置为
scope: {
index: '@'
},
如果将其更改为双向绑定,例如:
scope: {
index: '='
},
它将起作用:
<some-directive index="$index"></some-directive>
演示: http://plnkr.co/edit/kq16cpk7gyw8IE7HiaQL?p=preview
UPD。 @pankajparkar 提出了一个很好的观点,即在下一个摘要中更新值解决了这个问题。这种解决问题的方法比我在这个答案中所做的更接近。
正如您在此处使用的 @
一样,它需要来自具有 {{}}
插值指令的属性的值。似乎指令首先被加载,然后 vm.index
值被评估。因此,更改不会发生在当前的摘要周期中。如果你想让那些被反映出来,你需要 运行 使用 $timeout 以更安全的方式消化循环。
$timeout(function(){
vm.index = parseInt(vm.index, 10)
})
以上是确保将值转换为十进制值。添加将发生在指令 html <h2>Item {{ vm.index + 1 }}</h2>
这背后的可能原因
根据@dsfq 和我的讨论,我们经历了 angular $compile
API, & found that their is one method call initializeDirectiveBindings
,只有当我们在具有隔离范围的指令中使用 controllerAs
时才会调用它。在这个函数中有各种绑定 @
,=
和 &
的切换案例,所以当你使用 @
时,这意味着调用切换案例代码后的一种绑定方式.
代码
case '@':
if (!optional && !hasOwnProperty.call(attrs, attrName)) {
destination[scopeName] = attrs[attrName] = void 0;
}
attrs.$observe(attrName, function(value) {
if (isString(value)) {
destination[scopeName] = value;
}
});
attrs.$$observers[attrName].$$scope = scope;
if (isString(attrs[attrName])) {
// If the attribute has been provided then we trigger an interpolation to ensure
// the value is there for use in the link fn
destination[scopeName] = $interpolate(attrs[attrName])(scope);
}
break;
在上面的代码中,您可以清楚地看到他们放置了 attrs.$observe
,这是一种观察者,通常在值带有插值时使用,就像在我们的例子中一样 {{index}}
,这意味着这个 $observe
在摘要循环 运行 时得到评估,这就是为什么你需要在 index
值作为 decimal
.[=33= 时放置 $timeout
]
@dsfq 的回答之所以有效,是因为他使用 =
提供了两种绑定方式,代码不会让观察者直接从隔离范围 here is the code 中获取值。因此,如果没有摘要循环,该值就会更新。