在加入考试系统项目后,首先做的工作是添加操作提示框,本以为简单的工作,在使用时却出现了令人意想不到的错误。
背景
使用的模态框库为sweetalert2
,设计方法是在应用的根组件appComPonent
中使用模态框组件,appComPonent中暴露展示确认模态框的方法confirm,子组件通过注入appComPonent并调用confirm方法,通过传入回调函数,实现在子组件中展示模态框的功能。
// app.component.html
<swal #alert></swal>
<router-outlet></router-outlet>
// app.component.ts 中显示确认框的方法
@ViewChild('alert', {static: true})
public alert: SwalComponent;
confirm(callback?: () => void, description: string = '', title: string = '是否确认'): void {
/**
* 更新提示框信息
*/
this.alert.update({
titleText: title,
text: description,
icon: 'question',
background: '#F7F8FA',
allowOutsideClick: false,
confirmButtonText: '确定',
confirmButtonColor: '#007BFF',
showCancelButton: true,
cancelButtonText: '取消'
});
const result = this.alert.confirm.subscribe(() => {
// 执行回调
if (callback) {
callback();
}
// 取消订阅
result.unsubscribe();
});
/**
* 显示提示框
*/
this.alert.fire();
}
通过订阅模态框确认数据源(alert.confirm)来保证点击确认按钮时执行成功的回调函数。例如在子组件中使用示例:
// main.component.ts
constructor(private app: AppComponent,
private collegeService: CollegeService) {
}
delete(college: College): void {
// 确认框
this.app.confirm(() => {
this.collegeService.delete(college.id).subscribe(() => {
this.pageAll();
// 操作成功提示
this.app.success(() => {}, `成功删除${college.name}`);
}, () => {
// 操作失败提示
this.app.error(() => {}, '可能存在关联数据');
});
}, `即将删除学院信息:${college.name}`);
}
奇怪的现象
本着测试的原则,当按照之前的代码加入模态框,自己测试了以下,却出现了意想不到的事情:我点击删除,之后取消,进入编辑界面保存编辑后,回到首页却把数据给删除了。
回到代码,当我们展现删除提示框时,预约了模态框的确认(alert.confirm)数据源,来保证点击确定按钮时实现删除的操作,但是我却没点击确定,点击的是取消。此时确认数据源还在被我们预约着,在编辑页面点击了保存模态框的确定按钮后,由于使用的是都是根组件中的模态框实例,确认数据源被触发,从而执行我们之前预约的删除操作!
解决方法
解决方法1:
触发这奇怪现象的源头就是上一次预约确认数据源没有取消掉,把这个预约给取消掉,保证每一次模态框关闭后都没有观察者在订阅模态框即可。
// app.component.ts confirm 方法
const result = this.alert.confirm.pipe(first()).subscribe(() => {
// 执行回调
if (callback) {
callback();
}
// 取消订阅
cancel.unsubscribe();
});
const cancel = this.alert.cancel.pipe(first()).subscribe(() => {
result.unsubscribe();
});
订阅模态框的确认(confirm)和取消(cancel)事件源,在点击取消时取消掉确认事件的订阅,在点击确认时取消掉取消事件的订阅,并使用first()操作符保证每个观察者只能有一次订阅。
解决方法2:
由于确认和取消是两个不同的数据源,造成了编写时的观念错误,把确认和取消合并为模态框关闭的事件源,即可消除此错误。
使用merge
操作符将数据源合并,map
操作符将确认数据源改为true
,取消数据源改为false
:
// app.component.ts confirm 方法
merge(this.alert.confirm.pipe(map(() => true)), this.alert.cancel.pipe(map(() => false))).pipe(first())
.subscribe((is) => {
if (is && callback) {
callback();
}
});
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。