Home > Software engineering >  What makes a component fail to update its template when a Boolean value changes, in the Angular app?
What makes a component fail to update its template when a Boolean value changes, in the Angular app?

Time:11-08

In an Angular 11 app, I have a simle service that mekes a get request and reads a JSON.

The service:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Promo } from '../models/promo';


@Injectable({
  providedIn: 'root'
})

export class PromoService {

 public apiURL: string;
 
  constructor(private http: HttpClient) {
    this.apiURL = `https://api.url.com/`;
  }

  public getPromoData(){
    return this.http.get<Promo>(`${this.apiURL}/promo`);
  }
}

In the the component, I need to compare the array of products with the array of campaign products (included in the JSON mantioned above) and higlight the promoted products:

export class ProductCardComponent extends DestroyableComponent implements OnInit, OnChanges
{

     public promoData: any;
     public promoProducts: any;
     public isPromoProduct: boolean = false;
     
     
     public ngOnInit() {
         this.getCampaignData();
     }
     
     public ngOnChanges(changes: SimpleChanges): void {
        this.getCampaignData();
      }
     
     
     public getPromoData() {
        this.promoService.getPromoData().pipe(takeUntil(this.destroyed$)).subscribe(data => {
          this.promoData = data;
          this.promoProducts = this.promoData.products;

          let promoProduct = this.promoProducts.find((product:any) => { 
            return this.product.unique_identifier == product.unique_identifier;
          });

          if (promoProduct) {
              // Update boolean
              this.isPromoProduct = true;
            }
        });
     }
 
 }

In the component's html file (template), I have:

<span *ngIf="isPromoProduct" >Promo</span>

There are no compilation errors.

The problem

For a reason I have been unable to understand, the template does not react to the change of the variable isPromoProduct and the template is not updated, despite the fact that I call the function inside ngOnInit and ngOnChanges.

Questions:
  1. Where is my mistake?
  2. What is a reliable way to update the template?

CodePudding user response:

subscribing to Observable inside .ts file it's mostly not a best practice. try to avoid it by using async pipe of Angular.

you need to store the observable in the variable and not the data returned from the observable, for example:

// this variable holds the `observable` itself.
this.promoData$ = this.promoService.getPromoData()

and then in the template you can do it like this:

<div *ngIf="promoData$ | async as promoData">
  here you can access the promoData
</div>

you can still use pipe() to map the data etc but avoid the subscribe()

CodePudding user response:

The isPromoProduct boolean is not an input. The ngOnChanges gets triggered for changes on your properties that are decorated with the @Input decorator. For your particular case, you can inject the ChangeDetectorRef and trigger change detection manually:

constructor(private cdr: ChangeDetectorRef) {}

  // ...
public getPromoData() {
  this.promoService.getPromoData().subscribe(data => {
          // ...

          if (promoProduct) {
              // Update boolean
              this.isPromoProduct = true;
              this.cdr.detectChanges();
            }
        });
}

You also don't need to manage httpClient subscriptions. The observables generated by a simple get or post request will complete after they emit the response of the request. You only need to explicitly manage the unsubscribe for hot observables (that you create from subjects that you instantiate yourself).

  • Related