Invader
Invader

Reputation: 161

Can I create an instance of a service for every loaded component in Angular?

I have a component named edit-order.component with the following ts file

export class EditOrderComponent implements OnInit {

  constructor(private editOrderSrv: EditOrderService, private route: ActivatedRoute) { }

  ngOnInit(): void {
    this.editOrderSrv.getOrderById(this.route.snapshot.params.id);
  }
}

and in my edit-order-service.service.ts I have the following code

export class EditOrderService {
  order$: BehaviorSubject<any> = new BehaviorSubject(null);
  constructor(private http: HttpClient) { }

  getOrderById(id: string){
    this.http.get('url', {params: {id}}).subscribe(order => {
      this.order$.next(order);
    }, error => {console.error(error)});
  }
}

The client should be able to open more than one edit-order.component with different id. In my child.component I want to subscribe to order$ like that

export class ChildComponent implements OnInit {
  order: any;
  constructor(private editOrderSrv: EditOrderService) { }

  ngOnInit(): void {
    this.editOrderSrv.order$.subscribe(order => {
      if(order) this.order = order;
    })
  }

}

But therefore I have to have own instances of the service for every edit-order.component to not overwrite order$. How would I achieve that? Or is this not possible? And if it is not possible, what can I do else to achieve my goal?

Upvotes: 1

Views: 1124

Answers (2)

Eliseo
Eliseo

Reputation: 57971

Curiosity, why not your function is

getOrderById(id: string){
    return this.http.get('url', {params: {id}})
  }

And you subscribe to getOrderById?

You can pipe(catchError) if you wish

Update you can also use a "cache" in the service without use an array of Subject, only an array of object

  orders:any={}  //create an empty object where we store the result

  getOrderById(id: string){
    if (this.orders[id])
        return of(this.orders[id]

    return this.http.get('url', {params: {id}}).pipe(
      tap(res=>{
         this.orders[id]=res;
      })
    )
  }

Upvotes: 1

YaakovHatam
YaakovHatam

Reputation: 2344

It's a really bad idea to create different instances of a service. The purpose of the service is to be singleton and that's how it's designed. A good way you can use it is to hold a key-value object for every order observable. from parent components pass the this.route.snapshot.params.id to the child components as input. (Code untested)

service:

export class EditOrderService {
   public orders$: { [orderid: string]: BehaviorSubject<any> } = {};

   constructor(private http: HttpClient) { }

   getOrderById(id: string): void {
      this.http.get('url', { params: { id } }).subscribe(order => {
         if (!this.orders$[id]) {
            this.orders$[id] = new BehaviorSubject<any>(null);
         }
         this.orders$[id].next(order);

      }, error => { console.error(error); });
   }
}

child component:

export class ChildComponent implements OnInit {
  order: any;
  @Input() orderId: any;
  constructor(private editOrderSrv: EditOrderService) { }

  ngOnInit(): void {
    this.editOrderSrv.orders$[orderId].subscribe(order => {
      if(order) this.order = order;
    })
  }

}

Upvotes: 1

Related Questions