0

I’m working on an Angular v15+ app that uses a custom slideout panel system for showing forms. We’re trying to show an “unsaved changes” confirmation popup when the user closes the slideout, similar to how it works when navigating away from a routed page.

Works fine when loaded via route When the form is opened via a normal route like: /project/ba/questionnaire/:taskId/:id

We have this route setup:

{ path: 'branch-audit/questionnaire/:taskId/:id', component: ConfigurationQuestionnaireFormComponent, canDeactivate: [UnsavedChangesGuard], } 

And inside the component:

canDeactivate(): boolean | Observable<boolean> { if (this.hasUnsavedChanges) { const dialogRef = this.dialog.open(ConfirmationDialogComponent, { width: '39.375rem', data: { title: 'Warning', message: 'You have unsaved changes...', btnOK: 'Proceed Anyway', }, }); return dialogRef.afterClosed().pipe(map(result => !!result?.submit)); } return true; } 

This works perfectly when navigating away via router links or browser refresh. The browser beforeunload handler also works fine.

Issue: Doesn’t work when form is opened inside a slideout panel When the same form is opened from a slideout, it doesn’t trigger the confirmation popup.

Example of the slideout URL:

https://localhost:8186/project/ba/task/list?slidePanel=configuration%2Fbranch-audit%2Fquestionnaire%2FeyJ0YXNrSWQiOiIxNjg1YWM3Yi0wMWIzLWYwMTEtYWNmNy0xMjEzM2MyNDVjNzMiLCJpZCI6IjI5ODVhYzdiLTAxYjMtZjAxMS1hY2Y3LTEyMTMzYzI0 

Our slideout config:

[SLIDE_PANEL_URLS.AuditQuestionnaireResponseSubmission]: { component: ConfigurationQuestionnaireFormComponent, regex: new RegExp('/project/ba/task/list/([A-Za-z0-9-]+)', 'i'), defaultBaseUrl: ['project', 'b', 'a', 'task', 'list'], slidePanelUrl: SLIDE_PANEL_URLS.AuditQuestionnaireResponseSubmission, params: ['id', 'taskId'] } 

What I Tried

Since canDeactivate guards don’t apply to non-routed components, I manually tried intercepting the slideout close:

ngOnInit(): void { const originalClose = this.slideOutService.close.bind(this.slideOutService); this.slideOutService.close = (data?: any) => { if (this.hasUnsavedChanges) { const dialogRef = this.dialog.open(ConfirmationDialogComponent, { width: '39.375rem', data: { title: 'Warning', message: 'You have not saved your changes...', btnOK: 'Proceed Anyway', }, }); return new Promise<boolean>((resolve) => { dialogRef.afterClosed().subscribe(result => { if (result?.submit) { this.hasUnsavedChanges = false; resolve(originalClose(data) ?? true); } else { resolve(false); } }); }); } return originalClose(data); }; } 

But when closing the slideout:

  • The dialog flashes briefly or doesn’t appear at all.
  • The slideout closes immediately (component gets destroyed too fast).
  • No way to “block” the close until user responds.

Slideout Flow (simplified) Our slideOutService handles state manually:

close(slideOutData?: any): Promise<boolean> | null { const latestState = this._state.pop(); const navigate = this.router.navigate([...]); // removes query param this.state$.next(this._state); if (this._afterClosed && slideOutData) { this._afterClosed.next(slideOutData); this._afterClosed.complete(); } return navigate; } afterClosed(): Observable<ISlideOutData | null> { return this._afterClosed; } 

There’s no beforeClose$ hook, so I tried wrapping close() but couldn’t prevent it from destroying the component immediately.

Question What’s the best way to add a canDeactivate like confirmation for a component rendered inside a custom slideout panel (not via routing)?

Has anyone successfully delayed or intercepted the slideout close action to wait for user confirmation before destruction?

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.