Angular 使用 BehaviorSubject 在重新加载刷新期间查看组件数据丢失

Angular View Component Data Loss during Reload Refresh using BehaviorSubject

我正在编写一个 Angular9 应用程序,其中包含一个用例,其中我在 3 个页面上缓冲数据(表单接受数据输入)。

然后,在第 4 页,我以只读文本显示了在 3 页中收集的详细信息摘要。

我已经使用以下文章实现了数据缓冲:

https://www.infragistics.com/community/blogs/b/infragistics/posts/simplest-way-to-share-data-between-two-unrelated-components-in-angular

其中使用了 BehaviorSubject

下面是我的数据业务逻辑:

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders } from '@angular/common/http';
    import { Observable, BehaviorSubject, throwError } from 'rxjs';
    import { retry, catchError } from 'rxjs/operators';
    import { UserResponse } from  './user-response';

    @Injectable({
      providedIn: 'root'
    })

    export class UserService {

        //Details Page 1
        public salutation: BehaviorSubject<string>;
        public firstName: BehaviorSubject<string>;

      // Base url
      baseurl = 'https://localhost:8080/rest';

      constructor(private http: HttpClient) { }

      // Http Headers
      httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/json'
        })
      }

      // POST
      createUser(data): Observable<UserResponse> {
        alert('user - details = '+ data);
        return this.http.post<UserResponse>(this.baseurl + '/user', JSON.stringify(data), this.httpOptions)
        .pipe(
          retry(1),
          catchError(this.errorHandler)
        )
      }

      // Error handling
      errorHandler(error) {
         let errorMessage = '';
         if(error.error instanceof ErrorEvent) {
           // Get client-side error
           errorMessage = error.error.message;
         } else {
           // Get server-side error
           errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
         }
         console.log(errorMessage);
         return throwError(errorMessage);
      }

}

下面是我的第一个视图组件:

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { UserService } from '../service/user.service';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'app-details1',
  templateUrl: './details1.component.html',
  styleUrls: ['./details1.component.css']
})
export class Details1Component implements OnInit {
  salutation: string;
  firstName: string;

  constructor(private userService: UserService) { }

  ngOnInit(): void {
  }

  goToDetails2(form : NgForm) {
          this.userService.salutation = new BehaviorSubject(form.value.salutation);
          this.userService.firstName = new BehaviorSubject(form.value.firstName);
      }

}

下面是我的 final/summary 视图组件的片段

import { Component, OnInit} from '@angular/core';
import { Router } from '@angular/router';
import { UserService } from '../service/user.service';

@Component({
  selector: 'app-summary',
  templateUrl: './summary.component.html',
  styleUrls: ['./summary.component.css']
})

export class SummaryComponent implements OnInit {

       salutation: string;
       firstName: string;

  constructor(
    private router: Router,
    public userService: UserService
  ) {
   }

   ngOnInit(): void {
       this.userService.salutation.subscribe(c => { this.salutation = c; });
       this.userService.firstName.subscribe(c => { this.firstName = c; });
   }

}

最后一页我的html摘录如下:

<form #detailsForm4="ngForm">
<div class="govuk-form-group">
  <table class="govuk-table">
    <thead class="govuk-table__head">
    <tr class="govuk-table__row"></tr>
    </thead>
    <tbody class="govuk-table__body" align="left">
    <tr class="govuk-table__row">
      <th scope="row" class="govuk-table__header">Salutation</th>
      <td class="govuk-table__cell">   {{salutation}} </td>
      <td class="govuk-table__cell"> </td>
    </tr>
    <tr class="govuk-table__row">
      <th scope="row" class="govuk-table__header">First name</th>
      <td class="govuk-table__cell">   {{firstName}} </td>
      <td class="govuk-table__cell"> </td>
    </tr>

数据显示在摘要页面上,如在第 1-3 页的表单中捕获的那样, 但是数据在页面刷新或我的机器休眠等时丢失

我已经阅读了有关本地和会话存储持久性的内容,并且从 angularjs 1.x 天起就开始使用它。 很久以前,当我的摘要屏幕上的数据消失时,我真的很惊讶!

我想理想的解决方案是当用户离开相关表单时将数据存储在客户端存储中,然后在摘要页面上检索数据。

我猜,当摘要页面第一次刷新或显示时, 我将检查数据的存储并显示它是否存在。 如果存储为空,那么我将在运行时使用上一页的数据。

拜托,我需要有关最佳实践和稳定解决方案的帮助,它对商业应用程序来说是跨浏览器友好且智能的。

此外,适合 Angular9 BehaviorSubject - rxjs 堆栈或任何最新功能的方法,因为我知道 Angular 自 AngularJs 1.x 以来已经发展?

仅当用户导航回第 1-3 页中的任何一页以更改表单详细信息时,摘要详细信息才会更改。

对于将数据保存在摘要页面上的任何代码片段或参考,我将不胜感激。

非常感谢。

我会建议您在 ngOnDestroy 生命周期挂钩中的 SummaryComponent 中使用 localStorage。在组件因刷新而被销毁之前,它将始终在 localStorage 中设置您的数据。然后,当您尝试从服务中检索数据时,如果它为空,请尝试从 localStorage 获取它。

export class SummaryComponent implements OnInit, OnDestroy {

   salutation: string;
   firstName: string;

constructor(
  private router: Router,
  public userService: UserService
) {
  }

 ngOnInit(): void {
   this.userService.salutation.subscribe(c => { this.salutation = c || localStorage.get('salutation'); });
   this.userService.firstName.subscribe(c => { this.firstName = c || localStorage.get('firstName'); });
 }

 ngOnDestroy(): void {
   localStorage.setItem('salutation', this.salutation));
   localStorage.setItem('firstName', this.firstName));
 }

}

您可以在设置此值的组件中执行类似的实现,并且您希望用户可以在转到下一页之前刷新页面。

编辑

抱歉,您说得对,ngOnDestory 不会在页面刷新时触发,您需要处理 window:beforeunload。

  @HostListener('window:beforeunload', ['$event'])
  beforeunload($event: Event): void {
   // set localStorage here
  }  

继续您的解决方案,将项目设置到 localStorage 的最佳选择是您为服务设置值的地方。可能是 goToDetails2 方法。

goToDetails2(form : NgForm) {
          this.userService.salutation = new BehaviorSubject(form.value.salutation);
          this.userService.firstName = new BehaviorSubject(form.value.firstName);
          localStorage.setItem('salutation', form.value.salutation));
          localStorage.setItem('firstName', form.value.firstName));
      }

针对您在评论中描述的问题进行 EDIT-2

我建议您直接在服务内部初始化 BehaviorSubject

@Injectable({
  providedIn: 'root'
})

export class UserService {

    //Details Page 1
    public salutation: BehaviorSubject<string> = new BehaviorSubject('');
    public firstName: BehaviorSubject<string> = new BehaviorSubject('');

然后在 Details1Component 中使用 next

设置它们的值
goToDetails2(form : NgForm) {
          this.userService.salutation.next(form.value.salutation);
          this.userService.firstName.next(form.value.firstName);
          localStorage.setItem('salutation', form.value.salutation));
          localStorage.setItem('firstName', form.value.firstName));
      }