angular - 如何在路由器插座中调用同级组件功能并在 Angular 中等待其完成
问题描述
我目前正在开发一个由一系列长表单组成的 Web 应用程序。我有一个全局组件,其模板如下所示:
<app-header></app-header>
<div class="main-container">
<router-outlet></router-outlet>
</div>
<app-navigation></app-navigation>
所以我有多个页面在路由器插座和 2 个不变的组件内轮流,特别是导航组件,它由允许在不同屏幕/表单之间来回切换的按钮组成。
我的目标是能够从导航组件调用路由器插座内的页面/表单组件的功能,以触发表单验证和强制 Web 服务调用,然后触发导航。
我做了三件事,每个页面/表单都必须实现的接口,它看起来像这样:
export interface FormValidation {
executeValidation();
}
let subscription;
export function validationEventSubscriber(action: Subject<any>, handler: () => void, off: boolean = false) {
if (off && subscription) {
subscription.unsubscribe();
} else {
subscription = action.subscribe(() => handler());
}
}
用于管理包含以下内容的表单的服务:
export class FormsService {
//...other properties...
validationSubject = new Subject();
constructor() { }
executeValidation() {
this.validationSubject.next();
}
//...other functions...
}
还有一个服务来管理导航,它根据不同的业务规则调用 Router.navigateByUrl。
然后在我的 NavigationComponent 我有一个调用的方法executeValidation
:
//function called when clicking the button to go to the next page
nextPage() {
this.formsService.executeValidation();
}
最后在页面组件中我有这个:
constructor(...) {
this.executeValidation = this.executeValidation.bind(this);
validationEventSubscriber(this.formsService.validationSubject, this.executeValidation);
}
executeValidation() {
//...Validation...
this.navigationService.nextPage();
}
这个工作流按预期工作我可以executeValidation
从 NavigationComponent 触发页面的功能,但我正在努力实现的是使验证异步。
这里困扰我的是我正在调用NavigationService
页面内部,我需要在每个页面中都这样做,在每个executeValidation
方法中复制/粘贴同一行代码。我更愿意从内部执行此操作,NavigationComponent
但我必须等到页面组件内部的验证结束,这就是我挣扎的地方。
如果有人对如何解决这个问题有任何想法,我会全力以赴!
解决方案
我倾向于将纯业务逻辑限制在服务中,并将与“视图”部分相关的所有内容都限制在组件中,包括通过路由器进行的导航。
所以,如果这个理念适合你,这就是我要继续的方式。
创建一个myService
公开以下内容的服务
private _validate$ = new Subject<bool>();
public validate$ = this._validate$.asObservable();
public executeValidation() {
this._validate.next(true);
}
myService
in 注入到app-navigation
Component 和所有加载到router-outlet
.
然后,您可以创建另一个validationService
,在其中定义一个或多个验证方法,这些验证方法调用实际执行工作的 web 服务。
validationService
看起来像这样
private _validationResult$ = new Subject<bool>();
public validationResult$ = this_validationResult$.asObservable();
// each form may have its own validation method
// the input of each validation method can be typed via an interface or let any as here
public validateFormX(input: any) {
// assume validation is a post web service exposed by a remote server
this.http.post("validationX_url", input).pipe(
// when the response comes we notify it using _validationResult$
tap({
next: resp => this._validationResult$.next(resp),
error: err => this._validationResult$.error(err)
})
)
}
我们将 注入validationService
到所有加载到router-outlet
. 每个组件都必须订阅myService.validate$
并validationService.validationResult$
喜欢这个
// when myService.validate$ notifies, then we launch the validation logic
this.myService.validate$.subscribe(
// assume each Component in the router-outlet is able to create the input for validation
const input = buildValidationInput();
() => this.validationService.validateFormX(input)
)
this.validationService.validationResult$.subscribe(
validationResp => {
// depending on the validation response navigate to the corresponding page
this.router.navigate(....)
}
)
如果您遵循这种方法,您的优势在于服务中的大多数逻辑都可以比组件更容易测试。
推荐阅读
- python - 如何将一个 Jupyter 笔记本导入另一个
- c# - 在 Automapper 中映射集合
- python - 如何将调试控制台设置为 Visual Studio Code 中的默认选项卡?
- regex - 每行一个输出组,带有组名和组 ID
- c# - 如何处理静态 httpclient
- compiler-errors - 编译 ffmpeg:致命错误:ld 以信号 11 终止
- java - 在休眠中从 session.createQuery 获取超过 1 个对象
- git - 使用 Git 的 Sylius / Symfony 标准版本控制流程
- java - 如何使用 CompletableFuture 和 CompletionStage 进行异常处理
- ruby - 从 ruby rspec 运行命令行