合并观察者数据源

在加入考试系统项目后,首先作的工做是添加操做提示框,本觉得简单的工做,在使用时却出现了使人意想不到的错误。html

背景

使用的模态框库为sweetalert2,设计方法是在应用的根组件appComPonent中使用模态框组件,appComPonent中暴露展现确认模态框的方法confirm,子组件经过注入appComPonent并调用confirm方法,经过传入回调函数,实如今子组件中展现模态框的功能。app

// 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)来保证点击确认按钮时执行成功的回调函数。例如在子组件中使用示例:ide

// 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}`);
  }

Nov-29-2019 18-37-30.gif

奇怪的现象

本着测试的原则,当按照以前的代码加入模态框,本身测试了如下,却出现了意想不到的事情:我点击删除,以后取消,进入编辑界面保存编辑后,回到首页却把数据给删除了。
Nov-29-2019 18-39-56.gif函数

回到代码,当咱们展示删除提示框时,预定了模态框的确认(alert.confirm)数据源,来保证点击肯定按钮时实现删除的操做,可是我却没点击肯定,点击的是取消。此时确认数据源还在被咱们预定着,在编辑页面点击了保存模态框的肯定按钮后,因为使用的是都是根组件中的模态框实例,确认数据源被触发,从而执行咱们以前预定的删除操做!测试

解决方法

解决方法1:
触发这奇怪现象的源头就是上一次预定确认数据源没有取消掉,把这个预定给取消掉,保证每一次模态框关闭后都没有观察者在订阅模态框便可。this

// 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()操做符保证每一个观察者只能有一次订阅。spa

解决方法2:
因为确认和取消是两个不一样的数据源,形成了编写时的观念错误,把确认和取消合并为模态框关闭的事件源,便可消除此错误。
image.png设计

使用merge操做符将数据源合并,map操做符将确认数据源改成true,取消数据源改成false:code

// 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();
        }
      });
相关文章
相关标签/搜索