#angular #rxjs
Вопрос:
У меня есть простая угловая форма 11 (в компоненте), которая автоматически сохраняется. Однако сохранение наблюдаемого отменяется, когда пользователь переходит из формы. Есть ли способ позволить пользователю уйти от формы, но разрешить сохранение для завершения (а затем отказаться от подписки на наблюдаемое по завершении)?
Идея 1: Используйте эффекты NgRx. Я не вижу никакой причины, по которой это технически не сработало бы. Но мне кажется, что для решения этой проблемы требуется много сантехники. В настоящее время компонент очень прост и полностью самодостаточен.
Идея 2: Используйте угловую защиту canDeactivate. Запросите пользователя, если он хочет потерять изменения. Пользовательский интерфейс кажется неправильным. К тому времени, когда пользователь нажимает «Да», чтобы потерять изменения, выполняемое сохранение, вероятно, уже завершено и данные сохранены.
private unsubscribe = new Subject<void>();
ngOnInit() {
this.form = this.formBuilder.group({
myField1: [''],
myField2: [''],
myField3: [''],
});
this.form.valueChanges.pipe(
switchMap(formValue => this.save(formValue)),
takeUntil(this.unsubscribe)
).subscribe();
}
private save(formValue: any): Observable<any> {
return this.form.valid ? saveData(formValue) : of(null;
}
ngOnDestroy() {
this.unsubscribe.next();
}
Ответ №1:
Я думаю, что этот вариант использования действительно был бы достаточно хорошо обработан с точки зрения эффекта.
Отправка действия выполняется синхронно, поэтому после отправки действия вам больше не нужно беспокоиться о том, что наблюдаемое будет закрыто, когда компонент будет уничтожен.
Тем не менее, для объяснения некоторых RXJ, если бы вы хотели сделать это из своего компонента, вы могли бы сделать следующее:
const formUpdate$ = this.form.valueChanges;
const savingForm$ = formUpdate$.pipe(
switchMap((formValue) => this.save(formValue)),
shareReplay({ bufferSize: 1, refCount: true })
);
const isSavingForm$ = formUpdate$.pipe(
switchMap(() => concat(of(true), savingForm$.pipe(take(1), mapTo(false)))),
shareReplay({ bufferSize: 1, refCount: true })
);
const unsubscribeAfterPendingFormSaved$ = combineLatest([
this.onDestroy$,
isSavingForm$,
]).pipe(
switchMap(([_, isSavingForm]) => {
if (isSavingForm) {
return EMPTY;
}
return true;
}),
take(1)
);
savingForm$.pipe(takeUntil(unsubscribeAfterPendingFormSaved$));