为什么 Angular 1.5 双向绑定在将作用域变量传递给组件绑定时会失败?
Why does Angular 1.5 two way binding fail when passing a scope variable to component binding?
因此,我们正在将我们的 Angular 1.3 scope soup 应用程序提升到 1.5 标准。但是我们注意到了一些奇怪的行为。当我们将 $scope 变量传递到组件绑定时,它似乎没有正确反映组件内对 $scope 变量所做的任何更改。
我们基于 $scope 的控制器:
app.controller('ParentCtrl', function ($scope) {
$scope.dates = [...array of dates...]
$scope.focusDate = new Date()
})
我们的组件标签:
<section-dates dates="dates" focus-date="focusDate"></section-dates>
组件本身:
app.component("sectionDates", {
bindings: {
dates: "=",
focusDate: "="
},
controller: function () {
this.onClickADate = function (date)
{
this.focusDate=date
}
...
}
单击新日期时,组件中的 focusDate 会发生变化,但父控制器的 $scope 不会发生变化。这是为什么?
我们正在经历类似的事情。
一个让我们花了一些时间思考的重要概念是所有组件都有 isolate $scope。所以理论上这可以防止你提到的“$scope soup”问题,但实际上这导致需要显式地将数据传入和传出组件,这可能需要一些时间来适应。
通常,您会希望保持数据不可变,即防止子组件直接更改数据(在某些特定情况下双向数据绑定改进 UI)。
这里的想法是像这样使用单向数据绑定将数据传递到组件中:
...
bindings: {
oneWayBindingInput: '<'
},
...
然后将事件从子组件传回,然后由父组件处理:
...
bindings: {
oneWayBindingInput: '<'
onEventOutput: '&'
},
...
所以在你的情况下,你可以尝试这样的事情:
组件标签(在父模板中):
<section-dates dates="dates" on-update="handleUpdateEvent($event)"></section-dates>
组件:
app.component("sectionDates", {
bindings: {
dates: "<",
onUpdate: "&"
},
controller: function () {
this.onClickADate = function (date)
{
this.onUpdate({$event: {date: date});
}
...
}
父控制器:
app.controller('ParentCtrl', function ($scope) {
$scope.dates = [...array of dates...];
$scope.handleUpdateEvent = function(event) {
$scope.date = event.date;
};
})
只是一个简短的说明。如果单向数据绑定到组件中的数据是一个对象,它的属性仍然是可变的。此处未破坏单向数据绑定,这是典型的 javascript 行为。 Todd Motto 讨论了一种通过克隆数据来打破绑定来克服这个问题的好方法:
$onChanges() = function(changes) {
if(changes.user) {
this.user = angular.copy(this.user);
}
};
有关更多示例,请参阅这些具有有用组件模式的参考资料:
https://toddmotto.com/exploring-the-angular-1-5-component-method/
http://dfsq.info/site/read/angular-components-communication
因此,我们正在将我们的 Angular 1.3 scope soup 应用程序提升到 1.5 标准。但是我们注意到了一些奇怪的行为。当我们将 $scope 变量传递到组件绑定时,它似乎没有正确反映组件内对 $scope 变量所做的任何更改。
我们基于 $scope 的控制器:
app.controller('ParentCtrl', function ($scope) {
$scope.dates = [...array of dates...]
$scope.focusDate = new Date()
})
我们的组件标签:
<section-dates dates="dates" focus-date="focusDate"></section-dates>
组件本身:
app.component("sectionDates", {
bindings: {
dates: "=",
focusDate: "="
},
controller: function () {
this.onClickADate = function (date)
{
this.focusDate=date
}
...
}
单击新日期时,组件中的 focusDate 会发生变化,但父控制器的 $scope 不会发生变化。这是为什么?
我们正在经历类似的事情。
一个让我们花了一些时间思考的重要概念是所有组件都有 isolate $scope。所以理论上这可以防止你提到的“$scope soup”问题,但实际上这导致需要显式地将数据传入和传出组件,这可能需要一些时间来适应。
通常,您会希望保持数据不可变,即防止子组件直接更改数据(在某些特定情况下双向数据绑定改进 UI)。
这里的想法是像这样使用单向数据绑定将数据传递到组件中:
...
bindings: {
oneWayBindingInput: '<'
},
...
然后将事件从子组件传回,然后由父组件处理:
...
bindings: {
oneWayBindingInput: '<'
onEventOutput: '&'
},
...
所以在你的情况下,你可以尝试这样的事情:
组件标签(在父模板中):
<section-dates dates="dates" on-update="handleUpdateEvent($event)"></section-dates>
组件:
app.component("sectionDates", {
bindings: {
dates: "<",
onUpdate: "&"
},
controller: function () {
this.onClickADate = function (date)
{
this.onUpdate({$event: {date: date});
}
...
}
父控制器:
app.controller('ParentCtrl', function ($scope) {
$scope.dates = [...array of dates...];
$scope.handleUpdateEvent = function(event) {
$scope.date = event.date;
};
})
只是一个简短的说明。如果单向数据绑定到组件中的数据是一个对象,它的属性仍然是可变的。此处未破坏单向数据绑定,这是典型的 javascript 行为。 Todd Motto 讨论了一种通过克隆数据来打破绑定来克服这个问题的好方法:
$onChanges() = function(changes) {
if(changes.user) {
this.user = angular.copy(this.user);
}
};
有关更多示例,请参阅这些具有有用组件模式的参考资料: https://toddmotto.com/exploring-the-angular-1-5-component-method/ http://dfsq.info/site/read/angular-components-communication