我已经开发了具有两个视图的组件。组件A具有联系表单,组件B是“谢谢”页面。
组件A: 您填写表格并提交。 响应到达后,将立即创建一个新的ReplaySubject值。 用户将被路由到组件B。
组件B: 组件已初始化。 该组件从主题中获取价值。 视图将被渲染并显示“谢谢”消息。
HTTP调用响应(在成功发送Form数据后请求后返回):
{
"status": 200,
"body": {
"message": "We have received your request with the card information below and it will take 48h to be processed. Thank you!",
"card": {
"name": "John Doe",
"email": "john.doe@gmail.com",
"accountNumber": "12345-67890"
}
},
"type": "ItemCreated"
}
A组件(表单)代码:
import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { RequestCardWidgetService } from './request-card-widget.service';
import { RouterService } from '@framework/foundation/core';
import { Item } from '@pt/request-card-data'
@Component({
selector: 'pt-request-card-form',
templateUrl: './request-card-form.template.html',
providers: [RouterService]
})
export class RequestCardFormComponent {
constructor(private fb: FormBuilder, private data: RequestCardWidgetService, private router: RouterService){}
item: Item = {
name: '',
email: '',
accountNumber: ''
};
requestCardForm = this.fb.group({
name: ['', Validators.required],
email: ['', Validators.email],
accountNumber: ['', Validators.required]
})
onSubmit() {
this.item = this.requestCardForm.value;
this.data.requestCard(this.item)
.subscribe(data => {
this.data.processResult(data);
this.router.navigate(['/success']);
});
}
}
组件B(谢谢页面)代码:
import { Component } from '@angular/core';
import { RequestCardWidgetService } from './request-card-widget.service';
@Component({
selector: 'pt-request-card-success',
templateUrl: './request-card-success.template.html'
})
export class RequestCardSuccessComponent {
messages: any; // TODO: To use the proper type...
constructor( private requestCardService: RequestCardWidgetService) {
this.messages = this.requestCardService.message;
}
}
组件B模板(谢谢页面):
<div *ngIf='(messages | async) as msg'>
{{ msg.message}}
</div>
组件服务代码:
import { Injectable } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { map, take } from 'rxjs/operators';
import {
RequestCardDataService,
Item,
ItemCreated
} from '@example/request-card-data';
@Injectable()
export class RequestCardWidgetService {
constructor(private dataService: RequestCardDataService) { }
private readonly results = new ReplaySubject<ItemCreated>();
readonly message: Observable<ItemCreated> = this.results; // Message Line. This is the variable that I'm rendering in the template. Is this the correct way of extracting subject values?
requestCard (card: Item): Observable<ItemCreated> {
return this.dataService.postCardRecord(card).pipe(
take(1),
map((response: HttpResponse<ItemCreated>): ItemCreated | {} => {
return response.body
? response.body
: {};
})
);
}
processResult(data: ItemCreated) {
this.results.next(data);
}
}
回顾: 组件A具有一种形式。提交表单后,结果将作为新值存储在主题中。用户被路由到“谢谢”页面。 谢谢页面组件呈现该元素并从主题中获取最新值。然后呈现内容。
此代码有效,但我确实有一些疑问。
问题: 这是使用主题的正确方法吗?
这是:
readonly message: Observable<ItemCreated> = this.results;
从主题中提取值的正确方法是什么? (我正在向视图传递“消息”。)
是否有更好的方法可以达到相同的结果? 提前谢谢。
答案 0 :(得分:2)
ReplaySubect
将重播它先前发送给新订户的所有值。这可能导致用户可能会收到以前发出的消息,直到他们最终收到当前消息为止。因此,要么约束主题,要么考虑使用BehaviorSubject
。
一个Subject
及其所有派生词都是Observable
和Observer
。当向消费者提供主题时,您不想公开Observer
界面,即,消费者永远不能调用next
,error
或complete
。因此,如评论中所建议,应确保首先通过调用Observable
方法将asObservable
接口暴露给使用者。
readonly message: Observable<ItemCreated> = this.results.asObservable();
如果您想继续使用组件之间的基于服务的通信,那么我认为您有机会根据问题注释中链接的文档来清理/优化代码。
如果您的应用程序变得越来越复杂,我将指导您采用Redux风格的体系结构,并研究NgRx,尤其是使用效果来管理副作用。
效果可以通过简单,谨慎的可观察结构满足您的所有要求,即,一种用于处理表单提交,接收响应甚至导航到成功页面的效果。 More information about effects can be found here。
对于一个简单的任务,redux架构可能会显得过分杀伤,但是如果您正在处理管理大型状态树的大型应用程序,那么与基于服务的集成相比,我更喜欢这种方法。