angular *ngIf not working when ngstyle works

99 Views Asked by At

This is my angular code when bottom element load working ngif is not working, why could be so? Below there is component code and html , which are using in my snippet. Problem is really strange, because code should work. But !loading expression works well for ngif.
Before loading;

enter image description here
After loading;

enter image description here

export class AppComponent implements OnInit {
  title = 'Anular Application';
  //products: Iproduct[] = data;
  products: Iproduct[] = [];
  parentData: string = "This is parent data";
  details: boolean = false;
  loading: boolean = false;
  variable: boolean = true;
  constructor(private productsService: ProductsService,   ) {
  }

  //service proving us the data
  ngOnInit(): void {
    this.loading = true
    this.productsService.getProducts().subscribe(products => {
      setTimeout(() => {}, 2000);
      this.products = products;
      this.loading = false;
      this.variable = false;
    });

  }
}
<h1 class="text-center" [ngStyle]="{'visibility': loading ? 'visible' : 'hidden' }">Loading ngstyle 23..</h1>
<h1  *ngIf="loading" class="text-center">Loading if ..</h1>
<h1  *ngIf="!loading" class="text-center">not Loading if ..</h1>
<app-product-component [stringHardCode]="'string hardcoded'" [childData]="parentData" 
    *ngFor="let product of products; let i = index" [product]="product">

3

There are 3 best solutions below

0
PRATIK NUGURWAR On BEST ANSWER
<h1 class="text-center" [ngStyle]="{'visibility': loading ? 'visible' : 'hidden' }">Loading using ngStyle..</h1>
<h1 *ngIf="loading" class="text-center">Loading using *ngIf..</h1>
<h1 *ngIf="!loading" class="text-center">Not Loading using *ngIf..</h1>
<app-product-component
  [stringHardCode]="'string hardcoded'"
  [childData]="parentData"
  *ngFor="let product of products; let i = index"
  [product]="product">
</app-product-component>

 **.ts file**
export class AppComponent implements OnInit {
  title = 'Angular Application';
  products: IProduct[] = [];
  parentData: string = "This is parent data";
  loading: boolean = true;
  variable: boolean = true;

  constructor(private productsService: ProductsService) {}

  ngOnInit(): void {
    this.productsService.getProducts().subscribe(products => {
      setTimeout(() => {
        this.products = products;
        this.loading = false; 
        this.variable = false;
      }, 2000);
    });
  }
}

With these changes, the loading and conditional rendering should work as expected.

3
Eliseo On

Update Pratik was faster than me :) (You have a "type error", see where should be the { } in the setTimeout function), so only an advice:

If you want to simulate a "delay", you can also use the rxjs operator delay

this.productsService.getProducts().pipe(
 delay(2000)
 ).subscribe(products => {
      this.products = products;
      this.loading = false;
      this.variable = false;
})
0
MrCodingB On

Your problem doesn't seem to be with the *ngIf directive, but rather with your understanding and usage of the setTimeout function. The setTimeout function works by calling the provided callback function after a specified time has passed. It doesn't stop your code or introduce a delay in your code (See MDN). Therefore the issue is most likely that productsService.getProducts doesn't take a lot of time to complete and so the amount of time the loading text is displayed is too short for you to notice or even be rendered.

To make the loading text visible you'd have to actually introduce a delay that would allow the text to be displayed for long enough. This could be done in many ways, but mainly there are two options:

The first option would be using setTimeout, but fixing the empty callback:

ngOnInit(): void {
  this.loading = true;

  this.productsService.getProducts().subscribe(products => {
    setTimeout(() => {
      this.products = products;
      this.loading = false;
      this.variable = false;
    }, 2000);
  });
}

The second option would be to use the rxjs delay operator:

ngOnInit(): void {
  this.loading = true;

  this.productsService.getProducts()
    .pipe(delay(2000))
    .subscribe(products => {
      this.products = products;
      this.loading = false;
      this.variable = false;
    });
}