Spartacus中表单未提交时路由跳转弹窗实现方案咨询
在Spartacus中实现表单未提交时路由跳转触发确认弹窗
问题说明
需要在带有表单的Spartacus页面中实现:当用户未提交表单(表单处于脏状态)并尝试跳转至其他路由时,弹出确认弹窗提示数据可能丢失,确认后才允许离开页面。
现有方案的局限性
常规Angular Deactivate Guard:
该方式需要自定义路由配置,会忽略Commerce后台提供的页面布局,导致Spartacus默认的页眉、页脚等全局组件无法正常渲染,且Spartacus不支持为单个组件添加Deactivate Guard。
示例代码(不适用于Spartacus):RouterModule.forChild([ { path: 'xyz', component: XYZComponent, canDeactivate: mapToCanDeactivate([XYZDeactivateGuard]), }, ])window:beforeunload 事件:
仅在页面刷新或关闭浏览器时触发,无法拦截Spartacus应用内的路由跳转行为。
示例代码:@HostListener('window:beforeunload', ['$event']) check($event: any) { if (this.formDirty) { $event.returnValue = 'Your data will be lost!'; } }
适配Spartacus的可行方案
通过监听Angular路由的NavigationStart事件,结合表单脏状态判断,实现路由跳转前的确认拦截,完全兼容Spartacus的后台布局:
实现代码
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router, NavigationStart } from '@angular/router'; import { FormGroup, FormBuilder } from '@angular/forms'; import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; @Component({ selector: 'app-custom-form-page', templateUrl: './custom-form-page.component.html', }) export class CustomFormPageComponent implements OnInit, OnDestroy { form: FormGroup; isFormDirty = false; private navSubscription: Subscription | null = null; private pendingNavigationUrl: string | null = null; constructor( private fb: FormBuilder, private router: Router ) { // 初始化表单 this.form = this.fb.group({ fullName: [''], contactEmail: [''], message: [''] }); // 监听表单脏状态变化 this.form.valueChanges.subscribe(() => { this.isFormDirty = this.form.dirty; }); } ngOnInit(): void { // 订阅路由导航开始事件 this.navSubscription = this.router.events.pipe( filter(event => event instanceof NavigationStart) ).subscribe((event: NavigationStart) => { if (this.isFormDirty && !this.pendingNavigationUrl) { // 临时阻止路由跳转,避免浏览器历史记录异常 this.router.navigate([], { skipLocationChange: true }).then(() => { this.pendingNavigationUrl = event.url; // 弹出原生确认弹窗(也可替换为Spartacus的Dialog组件) const confirmLeave = confirm('你输入的数据尚未保存,确定要离开当前页面吗?'); if (confirmLeave) { // 用户确认离开,执行跳转 this.router.navigateByUrl(this.pendingNavigationUrl!); this.form.markAsPristine(); this.isFormDirty = false; } this.pendingNavigationUrl = null; }); } }); } ngOnDestroy(): void { // 销毁订阅,避免内存泄漏 if (this.navSubscription) { this.navSubscription.unsubscribe(); } } onFormSubmit(): void { // 表单提交逻辑 if (this.form.valid) { // ...执行提交操作(调用Spartacus的Commerce API等) this.form.markAsPristine(); this.isFormDirty = false; } } }
关键说明
- 无需自定义路由,完全保留Commerce后台提供的页面布局,页眉页脚可正常显示
- 通过
skipLocationChange: true临时阻止路由变化,避免浏览器历史记录出现无效条目 - 表单提交后调用
markAsPristine()重置脏状态,防止提交后仍触发确认弹窗 - 可将原生
confirm替换为Spartacus的DialogService,实现风格统一的弹窗
内容的提问来源于stack exchange,提问作者Vlasto
相关产品推荐
相关产品推荐

