Home > Software design >  Asign component variable with result of async method in a service
Asign component variable with result of async method in a service

Time:02-16

I'm trying to build an application and I don't want my component to have unnecessary code. There is a lot of logic that I would like to put in a service and then inject the service into my component. Let say my component has a variable named 'result':

my.component.ts

    .....

    private result:number;

and my service has an async method:

my.services.ts

    ......
    ......

    getNumberFromApi(){
    callAsync().subscribe( data => {
        console.log('This is the data obtained..' data);
    })

I would like to have the chance of passing a parameter to the method getNumberFromApi():

    getNumberFromAPI(destinationVar:number){
    callAsync().subscribe( data => {
        console.log('This is the data obtained..' data);
        destinationVar=data;
    })
    

So that in my component I would be able to call the method of this service in this way:

my.component.ts

    .....

    private result:number;
    myServiceInstance.getNumberFromApi(result);

I understand this is not possible (probably because the method's stack is already gone at the time the response arrives) but I don't find a way to do this or something similar. Can somebody recommend me an alternative? I would like to modify from the service variables of the component, even with async methods, without anything more than a method invocation line in the component. Is this possible? Am I missing a crucial concept of how Typescript/Angular works here? Thanks.

CodePudding user response:

You'd need to return the observable from the service and subscribe to it in the component. This way, the async nature of the observable would be preserved and you'd get to invoke the presumed API call with different parameters if needed.

Serivce

import { Observable } from 'rxjs';

getNumberFromApi(): Observable<any> {
  return callAsync();
}

Component

export class SomeComponent implements OnInit {
  someVar: any;

  constructor(private someService: SomeService) { }
  
  ngOnInit() {
    this.someService.getNumberFromApi().subscribe({
      next: (value: any) => this.someVar = value,
      error: (error: any) => { }
    });
  }
}

On the other hand, if the variable someVar in the component is only used in the template to render some data, you could skip the subscription in the component controller and using the async pipe in the template.

Controller (*.ts)

import { Observable } from 'rxjs';

export class SomeComponent implements OnInit {
  someVar$: Observable<any>;   // <-- dollar sign is only a convention

  constructor(private someService: SomeService) { }
  
  ngOnInit() {
    this.someVar$ = this.someService.getNumberFromApi();
  }
}

Template (*.html)

<ng-container *ngIf="(someVar$ | async) as someVar">
  <!-- use `someVar` -->
  {{ someVar }}
</ng-container>
  • Related