本文介绍了Angular4 - 如何使用dialogService确认使用链式可观察对象进行CanDeactive防护?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于。

I have a CanDeactive guard based on the Hero app in the official docs.

此警卫首先检查我的组件是否不需要清理,并立即返回 false 如果是这样。

This guard first checks if my component does not need cleanup, and it immediately returns false if so.

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

Otherwise it shows a confirm dialog to the user. The dialog is provided by this service (identical to the docs):

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 (再次,根据文档)。

If the user answers 'No' (false) to the dialog, then CanDeactive also immediately returns false. This is why it has two return types: Observable<boolean> and boolean (again, as per docs).

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

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

Where I differ from the docs is that if the user answers yes (true) to the confirm dialog, I need to do some cleanup and then call my api - which you can see is the line return this.onDestroyCleanup().subscribe().

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

So I don't want to return true immediately, but first call this method and return true or false from that (false only if the api call failed).

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

Here is that method, which calls the api and maps the result of the api call to true or 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;
      }
    );
  }

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

Everything works except the user stays on the page when they answer Yes. The console output is:

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

看到输出我意识到 CanDeactive 没有返回结果,所以我将 CanDeactive 的最后一部分更改为:

Seeing that output I realised that CanDeactive is not returning a result, so I changed the last part of the CanDeactive to this:

    ...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;
      }
    );
  }

但我得到的结果相同。

But I get the same result.

所以现在我不知道我是否正确构造这个或者是否可能是我的 onDestroyCleanup 代码这是错误的。

So now I don't know whether I am structuring this correctly or if perhaps my onDestroyCleanup code is the thing that is wrong.

更新

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

To help understanding, this code obviously works:

// 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'以及何时解析,返回那个结果。

...because it directly returns either true or false. The problem is how to replace the 'return true' with code that calls another Observable and when that resolves, to return the result of THAT one.

但为了进一步说明,这不起作用,因为它说类型Observable< false> | Observable< boolean>不能分配给boolean类型| Observable< boolean>

But to illustrate further, this does not work as it says "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;
  }
);


推荐答案

通过返回此信息。 onDestroyCleanup()。subscribe(); 在你的canDeactivate方法中,你要返回一个订阅,而不是一个可观察的订阅。您还需要返回一个链式可观察序列(使用flatMap / mergeMap)。这样,canDeactivate方法就会返回一个可以订阅的observable。

By doing return this.onDestroyCleanup().subscribe(); in your canDeactivate method, you are returning a subscription, not an observable. Also you need to return a chained observable sequence (with flatMap/mergeMap). This way the canDeactivate method altogether returns an observable that can be subscribed to.

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可以订阅。

As you can see, we are now returning a chained observable sequence that the CanDeactivate Guard can subscribe to.

当你换掉你的确认时,你可以修改你的confirm()方法,如

When you do swap out your confirm you can modify your confirm() method to something like

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

现在你的确认正在返回一个带有observable的异步实现。

Now your confirm is returning an asynchronous implementation with an observable.

这篇关于Angular4 - 如何使用dialogService确认使用链式可观察对象进行CanDeactive防护?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 18:04