Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listen to Changes on an Object's field in Angular2/Typescript

In Angular2/Typescript, is it possible to "observe" an object's field for changes.

For example, say I have a class Person with fields firstName, lastName, and fullName. Is it possible to automatically update fullName whenever either firstName or lastName changes?

Something like this:

export class Person {
  firstName: string= '';
  lastName: string = '';
  fullName: string = '';

  constructor(firstName: string, lastName: string) {
    this.firstName.onChange(() => { this.updateFullName(); });
    this.lastName.onChange(() => { this.updateFullName(); });

    this.firstName = firstName;
    this.lastName = lastName;
  }

  updateFullName() {
    this.fullName = `${this.firstName} ${this.lastName}`;
  }
}
like image 254
Fuzzley Avatar asked May 01 '16 17:05

Fuzzley


1 Answers

First approach

You could leverage TypeScript setters / getters as described below to synchronize fullName with firstName and lastName:

get lastName() {
  return this._lastName;
}

set lastName(lastName:string) {
  this._lastName = lastName;
  this.fullName = this._firstName + ' ' + this._lastName;
}

get firstName() {
  return this._firstName;
}

set firstName(firstName:string) {
  this._firstName = firstName;
  this.fullName = this._firstName + ' ' + this._lastName;
}

This way when setting lastName or firstName, fullName is automatically updated:

var p = new Person();
p.lastName = 'last';
p.firstName = 'first';
console.log(p.fullName); // print 'first last'

Second approach

Angular2 by default doesn't allow to define change of properties within objects. It only detects updates of at references. I mean if the reference (or value for primitive types) of a bound property is updated.

That bien said, Angular2 allows to plugin your own strategy using the ngDoCheck hook method.

In it you can leverage the KeyValueDiffers class (to be injected) to detect updates in specific objects.

See this link for more details:

  • https://angular.io/docs/ts/latest/api/core/DoCheck-interface.html

Here is a sample:

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

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

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

    if (changes) {
      changes.forEachChangedItem((elt) => {
        if (elt.key === 'firstName' || elt.key === 'lastName' ) {
          this.person.fullName = this.person.firstName + ' ' + this.person.lastName;
        }
      });
    }
  }
}

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

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

like image 52
Thierry Templier Avatar answered Sep 21 '22 23:09

Thierry Templier