javascript - Angular4 - 如何使 CanDeactive 守卫使用 dialogService 确认与链接的可观察对象一起工作?

标签 javascript angular typescript rxjs observable

我有一个 CanDeactive official docs 中基于 Hero 应用程序的守卫.

这个守卫首先检查我的组件是否不需要清理,然后立即返回 false如果是的话。

否则它会向用户显示一个确认对话框。该对话框由该服务提供(与文档相同):

import 'rxjs/add/observable/of';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

/**
 * Async modal dialog service
 * DialogService makes this app easier to test by faking this service.
 * TODO: better modal implementation that doesn't use window.confirm
 */
@Injectable()
export class DialogService {
  /**
   * Ask user to confirm an action. `message` explains the action and choices.
   * Returns observable resolving to `true`=confirm or `false`=cancel
   */
  confirm(message?: string): Observable<boolean> {
    const confirmation = window.confirm(message || 'Is it OK to leave the page?');

    return Observable.of(confirmation);
  };
}

如果用户对对话框回答“否”(false),则 CanDeactive也立即返回 false。这就是为什么它有两种返回类型:Observable<boolean>boolean (同样,根据文档)。

  canDeactivate(): Observable<boolean> | boolean {
    console.log('deactivating');
    // Allow immediate navigation if no cleanup needed
    if (this.template.template_items.filter((obj) => 
         { return !obj.is_completed }).length < 2)
      return true;

    // Otherwise ask the user with the dialog service
    this._dialogService.confirm('You have some empty items.
      Is it OK if I delete them?').subscribe(
      confirm => {
        console.log('confirm is ', confirm);
        if (confirm) return this.onDestroyCleanup().subscribe();
        else return false;
      }
    );
  }

我与文档的不同之处在于,如果用户对确认对话框回答是(真),我需要做一些清理然后调用我的 api - 你可以看到行 return this.onDestroyCleanup().subscribe() .

所以我不想立即返回 true,而是先调用此方法并从中返回 true 或 false(仅当 api 调用失败时才返回 false)。

这是调用 api 并将 api 调用的结果映射为 true 或 false 的方法:

  onDestroyCleanup():Observable<boolean> {
    console.log('cleaning up');
    this.template.template_items.forEach((item, index) => {
      // insert marker flag to delete all incomplete items
      if (!item.is_completed) {
        this.template.template_items[index]['_destroy'] = true;
      };
    });
    // a final save to remove the incomplete items
    return this._templateService.patchTemplate(this.template).take(1).map(
      result => {
        console.log('cleanup done: ', result);
        return true;
      },
      error => {
        console.log('cleanup done: ', error);
        this._apiErrorService.notifyErrors(error.json());
        return false;
      }
    );
  }

一切正常,除了用户在回答"is"时停留在页面上。控制台输出为:

deactivating
confirm is true
cleaning up
cleanup done: [returned json object]

看到那个输出我意识到CanDeactive没有返回结果,所以我更改了 CanDeactive 的最后一部分对此:

    ...same code up to here...
    // Otherwise ask the user with the dialog service
    return this._dialogService.confirm('You have some empty items. 
          Is it OK if I delete them?').map(
      confirm => {
        console.log('confirm is ', confirm);
        if (confirm) this.onDestroyCleanup().subscribe(r => {return r});
        else return false;
      }
    );
  }

但我得到了相同的结果。

所以现在我不知道我的结构是否正确,或者我的 onDestroyCleanup 是否正确?代码是错误的东西。

更新

为了帮助理解,这段代码显然有效:

// Otherwise ask the user with the dialog service
return this._dialogService.confirm('You have some empty items. Is it 
       OK if I delete them?').map(
  confirm => {
    console.log('confirm is ', confirm);
    if (confirm) return true;
    else return false;
  }
);

...因为它直接返回 true 或 false。问题是如何用调用另一个 Observable 的代码替换“return true”,并在解析时返回那个结果。

但为了进一步说明,这不起作用,因为它说“Type Observable <false> | Observable<boolean> is not assignable to type boolean | Observable<boolean>”:

// Otherwise ask the user with the dialog service
return this._dialogService.confirm('You have some empty items. Is it 
       OK if I delete them?').map(
  confirm => {
    console.log('confirm is ', confirm);
    if (confirm) return Observable.of(true); 
    else return false;
  }
);

最佳答案

通过在您的 canDeactivate 方法中执行 return this.onDestroyCleanup().subscribe();,您将返回一个订阅,而不是一个可观察对象。您还需要返回一个链接的可观察序列(使用 flatMap/mergeMap)。这样 canDeactivate 方法就会完全返回一个可以订阅的可观察对象。

canDeactivate(): Observable<boolean> | boolean {
    console.log('deactivating');
    // Allow immediate navigation if no cleanup needed
    if (this.template.template_items.filter((obj) => 
        { return !obj.is_completed }).length < 2)
        return true;

    // Otherwise ask the user with the dialog service
    return this._dialogService.confirm('You have some empty items. Is it OK if I delete them?')
        // chain confirm observable with cleanup observable
        .flatMap(confirm => {
            console.log('confirm is ', confirm);
            if (confirm) {
                return this.onDestroyCleanup();
            } else {
                return Observable.of(false);
            }
        });
}

如您所见,我们现在返回一个链式可观察序列,CanDeactivate Guard 可以订阅该序列。

当你换掉你的确认时,你可以将你的 confirm() 方法修改为类似的东西

confirm(message?: string): Observable<boolean> {
    return new Observable(observer => {
        // bring up custom confirm message somehow
        customConfirm(message, (confirmation: boolean) => {
            // emit result. This would likely be in a callback function of your custom confirm message implementation
            observer.next(confirmation);
            observer.complete();
        }); 
    });
};

现在您的确认正在返回一个带有可观察对象的异步实现。

关于javascript - Angular4 - 如何使 CanDeactive 守卫使用 dialogService 确认与链接的可观察对象一起工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47014700/

相关文章:

javascript - 如何通知父组件 Vue 动态组件发生了某些情况?

javascript - 为什么 1<x<3 总是正确的?

reactjs - 如何创建一个通用的 React.FC?

javascript - 无法从 CDN 下载 Mustache.js 文件

javascript - 对于模型的路径 ""处的值 "_id"转换为 ObjectId 失败

angular - 配置 Observable 以在推送新值时将所有先前值作为数组返回?

html - 如何将背景图像放在 Angular 2中

javascript - 如何监听 Angular 2 中代码的变化?

javascript - typescript :Map.has 没有返回正确的值

javascript - ng-if 内的 Angular js