I've developed a component with two views. Component A has a contact form, and Component B is the "Thank you" page.
Component A: You fill the form and submit it. As soon as the response arrives, a new ReplaySubject value is created. The user will be routed to the component B.
Component B: The component is initialized. The component gets the value from the subject. The view is rendered and displays the thank you message.
HTTP Call response (Returned after a successful Form data post request):
{
"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"
}
Component A (Form) code:
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']);
});
}
}
Component B (Thank you page) code:
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;
}
}
Component B Template (Thank you page):
<div *ngIf='(messages | async) as msg'>
{{ msg.message}}
</div>
Component Service code:
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);
}
}
Recap: Component A has a form. After you submit the form, the results are stored as a new value in the subject. The user is routed to the thank you page. The thank you page component renders the element and gets the newest value from the subject. Then it renders the contents.
This code works, but I do have some questions.
Question: Is this the proper way of using the Subject?
Is this:
readonly message: Observable<ItemCreated> = this.results;
the proper way of extracting the values from a subject? (I'm passing 'message' to the view.)
Are there better ways to achieve the same result? Thanks a lot in advance.