5

In a simplified way I have an Angular2 Component and an input object like this:

class MyObject{
 Prop1:string;
 Prop2:Number;
}  

@Component() 
export class MyComponent{
 @Input() myObject: MyObject;
 DoSomethingIfProp1Change(){
  console.log(myObject.Prop1);
 }
}

How can I detect if Prop1 was changed from Hostcomponent and then execute the DoSomethingIfProp1Change method from inside MyComponent?

Xaver
  • 383
  • 1
  • 4
  • 15

2 Answers2

5

In fact, by default Angular2 detects changes when object reference is updated not its content. But this default behavior can be changed by using the DoCheck interface.

In your case (detecting that a property was updated into the myObject object, you could use the following approach:

@Component({
  selector: 'my-component',
  (...)
}) 
export class MyComponent implements DoCheck {
  @Input() myObject: MyObject;
  differ: any;

  constructor(differs:  KeyValueDiffers) {
    this.differ = differs.find([]).create(null);
  }

  ngDoCheck() {
    var changes = this.differ.diff(this.myObject);

    if (changes) {
      changes.forEachChangedItem((elt) => {
        if (elt.key === 'prop1') {
          this.doSomethingIfProp1Change();
        }
      });
    }
  }

  doSomethingIfProp1Change() {
    console.log('doSomethingIfProp1Change');
  }
}

When the value of the prop1 property is updated, the doSomethingIfProp1Change method is called.

See this plunkr: http://plnkr.co/edit/uvOKMXQa9Ik8EiIhb60Y?p=preview.

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Trying to understand what this is actually doing but in the meantime, I'm getting an error on the line in the constructor, create expects no arguments. – azulBonnet May 20 '19 at 19:44
4

You can use observables to support notification of subscribers. Angular itself doesn't provide support for observing changes of internal object state.

class MyObject{
  constructor() {
    this.prop1Change$ = new Observable(observer => 
        this._prop1Observer = observer).share(); // share() allows multiple subscribers

    this.prop2Change$ = new Observable(observer =>
        this._prop2Observer = observer).share();
        console.debug(this._prop2Observer);
  }

  prop1Change$: Observable<string>;
  private _prop1Observer: Observer;
  _prop1:string;
  get prop1():string { return this._prop1 };
  set prop1(value:string) {
    this._prop1 = value;
    this._prop1Observer && this._prop1Observer.next(value);
  }

  prop1Change$: Observable<number>;
  private _prop2Observer: Observer;
  _prop2:Number;
  get prop2():number { return this._prop2 };
  set prop2(value:number) {
    this._prop2 = value;
    console.debug(this);
    this._prop2Observer && this._prop2Observer.next(value);
  }
}

This code could be shortened by using Subject but Observable should be favored over Subject.

@Component() 
export class MyComponent{
  @Input() myObject: MyObject;

  count2:number;

  DoSomethingIfProp1Change(){
    console.log(myObject.prop1);
  }

  ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    console.log('changes');
    if(changes['myObject']) {
      if(this.prop2Subscription) {
        this.prop2Subscription.unsubscribe();
      }
      this.prop2Subscription = this.myObject.prop2Change$.subscribe(value => {
        this.count2 = value;
        console.log('count2: ' + value);
      });
      // same for `prop2`
    }
  }
}

Plunker example

See also Delegation: EventEmitter or Observable in Angular2

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Hi gunter, on the link you provide, an update recommend to use Subject, what would you advice in terms of best practice ? – ThomasP1988 Jul 25 '16 at 13:36
  • @ThomasP1988 Not sure what you mean. `EventEmitter` is for `@Output()`s only. What else is unclear about best practice? – Günter Zöchbauer Jul 25 '16 at 14:06
  • in the link your provided 'Delegation: EventEmitter or Observable in Angular2' the best answer recommends to use BehaviorSubject instead of observable. Do you agree with that ? – ThomasP1988 Jul 25 '16 at 14:13
  • 2
    That depends no your requirements. There is a difference between `BehaviorSubject` and `Subject`. BehaviorSubject emits the last emitted value immediately to new subscribers. This is useful if the first event was emitted before the subscriber subscribed. With `Subject` you only get notified when another event is emitted while `BehaviorSubject` immediately replays the last event. `Observable` is a more barebone version of `Subject`. It's usually considered better practice to use `Observable` instead of `Subject` but `Subject` is a bit easier to set up. – Günter Zöchbauer Jul 25 '16 at 14:16