我正在尝试创建一个联系表单,该表单在API响应成功后会将用户重定向到“已发送消息”页面,该页面仅应在用户实际发送消息后显示(并从服务器)。
HTML表单(contact.component.html
)
可能无关紧要,但无论如何我都会把它包括在内
<div class="second column">
<span class="row">
<h4 style="display: inline">To: </h4> {{pointOfContact.name}}
</span>
<span class="row">
<label for="subject" class="field-label column">Subject</label>
<input id="subject" name="subject" #subject="ngModel" [(ngModel)]="emailMessage.subject" type="text" class="field column" required autofocus>
<button *ngIf="emailMessage.subject" (click)="emailMessage.subject = ''">Clear</button>
</span>
<span class="error" *ngIf="subject.invalid && !subject.pristine">Subject is required</span>
<span class="row">
<label for="name" class="field-label column">Name</label>
<input id="name" name="name" #name="ngModel" [(ngModel)]="emailMessage.sender.name" type="text" pattern="[A-Za-z ]+" class="field column" required>
<button *ngIf="emailMessage.sender.name" (click)="emailMessage.sender.name = ''">Clear</button>
</span>
<span class="error" *ngIf="name.invalid && !name.pristine">{{emailMessage.sender.name ? 'That name is invalid' : 'Please enter your name' }}</span>
<span class="row">
<label for="email" class="field-label column">E-mail</label>
<input id="email" name="email" type="email" #email="ngModel" [(ngModel)]="emailMessage.sender.email" class="field column" email required>
<button *ngIf="emailMessage.sender.email" (click)="emailMessage.sender.email = ''">Clear</button>
</span>
<span class="error" *ngIf="email.invalid && !email.pristine">{{emailMessage.sender.email ? 'Please enter valid email' : 'Email is required'}} </span>
<span class="row">
<label for="message" class="field-label column">Message</label>
<textarea id="message" name="message" #message="ngModel" [(ngModel)]="emailMessage.message" class="field column" required></textarea>
<button *ngIf="emailMessage.message" (click)="emailMessage.message = ''">Clear</button>
</span>
<span class="error" *ngIf="message.invalid && !message.pristine">Message is required</span>
<span class="row">
<span class="right error">
{{formError}}
</span>
</span>
<span class="row">
<span class="right">
<button
*ngIf="emailMessage.subject.length &&
emailMessage.sender.name.length &&
emailMessage.sender.email.length &&
emailMessage.message.length"
id="send-email"
(click)="sendEmail()"
class="form-button">Send Email</button>
</span>
</span>
</div>
该组件的TypeScript(contact.component.ts
)
提交表单所需的功能如下:
sendEmail() {
if (/^([a-z]@[a-z]).[a-z]$/.test(this.emailMessage.sender.email)) {
this.handleError("Bad email")
return;
}
this.emailSender = (this.contactService
.send(this.emailMessage))
this.emailSender
.subscribe(res => {
console.log(res);
if (res.code === 200) {
// post the data to the "Message Sent" service"
this.messageSentService.announceMessageSent(res.message)
// TODO: nativate straight to the success page
// this.router.navigate(['messageSent'])
this.router.navigateByUrl('contact/messageSent')
}
else {
this.handleError(res.message)
}
})
}
private handleError(cause : string) {
// show error message either somewhere in the form or as a modal
this.formError = cause;
}
MessageSentService
import { Injectable } from "@angular/core";
import { Subject } from "rxjs";
@Injectable()
export class MessageSentService {
// services, solely to announce the message has been successfully sent
private messageSentService = new Rx.ReplaySubject<string>(1);
// Observable string streams
messageSent$ = this.messageSentService.asObservable();
// service message command
announceMessageSent(successMessage : string) {
this.messageSentService.next(successMessage);
}
announceMessageFail() {
this.messageSentService.next();
}
}
要重定向到(message-sent-guard.ts
)的组件上的防护层
import { MessageSentService } from "../services/message-sent.service";
import { RouterStateSnapshot, CanActivate, Router, ActivatedRouteSnapshot } from "@angular/router";
import { first, map, switchMap, last } from "rxjs/operators";
import { NEVER, of, Observable } from "rxjs";
import { Injectable } from "@angular/core";
@Injectable()
export class MessageSentGuard implements CanActivate{
constructor(private router: Router,
private service : MessageSentService ) {
}
canActivate(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot) : Observable<boolean> {
console.log("Can you even see me?")
return this.service.messageSent$.pipe(
last(),
map(msg => !!msg),
switchMap(sent => {
console.log(sent)
if (!sent) {
this.router.navigate(['/home']);
return NEVER;
}
console.log("redirecting...")
return of(true);
})
);
}
}
“已发送消息”组件TypeScript文件(message-sent.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { Subscription } from 'rxjs';
import { MessageSentService } from '../../../services/message-sent.service';
import { AutoUnsubscribe } from '../../../auto-unsubscribe';
@Component({
selector: 'app-message-sent',
templateUrl: './message-sent.component.html',
styleUrls: ['./message-sent.component.css']
})
@AutoUnsubscribe
export class MessageSentComponent implements OnInit {
message: string;
subscription : Subscription;
constructor(private messageSentService: MessageSentService) {
this.subscription = this.messageSentService
.messageSent$
.subscribe(message => { this.message = message;})
}
ngOnInit() {
}
}
请务必注意,此组件是ContactComponent
的子级。
结果
什么都没发生!除此之外:
更糟糕的是,当我进入MessageSentComponent
本身(通过其路径contact/messageSent
)时,我得到了黑屏!
我该如何解决?!
更新:我对源代码进行了一些更改:
在private messageSentService = new Subject<string>();
,created a Stackblitz中将private messageSentService = new Rx.ReplaySubject<string>(1);
更改为MessageSentService
以隔离问题,并能够在那里解决问题,但是当我将更改复制到真正的源代码,它不起作用。