分享

合并观察者数据源

 路人甲Java 2020-03-06

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

背景

使用的模态框库为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}`);
  }

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

奇怪的现象

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

回到代码,当我们展现删除提示框时,预约了模态框的确认(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:
由于确认和取消是两个不同的数据源,造成了编写时的观念错误,把确认和取消合并为模态框关闭的事件源,即可消除此错误。
image.png

使用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();
        }
      });

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多