Angular canActivate返回Observable无法正常工作

时间:2018-10-06 20:16:53

标签: angular typescript observable

我正在尝试创建一个联系表单,该表单在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的子级。

结果

什么都没发生!除此之外:

enter image description here

更糟糕的是,当我进入MessageSentComponent本身(通过其路径contact/messageSent)时,我得到了黑屏!

我该如何解决?!

更新:我对源代码进行了一些更改:

private messageSentService = new Subject<string>();created a Stackblitz中将private messageSentService = new Rx.ReplaySubject<string>(1);更改为MessageSentService以隔离问题,并能够在那里解决问题,但是当我将更改复制到真正的源代码,它不起作用。

0 个答案:

没有答案