skip to Main Content

I’m using angular 17 and I’m getting data from my API but after reciving it the template doesn’t update and I ca’t show my data.

My component service where I’m doint my request to the server:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, tap } from 'rxjs';
import { APIBASEURL } from 'app/constants.config';


@Injectable({
  providedIn: 'root'
})
export class DashboardService {

  constructor(
    private http: HttpClient
  ) { }

  getData(): Observable<any> {
    return this.http.get(`${APIBASEURL}/dashboard/links`)
  }


}

My component where I subscribe to the previous method:

import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { FuseCardComponent } from '@fuse/components/card';
import { DashboardService } from './dashboard.service';
import { Subject, takeUntil } from 'rxjs';
import { MatIconModule, MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
// import { CustomIconDirective } from './custom-icon.directive';
import {MatInputModule} from '@angular/material/input'; 
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {MatButtonModule} from '@angular/material/button';
import { UserService } from 'app/core/user/user.service';
import { User } from 'app/core/user/user.types';


@Component({
  selector: 'app-dashboard',
  standalone: true,
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CommonModule, FuseCardComponent, MatIconModule, MatInputModule, MatSlideToggleModule, MatButtonModule],
  templateUrl: './dashboard.component.html',
})


export class DashboardComponent implements OnInit, OnDestroy {

  data: any;

  private unsubscribeAll: Subject<any> = new Subject<any>();


  constructor(
    private dashboardService: DashboardService,
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer,
    private _userService: UserService,

  ) { }

  ngOnInit() {

    // Subscribe to the dashboard service
    this.dashboardService.getData().subscribe((data) => {
      this.data = data;
      console.log('subscribe: ', this.data);
    });

    console.log('after: ', this.data)
  }

  ngOnDestroy(): void {
    this.unsubscribeAll.next(null);
    this.unsubscribeAll.complete();
  }

}


After that in the template I just show up my data but it’s always empty.

And if I look at the devtool in the console I’ll see that at first the second console log i’ts showing first and then the second one with the data correctly.

After a lot of research I found if I do this:
this.data = this.dashboardService.getData()
instead of subscribin and then in the template putting async
@if(data | async; as data) this works but I want to know why subscribing it’s not working.

Let you know that I’m new in angular and this is my first website.

I tried usgin the second method as I said but I want to know why the first one is not working

2

Answers


  1. Your view is not updating automatically because of the ChangeDetectionStrategy.OnPush.

    In order to update the view without using the async pipe in the template you can use the ChangeDetectionRef:

     constructor(
        ...
        private _cdr: ChangeDetectionRef
      ) { }
    

    And then:

     this.dashboardService.getData().subscribe((data) => {
          this.data = data;
          this._cdr.detectChanges(); // <----
          console.log('subscribe: ', this.data);
        });
    

    More details here

    PS:

    In general, it is better to use the AsyncPipe instead of subscribing manually.

    It is NOT. It always depends on what you’re trying to achieve.

    Login or Signup to reply.
  2. OnPush change detection will only update the view when an @Input value changes or an observable bound in the template emits.

    To fix your issue, you could manually call detectChanges as suggested by @Jacopo Sciampi.

    Or, you could use default change detection.

    Or you could keep your data as observable and use the async pipe, which is what I find to usually be the simplest code:

    export class DashboardComponent {
    
      data$: Observable<any> = this.dashboardService.getData();
    
      constructor(
        private dashboardService: DashboardService,
        private matIconRegistry: MatIconRegistry,
        private domSanitizer: DomSanitizer,
        private _userService: UserService,
      ) { }
    
    }
    
    <ng-container *ngIf="data$ | async as data">
    
      <p> My data </p>
      <pre>{{ data | json }}</pre>
    
    </ng-container>
    

    Notice that without an explicit subscription in the template, you no longer need to manage unsubscribing, so you no longer need the Subject, nor ngOnDestroy. If you initialize the data$ when you declare it, you also don’t need ngOnInit.


    Also, if you do decide you need some explicit subscriptions (usually in components this is not necessary), you can leverage the new takeUntilDestroyed() operator:

    private sub = this.dashboardService.getData().pipe(takeUntilDestroyed()).subscribe(
       data => this.data = data
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search