Angular 2 + Ionic 2: Detect if an object was modified

Q) If I've got an object with loads of properties, all bound to fields in a form, how do I catch when the object has changed?

I don't want to put (blur) events on every field as the page is quite heavy already and this could lead to way too many listeners on the page.

E.g

Object:

var person = {
    name: string,
    email: string,
    phone: string
};

Form:

<input [(ngModel)]="person.name" type="text" />
<input [(ngModel)]="person.email" type="text" />
<input [(ngModel)]="person.phone" type="text" />

Solution 1:

However, ideally I need another way, like the angular 1 $watch, as there are other ways my complex object can be changed, not just simple input fields

I was working in a Google Autocomplete Component, and I was dealing with a similar issue: when the user types an address and select one from the Google suggestions, I needed to update some other fields (like city, province, zip code, and so on).

Like @Günter Zöchbauer says, I've created an observable in order to know when something has changed in my autocomplete component, but the second problem was that the view was not being updated when that happened. That's because something very interesting and powerfull called Zones. If the concept is new for you, please refer to here and here for a great explanation.

As you can read there,

Application state change is caused by three things:

  1. Events - User events like click, change, input, submit, …

  2. XMLHttpRequests - E.g. when fetching data from a remote service

  3. Timers - setTimeout(),setInterval(), because JavaScript

… it turns out that these are the only cases when Angular is actually interested in updating the view.

So if

there are other ways my complex object can be changed

You will have to let Angular know that something has changed and needs to we aware of updating things. This is what I did:

import {Injectable} from '@angular/core';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class AutocompleteService {

    private autocompleteObserver: any;
    public autocomplete: any;

    constructor(...) {
        this.autocompleteObserver = null;

        this.autocomplete = Observable.create(observer => {
            this.autocompleteObserver = observer;
        });
    }

    public initializeAutocomplete(element): void { 

        // Where all the magic happens
        // ...

        // Send informtaion back to the caller
        this.autocompleteObserver.next(addressInformation);
    }

And then in my page .ts:

import { Component, NgZone } from '@angular/core';
import { AutocompleteService } from '../../providers/autocomplete-service/autocomplete-service';

@Component({
  templateUrl: 'build/pages/my-new-page/my-new-page.html',
  directives: [FORM_DIRECTIVES],
  providers: [AutocompleteService]
})
export class MyNewPage {

    constructor(..., private autocompleteService : AutocompleteService) {
    
        // Initialize all the things you need
        // ... 

       this.autocompleteService.autocomplete.subscribe((addressInfo) => {
            this.ngZone.run(() => {
                // Update the fields of the form, and Angular will update
                // the view for you.
                this.updateAddress(addressInfo);
            });
        });
    }
}

So by executing some code inside an angular zone you're telling Angular that it needs to be aware of those changes because things will probably need to be updated.

Solution 2:

you can use a form object and check if the form has changed.

I know that there have been some issues with latest release of Angular2 and Ionic2 with the new Forms module, but that would be my suggestion.

https://angular.io/docs/ts/latest/guide/forms.html