【问题标题】:Angular View Component Data Loss during Reload Refresh using BehaviorSubject使用 BehaviorSubject 重新加载刷新期间角度视图组件数据丢失
【发布时间】:2020-03-24 22:20:28
【问题描述】:

我正在编写一个 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);
      }

}

下面是我的最终/摘要视图组件的 sn-p

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 页以更改表单详细信息时,才会更改摘要详细信息。

我将感谢任何代码 sn-p 或参考以将数据保留在摘要页面上。

非常感谢。

【问题讨论】:

  • 在刷新的情况下数据丢失似乎很明显。解决方案之一是将数据保存在本地存储中,或者如果不是来自用户的输入,则在刷新后再次从服务器获取。
  • 感谢 Stefan 的快速回复。我找不到适合 angular9 的关于使用本地存储的好的 sn-p。想要重新保证最佳实践模式等
  • 这很可能是用户服务在未预料到的情况下被重新加载的问题。为了证明在 ngOnInit 中向控制台记录一条消息。然后重新创建问题。如果您看到不止一条消息....您可以考虑将行为主题设为静态,这样可以确保内容始终是正确的内容。

标签: javascript angular typescript angular9 angular-local-storage


【解决方案1】:

我会建议您在 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));
      }

【讨论】:

  • 嗨 Stefan,去看看结果:1) ngOnDestroy() 不会在刷新时调用,但是当我单击浏览器后退按钮 w chrome.So,salutation.subscribe(c => { this .salutation = c || localStorage.getItem('salutation'); }) 在刷新时不起作用 (2) 添加了逻辑 localStorage.setItem('salutation', this.salutation));在 page1 组件中。然后用户填写表格并转到摘要页面。摘要页面中 ngOnInit 第一行的 Alert() 确认数据是从 localstrorage 检索的,但 salutation.subscribe(c => { this.salutation = c || localStorage.get('salutation'); }) 不显示数据。
  • 在页面 1 组件中设置数据可以使用 localStorage.getItem() 使数据在摘要页面中可用。但是,刷新后,salutation.subscribe(c => { this.salutation = c || localStorage.get('salutation'); });不工作。似乎刷新会删除以前发布的内容。
  • 您能否在订阅时添加console.log(localStorage.get('salutation')),从第一步到摘要,然后刷新页面?您还可以使用浏览器开发工具查看 localStorage 中设置的内容。
  • 早上好 Stefan,控制台出现错误。 TypeError: Cannot read property 'subscribe' of undefined at SummaryComponent.ngOnInit (summary.component.ts:67) 问题是刷新后 this.userService.salutation 未定义。看起来数据服务变量需要在页面刷新后重新初始化。在总结组件中,我定义了一个 var underfined;然后检查 if(this.userService.salutation==undefined){ this.userService= new UserService(..).但是 UserService 有 constructor(private http: HttpClient) 看起来很乱。你有什么建议?是否需要重新初始化服务
  • 感谢您的评论和编辑的帖子。我想,我在本地存储中成功设置了变量。问题是 UserService 变量显示为未定义,如上所述。我需要重新初始化服务吗?如何最好地使用 HttpClient 参数?这是一个好方法吗?
猜你喜欢
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 1970-01-01
  • 2013-07-29
  • 2013-07-07
相关资源
最近更新 更多