Ich habe eine übergeordnete Komponente, die ein Array von Objekten mithilfe einer Ajax-Anforderung abruft.
Diese Komponente hat zwei untergeordnete Komponenten: Eine zeigt die Objekte in einer Baumstruktur und die andere rendert ihren Inhalt in einem Tabellenformat. Das übergeordnete Element übergibt das Array über eine @ input-Eigenschaft an seine untergeordneten Elemente und zeigt den Inhalt ordnungsgemäß an. Alles wie erwartet.
Das Problem tritt auf, wenn Sie ein Feld innerhalb der Objekte ändern: Die untergeordneten Komponenten werden nicht über diese Änderungen benachrichtigt. Änderungen werden nur ausgelöst, wenn Sie das Array manuell seiner Variablen zuweisen.
Ich bin es gewohnt, mit Knockout JS zu arbeiten, und ich muss einen ähnlichen Effekt erzielen wie ObservableArrays.
Ich habe etwas über DoCheck gelesen, bin mir aber nicht sicher, wie es funktioniert.
quelle
Antworten:
OnChanges
Der Lifecycle Hook wird nur ausgelöst, wenn sich die Instanz der Eingabeeigenschaft ändert.Wenn Sie überprüfen möchten, ob ein Element im Eingabearray hinzugefügt, verschoben oder entfernt wurde, können Sie IterableDiffers im
DoCheck
Lifecycle Hook wie folgt verwenden:constructor(private iterableDiffers: IterableDiffers) { this.iterableDiffer = iterableDiffers.find([]).create(null); } ngDoCheck() { let changes = this.iterableDiffer.diff(this.inputArray); if (changes) { console.log('Changes detected!'); } }
Wenn Sie Änderungen an Objekten in einem Array erkennen müssen, müssen Sie alle Elemente durchlaufen und KeyValueDiffers für jedes Element anwenden . (Sie können dies parallel zur vorherigen Prüfung tun).
Weitere Informationen finden Sie in diesem Beitrag: Erkennen Sie Änderungen an Objekten innerhalb des Arrays in Angular2
quelle
diff
Methode wurde umbenannt infind
: angular.io/api/core/IterableDiffersIterableDiffers
, nicht auf dieIterableDiffer
Schnittstelle. Bitte überprüfen Sie: angle.io/api/core/IterableDifferiterableDiffer:IterableDiffer<YourSingleItemType>;
ngDoCheck
ist teuer für Ressourcen, da ich es mit der Suchmethode verwendet habe, aber die Art und Weise, wie @SeidMehmedovic es tat, ist die beste für die Leistung. Daumen hochSie können jederzeit einen neuen Verweis auf das Array erstellen, indem Sie ihn mit einem leeren Array zusammenführen:
this.yourArray = [{...}, {...}, {...}]; this.yourArray[0].yourModifiedField = "whatever"; this.yourArray = [].concat(this.yourArray);
Der obige Code ändert die Array-Referenz und löst den OnChanges-Mechanismus in untergeordneten Komponenten aus.
quelle
Lesen Sie den folgenden Artikel und verpassen Sie keine veränderlichen oder unveränderlichen Objekte.
Das Hauptproblem besteht darin, dass Sie Array-Elemente mutieren, während die Array-Referenz gleich bleibt. Die Angular2-Änderungserkennung überprüft nur die Array-Referenz, um Änderungen zu erkennen. Nachdem Sie das Konzept unveränderlicher Objekte verstanden haben, werden Sie verstehen, warum Sie ein Problem haben und wie Sie es lösen können.
Ich verwende den Redux Store in einem meiner Projekte, um solche Probleme zu vermeiden.
https://blog.ehowtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
quelle
Sie können IterableDiffers verwenden
Es wird von * ngFor verwendet
constructor(private _differs: IterableDiffers) {} ngOnChanges(changes: SimpleChanges): void { if (!this._differ && value) { this._differ = this._differs.find(value).create(this.ngForTrackBy); } } ngDoCheck(): void { if (this._differ) { const changes = this._differ.diff(this.ngForOf); if (changes) this._applyChanges(changes); } }
quelle
Dies erscheint bereits beantwortet. Für zukünftige Problem-Suchende wollte ich jedoch etwas hinzufügen, das bei der Untersuchung und Fehlerbehebung eines Problems zur Änderungserkennung, das ich hatte, übersehen wurde. Jetzt war mein Problem ein wenig isoliert und zugegebenermaßen ein dummer Fehler für mich, aber dennoch relevant. Stellen Sie beim Aktualisieren der Werte in
Array
oderObject
in der Referenz sicher, dass Sie sich im richtigen Bereich befinden. Ich habe mich in eine Falle gestellt, indem ich verwendet habesetInterval(myService.function, 1000)
,myService.function()
um die Werte eines öffentlichen Arrays zu aktualisieren, das ich außerhalb des Dienstes verwendet habe. Dadurch wurde das Array nie aktualisiert, da die Bindung deaktiviert war und die korrekte Verwendung hätte erfolgen müssensetInterval(myService.function.bind(this), 1000)
. Ich habe meine Zeit damit verschwendet, Änderungserkennungs-Hacks zu versuchen, als es ein dummer / einfacher Fehler war. Beseitigen Sie den Umfang als Schuldigen, bevor Sie Lösungen zur Änderungserkennung ausprobieren. es könnte Ihnen einige Zeit sparen.quelle
Sie können ein unreines Rohr verwenden, wenn Sie das Array in Ihrer Komponentenvorlage direkt verwenden. (Dieses Beispiel ist für einfache Arrays gedacht, für die keine eingehende Prüfung erforderlich ist.)
@Pipe({ name: 'arrayChangeDetector', pure: false }) export class ArrayChangeDetectorPipe implements PipeTransform { private differ: IterableDiffer<any>; constructor(iDiff: IterableDiffers) { this.differ = iDiff.find([]).create(); } transform(value: any[]): any[] { if (this.differ.diff(value)) { return [...value]; } return value; } }
<cmp [items]="arrayInput | arrayChangeDetector"></cmp>
Für diejenigen Zeitreisenden unter uns, die immer noch auf Array-Probleme stoßen, gibt es hier eine Reproduktion des Problems zusammen mit mehreren möglichen Lösungen.
https://stackblitz.com/edit/array-value-changes-not-detected-ang-8
Lösungen umfassen:
quelle
Es ist Arbeit für mich:
@Component({ selector: 'my-component', templateUrl: './my-component.component.html', styleUrls: ['./my-component.component.scss'] }) export class MyComponent implements DoCheck { @Input() changeArray: MyClassArray[]= []; private differ: IterableDiffers; constructor(private differs: IterableDiffers) { this.differ = differs; } ngDoCheck() { const changes = this.differ.find(this.insertedTasks); if (changes) { this.myMethodAfterChange(); } }
quelle
changes
immer festgelegt ist - was bedeutet, dass Sie sie einfach imthis.myMethodAfterChange();
Inneren tun könnenngDoCheck
. Dies würde funktionieren, aber ein Leistungsproblem verursachen.