Home > Net >  Angular subscribe to change of variable in another component
Angular subscribe to change of variable in another component

Time:10-06

I have an application that consist of 3 components and 1 service:

  • app.component. This holds my navbar etc. In the navbar there is a mat-select where you can choose the customer.
  • orders.component. Lists the orders of the current selected customer.
  • products.component. Lists the products of the current selected customer.
  • customer.service. Some functions used for customers, but also a variable with the current selected customer

Desired state:

  • When a customer is not selected and user navigates to orders or products, no call should be made to the API.
  • When a customer is selected in the navbar while the user is on the orders/products page, the API should trigger to get the orders/products for the choosen customer.
  • When the customer is changed, the API should be triggered to load the new customers orders/products
  • When a customer is selected and the user navgiates to orders/products, the API should be called directly to get the data

Current state

  • Currently I have added customerObserver: Subject<boolean> = new Subject<boolean>(); to the customer.service.
  • When a customer is selected in the navbar (app.components), it calls a function in customer.service which in the end will do this.customerObserver.next(this.customer);
  • In both the orders and products components, I do this:
  ngOnInit(): void {
    if (this.customerService.customer) {
      this.loadOrders();
    }

    this.customerService.customerObserver.subscribe(customer => {
      if(customer) {
        this.loadOrders();
      }
    });
  }

The functionality worked fine, but I realised that as I do never unsubscribe this messes up the application totally as it creates a lot of subscribes when navigating around. I added unsubscribe in orders (see snippet below), but then when I am navigating around I get the following error: ObjectUnsubscribedErrorImpl {message: 'object unsubscribed', name: 'ObjectUnsubscribedError'}

  ngOnDestroy() {
    this.customerService.customerObserver.unsubscribe();
  }

I have tried to read up on subscribe for a while now but is stuck how to proceed.. Any tips on how to arrange to achieve the desired state?

CodePudding user response:

You can emit data from the service to the components observers.

private customerSubject = new Subject<number>();
customerSelectedAction$ = this.customerSubject.asObservable();

products$ = this.customerSelectedAction$.pipe(
 switchMap(customerId=>this.http.get<Product[]>(`${this.url}?customerId=${customerId}`))
    .pipe(
      tap(data => console.log(data)),
      catchError(this.handleError)
  ));

orders$ = this.customerSelectedAction$.pipe(
 switchMap(customerId=>this.http.get<Orders[]>(`${this.url}?customerId=${customerId}`))
    .pipe(
      tap(data => console.log(data)),
      catchError(this.handleError)
  ));

selectedCustomerChanged(customer: Customer): void {
  this.customerSubject.next(customer.id);
}

After that, you subscribe to the products$ or orders$ observables depending on which component you are. And use the selectedCustomerChanged(customer: Customer) method from navbar.

CodePudding user response:

You can manage the subscription in each component in a subscription array, you can look here for the best answer: Unsubscribing an array of subscriptions

Another tip, you can use a private BehaviorSubject (and a public asObservable prop), starting with null, so you can remove the customerObserver: Subject<boolean> = new Subject<boolean>(); altogether. You just subscribe to that observable and load orders if the customer is not null (you can also use distinct until changed).

  • Related