Change detection
The *ngIf="(obs | async)" problem is one way to detect changes. The obs variable itself does not change when the radiation, in combination with the fact that this expression is in the template, makes it difficult to detect changes for detection.
In this scenario, there are a few principles to consider:
The observed variables are "pipes", i.e. wrappers for values ​​passing through them, not the changing values ​​themselves. These two are often equated, but it looks like the elements of an array and an array are the same thing.
RxJs is an "external" (non-w500>) library. In these libraries, we need to know if changes in the data processed by the library are visible on Angular change detection.
Fix for # 10165
<div style="background-color: green;" *ngIf="trigger">{{(val1 | async)}}</div> <div style="background-color: green;" *ngIf="!trigger">{{(val2 | async)}}</div> ngOnInit() { this.trigger = this.ifObservable.subscribe(); }
Work with asynchronous data
In the broader issue of “observable everywhere,” you are perfectly correct, but is it not a problem inherent in the asynchronous nature of web applications?
It would be interesting to compare your old AngularJS code with the new Angular code. Is there an increase in complexity for the same feature set?
The principle that I would like to apply is to process “one-time” observables, such as http.get , by subscribing to them, and to keep “multi-capture” observables connected via asynchronous channels.
Onpush
This is, in fact, a way to dial the amount of automatic change detection, and therefore speed up the application. Of course, this means that you may have to exchange detection of fire changes more often - a compromise between speed and compromise.
Redux
While Redux repositories typically display state as observable (so you still need an asynchronous channel in the template), it eliminates the complexity around multiple update points, which may mean that less observables are required (or at least observables are abstracted from components).
The only shade of Redux that I looked at that does not include deasynchronous data in the template is Mobex , which essentially converts simple variables into objects with getters and setters that contain logic for viewing asynchronous changes and deploying them. But it has problems / caveats with arrays.
Simplification of the template
One way that you could simplify the pattern you showed (I have not tested this) is to wrap it in a child component and pass the expanded values
<nav aria-label="Pagination" class="mt-5" *ngIf="items.length"> <ul class="pagination"> <li class="page-item" [class.disabled]="currentPage === 1"> <a class="page-link" [routerLink]="" [queryParams]="{ page: currentPage - 1 }" queryParamsHandling="merge">Previous</a> </li> <li *ngFor="let page of pages" class="page-item" [class.active]="page === currentPage"> <a class="page-link app-page-number" [routerLink]="" [queryParams]="{ page: page }" queryParamsHandling="merge">{{ page }} <span class="sr-only" *ngIf="page === currentPage">(current)</span></a> </li> <li class="page-item" [class.disabled]="currentPage === lastPage"> <a class="page-link" [routerLink]="" [queryParams]="{ page: currentPage + 1 }" queryParamsHandling="merge">Next</a> </li> </ul> </nav> export class PageComponent { @Input() currentPage = 0; @Input() pages = []; @Input() items = [];
and in the parent,
<page-component [pages]="pages$ | async" [items]="items$ | async" [currentPage]="currentPage$ | async" >
By default, @Input connects to change detection even with the onPush strategy.
Be careful to give child values ​​default values.