我有一个 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/