I'm trying to send the result of HttpClient
post
requests multiple components in my Angular app. I'm using a Subject
and calling its next()
method whenever a new post
request is successfully executed. Each component subscribes to the service's Subject
.
The faulty services is defined as
@Injectable()
export class BuildingDataService {
public response: Subject<object> = new Subject<object>();
constructor (private http: HttpClient) { }
fetchBuildingData(location) {
...
this.http.post(url, location, httpOptions).subscribe(resp => {
this.response.next(resp);
});
}
The components subscribe to BuildingService.response
as follows
@Component({
template: "<h1>{{buildingName}}</h1>"
...
})
export class SidepanelComponent implements OnInit {
buildingName: string;
constructor(private buildingDataService: BuildingDataService) { }
ngOnInit() {
this.buildingDataService.response.subscribe(resp => {
this.buildingName = resp['buildingName'];
});
}
updateBuildingInfo(location) {
this.buildingDataService.fetchBuildingData(location);
}
}
updateBuildingInfo
is triggered by users clicking on a map.
Retrieving the data from the server and passing it to the components works: I can output the payloads to the console in each component. However, the components' templates fail to update.
After Googling and fiddling for most of today I found that this implementation does not trigger Angular's change detection. The fix is to either
- wrap my call to
next()
in the service inNgZone.run(() => { this.response.next(resp); }
- call
ApplicationRef.tick()
afterthis.title = resp['title']
in the component.
Both solutions feel like dirty hacks for such a trivial use case. There must be a better way to achieve this.
My question therefore is: what is the proper way to fetch data once and send it off to several components?
I'd furthermore like to understand why my implementation escapes Angular's change detection system.
EDIT it turns out I was initiating my call to HttpClient
outside of Angular's zone hence it could not detect my changes, see my answer for more details.