Angular4-如何使用dialogService确认使CanDeactive guard与链式可观察器一起工作



我在官方文档中有一个基于Hero应用程序的CanDeactive卫士。

这个保护首先检查我的组件是否不需要清理,如果需要,它会立即返回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;
}
);
}

我与文档的不同之处在于,如果用户对确认对话框的回答是yes(true),我需要进行一些清理,然后调用我的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;
}
);
}

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

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。问题是如何将"return true"替换为调用另一个Observable的代码,当问题解决时,返回该代码的结果。

但为了进一步说明,这并不像它所说的"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();
}); 
});
};

现在您的confirm返回了一个具有可观察到的异步实现。

最新更新