合併觀察者數據源

在加入考試系統項目後,首先作的工做是添加操做提示框,本覺得簡單的工做,在使用時卻出現了使人意想不到的錯誤。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();
        }
      });
相關文章
相關標籤/搜索