javascript - 使用 BehaviorSubject 重新加载刷新期间的角度视图组件数据丢失
问题描述
我正在编写一个带有用例的 Angular9 应用程序,其中我在 3 个页面之间缓冲数据(表单接受数据输入)。
然后,在第 4 页,我将 3 页中收集的详细信息摘要显示为只读文本。
我使用以下文章实现了数据缓冲:
哪个使用 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);
}
}
下面是我的最终/摘要视图组件的片段
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 页以更改表单详细信息时,才会更改摘要详细信息。
我将不胜感激任何代码片段或参考,以将数据保留在摘要页面上。
非常感谢。
解决方案
我会建议您SummaryComponent
在 ngOnDestroy 生命周期挂钩内使用 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));
}
推荐阅读
- javascript - div 容器伸展超过 100% 的高度
- python - 如何在没有嵌套循环的情况下检查两个模型 ID?
- node.js - 根据 mongoDB 中的条件更新嵌套数组中的字段
- arrays - 如何从 k 个交换中的 2 个数组中获得最小加法结果?
- azure-web-app-service - Azure Web 应用程序中的 TCP 端口有什么限制?
- highcharts - yAxis调整大小来改变svgrenderer的位置也是highcharts
- python - 无法使用 shell 脚本调用 python 函数
- algorithm - 子图上的 MST 递归构造
- sql - 我需要对 (Account No_) 列的计数求和,并得到高于 2 的结果
- c# - 实体框架:根据父实体上的值对子实体进行索引以实现唯一性