Ich weiß, dass ich nicht der erste bin, der danach fragt, aber ich kann in den vorherigen Fragen keine Antwort finden. Ich habe dies in einer Komponente
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
In der Steuerung rawLapsdata
wird von Zeit zu Zeit mutiert.
In laps
werden die Daten als HTML in einem Tabellenformat ausgegeben. Dies ändert sich bei jeder rawLapsdata
Änderung.
Meine map
Komponente muss ngOnChanges
als Auslöser zum Neuzeichnen von Markierungen auf einer Google Map verwendet werden. Das Problem ist, dass ngOnChanges bei rawLapsData
Änderungen im übergeordneten Element nicht ausgelöst wird. Was kann ich tun?
import {Component, Input, OnInit, OnChanges, SimpleChange} from 'angular2/core';
@Component({
selector: 'map',
templateUrl: './components/edMap/edMap.html',
styleUrls: ['./components/edMap/edMap.css']
})
export class MapCmp implements OnInit, OnChanges {
@Input() lapsData: any;
map: google.maps.Map;
ngOnInit() {
...
}
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
console.log('ngOnChanges = ', changes['lapsData']);
if (this.map) this.drawMarkers();
}
Update: ngOnChanges funktioniert nicht, aber es sieht so aus, als würde lapsData aktualisiert. In ngInit befindet sich ein Ereignis-Listener für Zoomänderungen, der auch aufruft this.drawmarkers
. Wenn ich den Zoom ändere, sehe ich tatsächlich eine Änderung der Markierungen. Das einzige Problem ist also, dass ich zum Zeitpunkt der Änderung der Eingabedaten keine Benachrichtigung erhalte.
Im Elternteil habe ich diese Zeile. (Denken Sie daran, dass sich die Änderung in Runden widerspiegelt, jedoch nicht in der Karte.)
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
Beachten Sie, dass dies this.rawLapsData
selbst ein Zeiger auf die Mitte eines großen JSON-Objekts ist
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
zone.run(...)
sollte es dann tun.ngOnChanges()
nicht aufgerufen. Sie könnenngDoCheck()
Ihre eigene Logik verwenden und implementieren, um festzustellen, ob sich der Array-Inhalt geändert hat.lapsData
wird aktualisiert, weil es einen Verweis auf dasselbe Array wie hat / istrawLapsData
.Antworten:
rawLapsData
zeigt weiterhin auf dasselbe Array, auch wenn Sie den Inhalt des Arrays ändern (z. B. Elemente hinzufügen, Elemente entfernen, ein Element ändern).Wenn Angular während der Änderungserkennung die Eingabeeigenschaften der Komponenten auf Änderungen überprüft, wird (im Wesentlichen) die
===
Schmutzprüfung verwendet. Für Arrays bedeutet dies, dass die Array-Referenzen (nur) verschmutzt sind. Da sich dierawLapsData
Array-Referenz nicht ändert,ngOnChanges()
wird sie nicht aufgerufen.Ich kann mir zwei mögliche Lösungen vorstellen:
Implementieren Sie
ngDoCheck()
Ihre eigene Änderungserkennungslogik und führen Sie sie aus, um festzustellen, ob sich der Array-Inhalt geändert hat. (Das Lifecycle Hooks-Dokument enthält ein Beispiel .)Weisen Sie ein neues Array zu,
rawLapsData
wenn Sie Änderungen am Array-Inhalt vornehmen. DannngOnChanges()
wird aufgerufen, da das Array (Referenz) als Änderung angezeigt wird.In Ihrer Antwort haben Sie eine andere Lösung gefunden.
Wiederholen Sie einige Kommentare hier zum OP:
laps
Komponente durchläuft Ihr Code / Ihre Vorlage jeden Eintrag imlapsData
Array und zeigt den Inhalt an, sodass für jedes angezeigte Datenelement Winkelbindungen vorhanden sind.===
Überprüfung), werden alle Vorlagenbindungen (standardmäßig) überprüft. Wenn sich eine dieser Änderungen ändert, aktualisiert Angular das DOM. Das sehen Sie.maps
Komponente hat wahrscheinlich keine Bindungen in ihrer Vorlage zu ihrerlapsData
Eingabeeigenschaft, oder? Das würde den Unterschied erklären.Beachten Sie, dass
lapsData
in beiden Komponenten undrawLapsData
in der übergeordneten Komponente alle auf dasselbe / ein Array verweisen. Obwohl Angular keine (Referenz-) Änderungen an denlapsData
Eingabeeigenschaften bemerkt , "erhalten" / sehen die Komponenten Änderungen des Array-Inhalts, da sie alle dieses eine Array gemeinsam nutzen / referenzieren. Wir brauchen Angular nicht, um diese Änderungen zu verbreiten, wie wir es bei einem primitiven Typ (Zeichenfolge, Zahl, Boolescher Wert) tun würden. Bei einem primitiven Typ würde jedoch jede Änderung des Werts immer ausgelöstngOnChanges()
- was Sie in Ihrer Antwort / Lösung ausnutzen.Wie Sie wahrscheinlich inzwischen herausgefunden haben, verhalten sich Objekteingabeeigenschaften genauso wie Array-Eingabeeigenschaften.
quelle
Nicht der sauberste Ansatz, aber Sie können das Objekt jedes Mal klonen, wenn Sie den Wert ändern?
Ich denke, ich würde diesen Ansatz der Implementierung Ihres eigenen vorziehen,
ngDoCheck()
aber vielleicht könnte sich jemand wie @ GünterZöchbauer einschalten.quelle
Bei Arrays können Sie dies folgendermaßen tun:
In der
.ts
Datei (übergeordnete Komponente), in der Sie Ihr Update durchführen,rawLapsData
gehen Sie wie folgt vor:Lösung:
und
ngOnChanges
wird in der untergeordneten Komponente aufgerufenquelle
Als Erweiterung von Mark Rajcoks zweiter Lösung
Sie können den Inhalt des Arrays folgendermaßen klonen:
Ich erwähne das, weil
hat bei mir nicht funktioniert. Ich hoffe das hilft.
quelle
Wenn die Daten aus einer externen Bibliothek stammen, müssen Sie möglicherweise die Anweisung data upate in ausführen
zone.run(...)
. Injizieren Siezone: NgZone
dafür. Wenn Sie die Instanziierung der externen Bibliothekzone.run()
bereits ausführen können , benötigen Sie diese möglicherweisezone.run()
später nicht mehr.quelle
$scope.$apply
?zone.run
ist ähnlich wie$scope.apply
.Verwenden
ChangeDetectorRef.detectChanges()
Sie diese Option, um Angular anzuweisen, eine Änderungserkennung auszuführen, wenn Sie ein verschachteltes Objekt bearbeiten (das bei der fehlerhaften Überprüfung fehlt).quelle
Ich habe 2 Lösungen, um Ihr Problem zu lösen
ngDoCheck
diese Option, umobject
geänderte oder nicht geänderte Daten zu erkennenobject
einer neuen Speicheradresse vonobject = Object.create(object)
der übergeordneten Komponente zu.quelle
Meine "Hack" -Lösung ist
selectedTps ändert sich gleichzeitig mit rawLapsData, und dies gibt map eine weitere Möglichkeit, die Änderung durch einen einfacheren primitiven
Objekttypzu erkennen . Es ist NICHT elegant, aber es funktioniert.quelle
Die Änderungserkennung wird nicht ausgelöst, wenn Sie eine Eigenschaft eines Objekts (einschließlich eines verschachtelten Objekts) ändern. Eine Lösung wäre, eine neue Objektreferenz mit der Funktion 'lodash' clone () neu zuzuweisen.
quelle
Hier ist ein Hack, der mich aus diesem Problem herausgeholt hat.
Ein ähnliches Szenario wie beim OP: Ich habe eine verschachtelte Angular-Komponente, an die Daten weitergegeben werden müssen, aber die Eingabe zeigt auf ein Array. Wie oben erwähnt, sieht Angular keine Änderung, da die nicht untersucht wird Inhalt des Arrays.
Um dies zu beheben, konvertiere ich das Array in eine Zeichenfolge, damit Angular eine Änderung erkennt, und teile dann in der verschachtelten Komponente die Zeichenfolge wieder in ein Array und seine glücklichen Tage auf (',').
quelle
Ich bin auf das gleiche Bedürfnis gestoßen. Und ich habe viel darüber gelesen, hier ist mein Kupfer zu diesem Thema.
Wenn Sie möchten, dass Ihre Änderungserkennung auf Push erfolgt, haben Sie sie dann, wenn Sie den Wert eines Objekts im Inneren ändern, oder? Und Sie hätten es auch, wenn Sie irgendwie Objekte entfernen würden.
Wie bereits erwähnt, verwenden Sie changeDetectionStrategy.onPush
Angenommen, Sie haben diese Komponente mit changeDetectionStrategy.onPush erstellt:
Dann würden Sie einen Artikel drücken und die Änderungserkennung auslösen:
oder Sie entfernen ein Element und lösen die Änderungserkennung aus:
oder Sie ändern einen Attributwert für ein Element und lösen die Änderungserkennung aus:
Inhalt der Aktualisierung:
Die Slice-Methode gibt genau dasselbe Array zurück, und das Zeichen [=] verweist neu darauf und löst die Änderungserkennung jedes Mal aus, wenn Sie sie benötigen. Einfach und lesbar :)
Grüße,
quelle
Ich habe alle hier genannten Lösungen ausprobiert, aber aus irgendeinem Grund
ngOnChanges()
immer noch nicht für mich ausgelöst. Also habe ich es mit aufgerufen,this.ngOnChanges()
nachdem ich den Dienst angerufen hatte, der meine Arrays neu bevölkert hat, und es hat funktioniert ... richtig? wahrscheinlich nicht. Ordentlich? Auf keinen Fall. Funktioniert? Ja!quelle
ok also meine lösung dafür war:
Und das löst mich ngOnChanges aus
quelle
Ich musste einen Hack dafür erstellen -
quelle
In meinem Fall waren es Änderungen des Objektwerts, die
ngOnChange
nicht erfasst wurden. Einige Objektwerte werden als Reaktion auf einen API-Aufruf geändert. Durch die Neuinitialisierung des Objekts wurde das Problem behoben und dasngOnChange
Auslösen in der untergeordneten Komponente verursacht.Etwas wie
quelle