角度1.5组件,ui路由器解析,$ onChanges生命周期挂钩 [英] angular 1.5 component, ui-router resolve, $onChanges lifecycle hook
问题描述
在以下示例中( plunker ),UI路由器状态路由至一个 app 组件,它具有一个 data 对象和一个 replace 方法,该方法使用给定值用一个新对象替换该对象.在其模板中,具有:
In the following example (plunker), a ui-router state routes to an app component that has a data object and a replace method that replaces this object with a new one using the given value. In its template, it has:
- 一个编辑器组件,该组件通过回调绑定('&') 触发 replace 方法 通过1向绑定('<')接收 data 对象的
- display 组件,在触发$ onChanges生命周期挂钩时进行本地复制,并显示对象的内容
- an editor component which triggers the replace method through a callback binding ('&')
- a display component which receives the data object through a 1-way binding ('<'), makes a local copy when the $onChanges lifecycle hook is triggered, and displays the contents of the object
一切正常,并按预期进行:-)
Everything works fine and as expected :-)
angular
.module('app', ['ui.router'])
.config(($urlRouterProvider, $stateProvider) => {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('root', {
url: '/',
component: 'app'
});
})
.component('app', {
controller: function () {
this.data = { name: 'initial' };
this.replace = (value) => { this.data = { name: value }; };
},
template: `
<editor on-replace="$ctrl.replace(value)"></editor>
<display data="$ctrl.data"></display>
`
})
.component('editor', {
bindings: {
onReplace: '&'
},
controller: function () {
this.replace = (value) => this.onReplace({value});
},
template: `
<input type="text" ng-model="value">
<button ng-click="$ctrl.replace(value)"> replace object </button>
`
})
.component('display', {
bindings: {
data: '<'
},
controller: function () {
this.$onChanges = (changes) => {
if (changes.data) {
this.data = Object.assign({}, this.data);
}
};
},
template: `
<p> value : {{ $ctrl.data.name }} </p>
`
});
以下第二个示例对我有问题( plunker ).设置完全相同,只是 app 组件不再管理 data 本身,而是通过1路方式接收 data 对象绑定('<'),它定义为ui-router状态的解析(从注释中可以看出,我使用全局对象和方法进行了测试,并通过服务进行了交互).重新分配此解析的对象后,我期望触发 app 组件的$ onChanges钩子(因为 display 组件的
I have a problem with the following second example (plunker). It is the exact same setting, except that the app component no longer manages the data itself, but receives a data object through a 1-way binding ('<') that is defined as a resolve of the ui-router state (as can be seen in the comments, I tested both using a global object and method, and interacting through a service). When this resolved object is reassigned, I was expecting the $onChanges hook of the app component to be triggered (as it is for the display component when the data object of the app component is reassigned), but this is not the case. Does anyone has an explanation?
let data = { name: 'initial' };
const replace = (value) => { data = { name: value }; };
angular
.module('app', ['ui.router'])
/*.factory('DataService', function () {
let data = { name: 'initial' };
return {
getData: () => data,
replace: (value) => { data = { name: value }; }
};
})*/
.config(($urlRouterProvider, $stateProvider) => {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('root', {
url: '/',
component: 'app',
resolve: {
data: () => data /*(DataService) => DataService.getData()*/
}
});
})
.component('app', {
bindings: {
data: '<'
},
controller: function (/*DataService*/) {
this.$onChanges = (changes) => {
if (changes.data) {
this.data = Object.assign({}, this.data);
}
};
this.replace = (value) => { replace(value); }; /*(value) => { DataService.replace(value); };*/
},
template: `
<editor on-replace="$ctrl.replace(value)"></editor>
<display data="$ctrl.data"></consumer>
`
})
.component('editor', {
bindings: {
onReplace: '&'
},
controller: function () {
this.replace = (value) => this.onReplace({value});
},
template: `
<input type="text" ng-model="value">
<button ng-click="$ctrl.replace(value)"> replace object </button>
`
})
.component('display', {
bindings: {
data: '<'
},
controller: function () {
this.$onChanges = (changes) => {
if (changes.data) {
this.data = Object.assign({}, this.data);
}
};
},
template: `
<p> value : {{ $ctrl.data.name }} </p>
`
});
推荐答案
在后台,UI-ROUTER
创建的HTML具有在父作用域上与$resolve.data
的一次性绑定.
Under the hood, UI-ROUTER
creates HTML with a one-time binding to $resolve.data
on the parent scope.
<app data="::$resolve.data" class="ng-scope ng-isolate-scope">
<editor on-replace="$ctrl.replace(value)" class="ng-isolate-scope">
<input type="text" ng-model="value" class="ng-pristine ng-untouched ng-valid ng-empty">
<button ng-click="$ctrl.replace(value)"> replace object </button>
</editor>
<display data="$ctrl.data" class="ng-isolate-scope">
<p class="ng-binding"> value : initial </p>
</display>
</app>
在app
组件中调用$onChanges
钩子的观察程序监视父作用域的$resolve.data
属性.它对隔离范围的$ctrl.data
属性的更改没有反应.而且由于它是一次性绑定,因此$onChanges
挂钩仅在变量被初始化时才被调用,而不是在随后的更改时被调用.
The watcher that invokes the $onChanges
hook in the app
component watches the $resolve.data
property of the parent scope. It does not react to changes to the $ctrl.data
propery of the isolate scope. And since it is a one-time binding, the $onChanges
hook gets invoked only when the variable gets initialized and not on subsequent changes.
与其尝试弯曲$onChange
来完成并非为之设计的事情,而是使用 RxJS Angular扩展.
Instead of trying to bend $onChange
to do something for which it was not designed, build a service with RxJS Extensions for Angular.
app.factory("DataService", function(rx) {
var subject = new rx.Subject();
var data = "Initial";
return {
set: function set(d){
data = d;
subject.onNext(d);
},
get: function get() {
return data;
},
subscribe: function (o) {
return subject.subscribe(o);
}
};
});
然后只需订阅更改.
app.controller('displayCtrl', function(DataService) {
var $ctrl = this;
$ctrl.data = DataService.get();
var subscription = DataService.subscribe(function onNext(d) {
$ctrl.data = d;
});
this.$onDestroy = function() {
subscription.dispose();
};
});
在PLNKR上的 DEMO .
这篇关于角度1.5组件,ui路由器解析,$ onChanges生命周期挂钩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!