9

I'd like to watch an object/array, which ca be edited by a service or by a controllers routine. I thought that an Observable could watch an object/array.

My implementation doesn't react on changes of the items :

  private data : Observable<Array<any>>;
  private dataObserver: Observer<Array<any>>;
  private sub : Subscription;
  private items: <Array<any>>;

  ngOnInit() {
     this.items = itemService.getItems();
     this.data = new Observable<Array<any>>(observer =>{
        this.dataObserver = observer;
     });
     this.data.subscribe(
        x => console.log('onNext: %s', x),
        e => console.log('onError: %s', e),
        () => console.log('onCompleted')
     );
     this.dataObserver.next(this.items);
  }


private start(){

  //change values of the array in an interval
  let loop = Observable.interval(250)
  let i=0;
  self.sub = loop.subscribe(() => {
      if(self.items[0]){
        self.items[0].id= i;
        if(i<100) i++;
        else i=1;
      }
  })
}

The observalbes subsciption doesn't react on changes of the items array. It only triggers on its next mehtod. On the other hand .. this is too cumbersome for a simple watch method.

What does angular-2 offer us to watch for changes, as $scope.$watch did in angular-1?

Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
marcel
  • 3,231
  • 8
  • 43
  • 76

3 Answers3

14

Angular2 provides IterableDiffer (array) and KeyValueDiffer (object) to get information about differences between two checks.

NgClass is a good example https://github.com/angular/angular/blob/14ee75924b6ae770115f7f260d720efa8bfb576a/modules/%40angular/common/src/directives/ng_class.ts#L122

See also https://angular.io/docs/ts/latest/api/#!?query=differ

An example

// inject a differ implementation 
constructor(differs: KeyValueDiffers) {
  // store the initial value to compare with
  this.differ = differs.find({}).create(null);
}

@Input() data: any;

ngDoCheck() {
  var changes = this.differ.diff(this.data); // check for changes
  if (changes && this.initialized) {
    // do something if changes were found
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Do you have a simple example how an array/object could be watched? It's one line of code in Angular1, If it's that complicated as I see in NgClass it is overdesigned. – marcel Nov 24 '16 at 14:05
  • Angular2 has not much in common with Angular1. They did 2 complete rewrites to get where they are now, and for a reason. Angular2 aims for maximum performance. There are things that are better than in Angular1 and some that are not. The things that not better from one perspective, are usually to gain other benefits. – Günter Zöchbauer Nov 24 '16 at 14:09
  • To watch an object a fundamental feature. That means it is not possible in Angular2? What kind of strategy do I have to follow in angular2 now? – marcel Nov 24 '16 at 14:14
  • Ok, I don't understand it. Every question can be anseared by a frameworks implementation itself. So, how about three line of codes how to watch an object? – marcel Nov 24 '16 at 14:19
  • Thx for your example. This has a decent effort. – marcel Nov 24 '16 at 14:57
6

In the import section:

import { DoCheck, KeyValueDiffers, KeyValueChangeRecord } from '@angular/core';

Adding the 'KeyValueDiffers' injector:

private _differ: any;    

constructor(private _differs: KeyValueDiffers) {
    this._differ = _differs.find({}).create();
}

Finally track changes:

ngDoCheck() {
    const change = this._differ.diff(this.Your_Object_To_Track);
    if (change) {
        change.forEachChangedItem(
            (record: KeyValueChangeRecord<any, any>) => {
                console.log(record.key + ': ' +  record.previousValue + '=>' + record.currentValue) });

        change.forEachRemovedItem(                
                (record: KeyValueChangeRecord<any, any>) => {
                    console.log(record.key + ': ' +  record.previousValue + '=>' + record.currentValue) });

        change.forEachAddedItem((record: KeyValueChangeRecord<any, any>) => {
                console.log(record.key + ': ' +  record.previousValue + '=>' + record.currentValue) });
    }
}
johnny 5
  • 19,893
  • 50
  • 121
  • 195
Hany
  • 1,310
  • 15
  • 17
1

Thanks for your example Gunter.

I choose a quick solution based on your response.

I replace the OnInit handle by a DoCheck implementation. Now if value change in my service external called Language the view is updated.

In my case example :

import { Component, DoCheck } from "@angular/core";
export class LangListUserComponent implements DoCheck {

  constructor(private _languageService: LanguageService)
  {}

  ngDoCheck() {
    /** Get available lang */
    this.oLanguages = this._languageService.getLanguageList();
    this.setCurrentLang(this.oLanguages);
  };
}
TGA
  • 73
  • 1
  • 7