Ich habe eine Liste von Objekten. Der Benutzer kann auf einen klicken, der dann eine untergeordnete Komponente lädt, um diese Komponente zu bearbeiten.Angular4 - wie sicherzustellen, dass ngOnDestroy endet, bevor Sie weg navigieren
Das Problem, das ich habe, ist, dass, wenn der Benutzer zurück zu der Liste Komponente, die Kind-Komponente muss einige Aufräumarbeiten in der ngOnDestroy-Methode - die einen Aufruf an den Server, um eine abschließende "Patch" der machen müssen Objekt. Manchmal kann diese Verarbeitung etwas langsam sein.
Natürlich passiert, der Benutzer kommt zurück auf der Liste, und dieser API-Aufruf wird abgeschlossen, bevor die Datenbanktransaktion von ngOnDestroy
abgeschlossen ist, und somit der Benutzer veraltete Daten sieht.
ngOnDestroy(){
this.destroy$.next();
this.template.template_items.forEach((item, index) => {
// mark uncompleted items for deletion
if (!item.is_completed) {
this.template.template_items[index]['_destroy'] = true;
};
});
// NOTE
// We don't care about result, this is a 'silent' save to remove empty items,
// but also to ensure the final sorted order is saved to the server
this._templateService.patchTemplate(this.template).subscribe();
this._templateService.selectedTemplate = null;
}
Ich verstehe, dass synchrone Anrufe nicht zu tun ist, da es die Benutzeroberfläche/den gesamten Browser blockiert, was nicht toll ist.
Ich bin sicher, es gibt mehrere Möglichkeiten, dies zu lösen, aber wirklich nicht wissen, welche die beste ist (vor allem, da Angular keine Sync-Anfragen unterstützt, so würde ich auf Standard-Ajax zurückgreifen müssen).
Eine Idee, die ich dachte, war, dass die ngOnDestroy einen "Marker" an die API übergeben konnte, und es könnte dann dieses Objekt als "Verarbeitung" markieren. Wenn die Listenkomponente seinen Aufruf des Fall ist, könnte es jedes Objekt untersuchen, um zu sehen, ob es diesen Marker hat und zeigt eine Taste in diesem Zustand für jedes Objekt ‚veraltete Daten aktualisieren‘ (die 99% der Zeit nur ein einzelne Element ohnehin wäre, der letzte, den der Benutzer bearbeitet hat). Scheint ein bisschen eine Mist Workaround und erfordert eine Tonne zusätzlichen Code im Vergleich zu nur einen asynchronen Anruf zu einem Synchronisierungsanruf ändern.
Andere haben müssen ähnliche Probleme auftreten, aber ich kann keine klare Beispiele außer this sync one zu finden scheinen.
EDIT
Beachten Sie, dass dieses Kind Komponente bereits eine CanDeactive Wache auf sie. Er fordert den Benutzer auf, zu bestätigen (dh Änderungen zu verwerfen). Wenn sie zum Bestätigen klicken, wird dieser Bereinigungscode in ngOnDestroy ausgeführt. Beachten Sie jedoch, dass dies keine typische eckige Form ist, bei der der Benutzer Änderungen wirklich "verwirft". Bevor diese Seite verlassen wird, muss der Server eine gewisse Verarbeitung der endgültigen Datenmenge vornehmen. Im Idealfall möchte ich nicht, dass der Benutzer verlässt, bis ngOnDestroy fertig ist - wie kann ich es zwingen, zu warten, bis dieser API-Aufruf beendet ist?
Mein CanDeactive-Wächter ist fast genauso implementiert wie in der official docs für die Hero-App, indem er sich in einen allgemeinen Dialogdienst einklinkt, der den Benutzer auffordert, auf der Seite zu bleiben oder fortzufahren. Hier ist sie:
canDeactivate(): Observable<boolean> | boolean {
console.log('deactivating');
if (this.template.template_items.filter((obj) => { return !obj.is_completed}).length < 2)
return true;
// Otherwise ask the user with the dialog service and return its
// observable which resolves to true or false when the user decides
return this._dialogService.confirm('You have some empty items. Is it OK if I delete them?');
}
Die docs machen es nicht für meine Situation klar aber - auch wenn ich meine Bereinigungscode bewegen sich von ngOnDestroy zu einem „JA“ Methodenhandler zum Dialog, es hat immer noch die api anrufen , also würde der YES-Handler immer noch vervollständigen, bevor die API es getan hat und ich bin mit dem gleichen Problem zurück.
UPDATE
Nachdem alle Kommentare lesen Ich vermute, die Lösung so etwas wie dieses.Ändern Sie die Wache aus:
return this._dialogService.confirm('You have some empty items.
Is it OK if I delete them?');
zu
return this._dialogService.confirm('You have some empty items.
Is it OK if I delete them?').subscribe(result => {
...if yes then call my api and return true...
...if no return false...
});
Schauen Sie sich CanDeactivate oder Wächter im Allgemeinen an, siehe [hier] (https://stackoverflow.com/questions/41148020/angular2-candeactivate-guard) zum Beispiel. – Matt
Danke, das ist nicht die Lösung. Ich werde die Frage aktualisieren, um zu erklären, warum. – rmcsharry
@rmcsharry das ist eine Lösung. Ihre Benutzerbestätigung in 'CanDeactivate' ist keine Lösung. –