Je travaille sur une application Angular 4, mais j'ai un problème dans la mesure où je dois appeler this.changeDetectorRef.detectChanges();
pour mettre à jour la vue lorsque le modèle change. Par exemple, J'ai ce code qui est pour la pagination:
changePage(pageNumber) {
this.currentPage = pageNumber;
// why do I need to do this?
this.changeDetectorRef.detectChanges();
}
J'ai explicitement défini la stratégie de détection des modifications sur le composant sur ChangeDetectionStrategy.Default
mais cela n'a aucun effet. Cela se produit ici aussi lors de la souscription à un observable:
showResults(preference) {
this.apiService.get('dining_autocomplete/', `?search=${preference}`)
.subscribe((results) => {
this.searchResults = results;
// why do I need to do this?
this.changeDetectorRef.detectChanges();
});
}
Si je console.log()
this.searchResults
dans le TypeScript, j'obtiens les résultats attendus, mais si j'utilise {{ searchResults }}
dans le HTML, il ne se met pas à jour jusqu'à un autre événement arrive, probablement quand il passe par un autre cycle de digestion.
Que pourrait-il se passer?
== EDIT ================================================ ============
Le code de mon composant ressemble à ceci:
import {ChangeDetectorRef, Component, Input, OnChanges} from "@angular/core";
import * as _ from 'lodash';
@Component({
selector: 'dining-search-results',
templateUrl: './dining-search-results.template.html',
styleUrls: ['./dining-search-results.style.scss'],
})
export class DiningSearchResultsComponent {
@Input() searchResults: any[];
@Input() hotTablesOnly: boolean = false;
@Input() memberBenefitsOnly: boolean = false;
numberOfTagsToDisplay: number = 3;
resultsPerPage: number = 5;
currentPage: number = 1;
constructor(private changeDetectorRef: ChangeDetectorRef) {
}
get filteredResults() {
return this.searchResults ?
this.searchResults.filter((r) => !((this.hotTablesOnly && !r.has_hot_table)
|| (this.memberBenefitsOnly && !r.has_member_benefit))) : [];
}
get pagedResults() {
return _.chain(this.filteredResults)
.drop(this.resultsPerPage * (this.currentPage - 1))
.take(this.resultsPerPage)
.value();
}
get totalPages(): number {
return Math.ceil(this.filteredResults.length / this.resultsPerPage);
}
getInitialTags(tagsArray: any[], count: number): any[] {
return _.take(tagsArray, count);
}
changePage(pageNumber) {
this.currentPage = pageNumber;
// why do I need to do this?
this.changeDetectorRef.detectChanges();
}
}
Lorsque changePage()
est appelé et this.currentPage
est mis à jour, les modifications ne sont pas reflétées dans le code HTML sauf si j'appelle detectChanges()
.
J'ai résolu le problème.
Un autre composant envoyant des notifications à ce composant exécutait Observable.fromEvent()
en dehors de la zone Angular, donc la détection des modifications ne se produisait pas automatiquement en réponse à ces événements. Ce message sur zones et ce post StackOverflow sur la question a tenu la solution!
Vous pouvez entrer votre searchResults
dans les composants enfants
@Input() searchResults;
après cela, vous le passez à travers le modèle parent
// parent template
<app-child [searchResults]="searchResults"></app-child>
vous pouvez l'utiliser dans le modèle enfant
// child template
<my-date-picker [ngModel]="searchResults"></my-date-picker>
après cela, vous pouvez "écouter" les modifications de cette propriété dans le composant enfant
export class ChildComponent implements OnChanges {
@Input() searchResults;
constructor() { }
ngOnChanges() {
// some code
}
Chaque fois que searchResults
est modifié, les modifications seront renseignées dans le composant enfant, les valeurs dans le modèle enfant obtiendront la nouvelle valeur.