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
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 theChangeDetectionRef
:And then:
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.
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:
Notice that without an explicit subscription in the template, you no longer need to manage unsubscribing, so you no longer need the
Subject
, norngOnDestroy
. If you initialize thedata$
when you declare it, you also don’t needngOnInit
.Also, if you do decide you need some explicit subscriptions (usually in components this is not necessary), you can leverage the new
takeUntilDestroyed()
operator: