Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it good practice to reference services in html templates in Angular 2?

As the question states, is there any downside in referencing the service directly in the template as such :

 [disabled]="stateService.selectedClient == null || stateService.currentStep == 1"

In my opinion this doesn't seem like good practice and I'd much rather keep a "selectedClient" object in whatever component needs to use it. How can I get the state and store it into local variables, while observing the changes:

example: I want to move from step1 to step2 by changing "currentStep" in the "stateService", however I want the component that keeps "currentStep" ALSO as a local variable to reflect the change in the state?

like image 416
ZeroCool Avatar asked Aug 24 '16 19:08

ZeroCool


2 Answers

Is it good practice to reference services in html templates in Angular 2?

I'd generally avoid it. It seems to bring more chaos than good.

Cons:

  • Coming from OOP background, this approach looks like it breaks the Law of Demeter, but more importantly,
  • It's no longer MVC, where your controller (Angular2's Component) acts like a mediator between the view and the services.
  • Like Ced said, what if a call to a service's member is costly and we need to refer to it multiple times in the view?
  • At the moment my editor of choice (VS Code) does not fully support Angular2 templates; referencing too many things outside of its own Component's scope in a template makes refactoring not fun anymore.

Pros:

  • Sometimes it looks more elegant (because it saves you 2 lines of code), but trust me, it's not.

How can I get the state and store it into local variables, while observing the changes

Madhu Ranjan has a good answer to this. I'll just try to make it more complete here for your particular example:

In your StateService, define:

currentStep : Subject<number> = new Subject<number>();
selectedClient: Subject<Client> = new Subject<Client>();

changeStep(nextStep: number){          
  this.currentStep.next(nextStep);
}

selectClient(client: Client) {
  this.selectedClient.next(client);
}

In your Component:

currentStep: number;

constructor(stateService : StateService){
  stateService.currentStep.combineLatest(
    stateService.selectedClient, 
    (currStep, client) => {
      if (client == null) {
        // I'm assuming you are not showing any step here, replace it with your logic
        return -1; 
      }
      return currStep;
    })
  .subscribe(val => {
    this.currentStep = val;
  });
}
like image 87
Harry Ninh Avatar answered Sep 30 '22 22:09

Harry Ninh


You may try below,

stateService

 currentStep : Subject<number> = new Subject<number>();

 somestepChangeMethod(){          
    this.currentStep.next(<set step here to depending on your logic>);
 }

component

 // use this in template
 currentStep: number;

 constructor(stateService : stateServiceClass){
    stateService.currentStep.subscribe(val => {
       this.currentStep = val;
    });
 }

Hope this helps!!

like image 36
Madhu Ranjan Avatar answered Sep 30 '22 22:09

Madhu Ranjan