我们能够在复杂对象上应用$watch
,如何在Angular 2中执行类似操作。
Angular 1
$scope.data = {name : "somvalue"}
$scope.$watch('data.name', function(newValue, oldValue) {
scope.counter = scope.counter + 1;
});
Angular 2
export class MyData{
name: string;
}
export class MyComponent implements OnInit {
@Input() data: MyData;
constructor(private ds: MyService){
this.data = ds.data;
}
// $watch('data.name', function(newValue, oldValue) {
// scope.counter = scope.counter + 1;
// });
}
现在如果data.name
在服务中发生变化,如何监视组件本身的变化,请注意数据不是可观察的,它只是一个常规对象。
更新
Please see Plunk for an example
提前致谢!!
答案 0 :(得分:2)
Angular检查属性,如果它们在模板中绑定,则甚至是内部对象。
对于复杂对象,首选选项是使用Observable
主动通知Angular2有关更改。
您还可以通过实施DoCheck
答案 1 :(得分:0)
实现组件生命周期钩子“ngOnChanges”:
@expectedException \InvalidArgumentException
<强>更新强>
我找到了一个可行的解决方法。实现DoCheck钩子而不是OnChanges。
import { OnChanges } from '@angular/core';
@Component({
selector: 'child',
template: `
<h2>Child component</h2>
{{ person }}
`
})
class ChildComponent implements OnChanges {
@Input() person: string;
ngOnChanges(changes: {[ propName: string]: SimpleChange}) {
console.log('Change detected:', changes[person].currentValue);
}
}
请记住,doCheck运行多次,如果错过使用会导致性能问题。
答案 2 :(得分:0)
一般情况下,除非您使用不同的更改检测策略,否则您的组件将会听取所有对象的突变。
import { OnChanges } from '@angular/core';
@Component({
selector: 'child',
template: `
<h2>Child component</h2>
{{ person }}
`,
changeDetection:ChangeDetectionStrategy.OnPush/Default/CheckOnce/Always
})
class ChildComponent implements OnChanges {
@Input() person: string;
ngOnChanges(changes: {[ propName: string]: SimpleChange}) {
console.log('Change detected:', changes[person].currentValue);
}
这:
changeDetection:ChangeDetectionStrategy.OnPush/Default/CheckOnce/Always
将定义当其中一个输入更新时组件的行为方式。
最重要的一个是OnPush和Default。
OnPush表示仅当整个对象替换为新对象时才更新组件,而Default表示如果任何嵌套值已更新(变异)则更新我。
而且,如果你不在组件中使用该对象,Angular将忽略并且不会更新视图(为什么会这样)。
然后你可以轻松地挂钩到ngOnChange生命周期钩子,而另一个答案建议得到更新。
答案 3 :(得分:0)
如果您想进行更多自定义并进行更多手动操作,它是DoCheck
的替代解决方案。当然,根据Günter Zöchbauer answer,这是一种Observable
解决方案。
我使用装饰器来告诉TS必须检测到该属性,因此让我们开始吧。
export class ChangeDetection {
private emitedChangeDetector: ChangeDetection;
private _value;
get value() {
return this._value;
}
/** @warning Don't use it */
__action: (value: any) => void;
/** @warning Don't use it */
__change(value: any) {
this._value = value;
this.__action && this.__action(value);
this.emitedChangeDetector?.__change &&
this.emitedChangeDetector.__change(this.emitedChangeDetector.value);
}
onChange<T = any>(action: (value: T) => void) {
this.__action = action;
return this;
}
emit(extendedObserver: ChangeDetection) {
this.emitedChangeDetector = extendedObserver;
}
}
// For manage list of changes
export class ChangeDetectionList {
changeDetectors: ChangeDetection[];
constructor(...changeDetectors: ChangeDetection[]) {
this.changeDetectors = changeDetectors;
}
onChange(callback: (data: any) => void): ChangeDetectionList {
this.changeDetectors.forEach((a: ChangeDetection) => a.onChange(callback));
return this;
}
emit(changeDetector: ChangeDetection): ChangeDetection {
this.changeDetectors.forEach((a: ChangeDetection) =>
a.emit(changeDetector)
);
return changeDetector;
}
}
/**
* @usageNotes{
* ```typescript
* @ChangeDetector()
* data : string
* ```
* Gives you a ChangeDetection object with the name of data$ that fires "onChange()" function when "data" is changed
*/
export function ChangeDetector(suffix: string = "$") {
return function (prototype: any, key: string | symbol) {
const changeDetectorName: string = `${key.toString()}${suffix}`;
if (!prototype[changeDetectorName]) {
Object.defineProperty(prototype, changeDetectorName, {
value: new ChangeDetection(),
});
const changeDetectorObject = prototype[changeDetectorName] as ChangeDetection;
Object.defineProperty(prototype, key, {
set(value: any) {
Object.defineProperty(this, key, {
get() {
return changeDetectorObject.value;
},
set(v: any) {
changeDetectorObject.__change(v);
},
enumerable: true,
});
this[key] = value;
},
enumerable: true,
configurable: true,
});
}
};
}
现在,它很容易使用。只需在要检测的每个属性上放置@ChangeDetector()
装饰器,或定义一个changeDetector
属性,以在属性更改时引发onChange
事件。
下面是一个示例,向您展示如何使用它。
export class PersonModel {
@ChangeDetector()
changeDetector: number;
changeDetector$: ChangeDetection; // It's just for intellisense, you can ignore it.
firstName: string;
lastName: string;
age: number;
constructor() {
this.age = 34;
this.changeDetector = 0;
}
}
export class ProfileModel {
@ChangeDetector('Listener')
person: PersonModel;
personListener: ChangeDetection; // It's just for intellisense, you can ignore it.
constructor() {
this.person = new PersonModel();
}
}
export class ProfileService {
profile: ProfileModel;
constructor() {
this.profile = new ProfileModel();
// calls 'profileChanged()' when 'person' is changed
this.profile.personListener.onChange((_) => this.profileChanged());
}
setProfile() {
Object.assign(this.profile.person, { firstName: 'Pedram', lastName: 'Ahmadpour' });
this.profile.person.changeDetector++;
}
private profileChanged() {
console.log('profile is', JSON.stringify(this.profile));
}
}
export class ProfileComponent {
constructor(private profileService: ProfileService) {
// Now, profileService.profile listen to its own child changes
this.profileService.profile.person.changeDetector$.emit(profileService.profile.personListener);
this.profileService.setProfile();
}
happyBirthday() {
this.profileService.profile.person.age = 35;
console.log('Happy birthday');
this.profileService.profile.person.changeDetector++;
}
}
或者在实际的Angular项目中:
@Input()
@ChangeDetector()
data: ProfileModel;
data$: ChangeDetection;
并进行测试:
const profileService = new ProfileService();
const profileComponent = new ProfileComponent(profileService);
profileComponent.happyBirthday();