6

I need some clarification on binding between service and component properties and data binding in angular2

assume i have a service(singleton) and a component

export class Service {
 name = "Luke";
 object = {id:1};
 getName(){return this.name};
 getObject(){return this.object};
}

export class Component implements OnInit{
 name:string;
 object:any;
 constructor(private _service:Service){}
 ngOnInit():any{

   //Is this 2 way binding?
   this.name = this._service.name;
   this.object = this._service.object;

   //Is this copying?
   this.name = this._service.getName();
   this.object = this._service.getObject();
  }
}
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
Han Che
  • 8,239
  • 19
  • 70
  • 116

3 Answers3

7

Angular binding only works for bindings declared in the view (HTML).

If you want properties in your component being updated when values in a service change, you need to take care of it yourself.

Observables make this easy. See detect change of nested property for component input for an example.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Hi Günter, thanks for your reply and yes I'm on the observables, but in case of this.name = this._service.name; what does it do, is it then just a simple copy? – Han Che Apr 06 '16 at 09:10
  • Yes it copies the value once when `ngOnInit()` is called. If for example the service acquires the data from a remote server using an HTTP request, then there might not yet be a value in `this.service.name`. If the service later receives the response from the server the component doesn't get the new value. – Günter Zöchbauer Apr 06 '16 at 09:14
  • the ngOnInit() was just an example, but then what would the difference be between using this.service.name and this.service.getName()? Is it like in java if I declare name as private in the service to protect it and use getters and setters? – Han Che Apr 06 '16 at 09:18
  • This only depends on what `Service.name` and `Service.getName()` return. The value returned from the property or method are assigned to `this.name`, that's all. There is no Angular involved. This is just what TypeScript does. – Günter Zöchbauer Apr 06 '16 at 09:21
7

If you update elements by reference (if you update something into the object property), you will see the updates in the view:

export class Service {
  (...)

  updateObject() {
    this.object.id = 2;
  }
}

If you update elements by value (if you update something into the name property), you won't see the updates in the view:

export class Service {
  (...)

  updateName() {
    this.name = 'Luke1';
  }
}

See this plunkr: https://plnkr.co/edit/w7bS0fAVjOc3utnpD39b?p=preview.

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • i see, because in the first case ive created two references pointing towards the same object, while the below i would net to "copy" the property again? – Han Che Apr 06 '16 at 11:56
  • but wait, does it mean that if I have a reference datatype in a Service Singleton, and create new references pointing towards it in various components, the view will update automatically each time i'm changing it?? – Han Che Apr 06 '16 at 12:15
  • 1
    @HanChe, yes, the views will all update automatically, because all of your template bindings are bound to the same/one object. All of your components have their own references, but they all point to the same Singleton service, and then all of the template bindings have their own references, but they all point to the same object within that Singleton. So it all works. – Mark Rajcok Apr 06 '16 at 15:51
  • @MarkRajcok Thanks! but it is this save to use? Are there any major pitfalls? – Han Che Apr 07 '16 at 06:24
0

If you want properties in a component updates as soon as a value in change in a service changes:

  1. Import DoCheck from @angular/core and your service into the component.
  2. Call the service functions affecting the component property in ngDoCheck(){...}
  3. The component view will be updated automatically as soon as any changes

Something like this in your component:

  ngDoCheck() {
    this.qty = this.cartService.getTotalQtyInCart();
  }