Ваша проблема
Требуется многоразовый способ запроса пользователей перед переходом от компонента, содержащего грязную форму.
Требования:
- Нет запросить, если форма чиста
- Если пользователь хочет выйти, навигация продолжится
- Если пользователь не хочет выйти, навигация будет отменена
Ваше существующее решение
Как только я потратил немного времени на понимание вашего решения, я вижу, что это элегантный способ работы с несколькими компонентами.
Ваш дизайн примерно такой:
export abstract class ComponentCanDeactive {
abstract canDeactivate(): boolean;
}
export abstract class FormCanDeactivate extends ComponentCanDeactivate {
abstract get form(): NgForm;
canDeactivate(): boolean {
return this.form.submitted || !this.form.dirty;
}
}
Если вы хотите применить это к компоненту, вы просто расширяете класс FormCanDeactivate
.
Вы реализуете его, используя Angular CanDeactivate
охранник маршрута.
export class CanDeactivateGuard implements CanDeactivate<ComponentCanDeactivate> {
canDeactivate(component: ComponentCanDeactivate): boolean {
return component.canDeactivate();
}
}
Вы добавляете это к соответствующим маршрутам в вашем маршруте. Я предполагаю, что вы понимаете, как все это работает, поскольку вы предоставили код и демонстрационную версию для него.
Если вы просто хотите предотвратить деактивацию маршрута, когда компонент имеет грязную форму, вы уже решили проблему.
Использование диалогового окна
Теперь вы хотите дать пользователю выбор, прежде чем он уйдет от грязной формы. Вы реализовали это с синхронным javascript confirm
, но вы хотите использовать диалоговое окно Angular Material, которое является асинхронным.
Решение
Во-первых, так как вы собираетесь используйте это асинхронно, вам нужно вернуть асинхронный тип из вашей охраны. Вы можете вернуть либо Promise
, либо Observable
. Диалог Angular Material возвращает Observable
, поэтому я буду его использовать.
Теперь это просто случай настройки диалога и возврата наблюдаемой функции закрытия.
deactivate- guard.ts
constructor(private modalService: MatDialog) {}
canDeactivate(component: ComponentCanDeactivate): Observable<boolean> {
// component doesn't require a dialog - return observable true
if (component.canDeactivate()) {
return of(true);
}
// set up the dialog
const dialogRef = this.modalService.open(YesNoComponent, {
width: '600px',
height: '250px',
});
// return the observable from the dialog
return dialogRef.afterClosed().pipe(
// map the dialog result to a true/false indicating whether
// the route can deactivate
map(result => result === true)
);
}
Где YesNoComponent
- это настраиваемый компонент диалога, созданный вами как оболочка для диалогового окна.
export class YesNoComponent {
constructor(private dialogRef: MatDialogRef<YesNoComponent> ) { }
Ok(){
this.dialogRef.close(true);
}
No(){
this.dialogRef.close(false);
}
}
DEMO: https://stackblitz.com/edit/angular-custom-popup-candeactivate-mp1ndw