Javascript 使用BehaviorSubject重新加载刷新期间角度视图组件数据丢失
我正在编写一个Angular9应用程序,其中有一个用例,我在3页之间缓冲数据(表单接受数据输入) 然后,在第4页,我以只读文本的形式显示了在3页中收集的详细信息的摘要 我使用以下文章实现了数据缓冲: 哪个使用行为主体 下面是我的数据服务逻辑:Javascript 使用BehaviorSubject重新加载刷新期间角度视图组件数据丢失,javascript,angular,typescript,angular9,angular-local-storage,Javascript,Angular,Typescript,Angular9,Angular Local Storage,我正在编写一个Angular9应用程序,其中有一个用例,我在3页之间缓冲数据(表单接受数据输入) 然后,在第4页,我以只读文本的形式显示了在3页中收集的详细信息的摘要 我使用以下文章实现了数据缓冲: 哪个使用行为主体 下面是我的数据服务逻辑: import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import
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 { 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>
打招呼
{{称呼}}
名字
{{firstName}}
数据显示在摘要页面上,如第1-3页表格所示,
但是数据在页面刷新或我的机器休眠时丢失
我读过关于本地和会话存储持久性的文章,从angularjs 1.x时代起就开始使用它。
很久以前,当数据消失在我的摘要屏幕上时,我真的很惊讶
我想理想的解决方案是当用户离开相关表单时,将数据存储在客户端存储中,然后在摘要页面上检索数据
我想,当第一次刷新或显示摘要页面时,
我将检查数据的存储并显示它是否存在。
若存储是空的,那个么我将在运行时使用上一页中的数据
请,我需要一个最佳实践和稳定的解决方案,这是跨浏览器友好和智能的商业应用程序的帮助
另外,一种适合Angular9 BehaviorSubject-rxjs堆栈或任何最新特性的方法,因为我知道AngularJs从AngularJs 1.x开始就有了发展
摘要详细信息仅在用户导航回任何页面1-3以更改表单详细信息时更改
我将感谢任何代码片段或参考,以保持在摘要页面上的数据
非常感谢。我建议您在Ngondestory生命周期钩子中的
Summary组件中使用本地存储。在组件因刷新而销毁之前,它将始终在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
}
继续使用您的解决方案,将项设置到本地存储的最佳选项是为服务设置值的位置。这可能是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));
}
根据注释中描述的问题编辑-2
我建议您直接在服务内部初始化行为主体
@Injectable({
providedIn: 'root'
})
export class UserService {
//Details Page 1
public salutation: BehaviorSubject<string> = new BehaviorSubject('');
public firstName: BehaviorSubject<string> = new BehaviorSubject('');
很明显,数据在刷新时会丢失。解决方案之一是将您的数据保存在本地存储器中,或者,如果数据不是来自用户的输入,请在刷新后从服务器重新获取数据。谢谢Stefan的快速回复。我找不到一个适合angular9的关于使用本地存储的好片段。想要重新保证最佳实践模式等这很可能是在不期望的情况下重新加载用户服务的问题。证明在ngOnInit中,将消息记录到控制台。然后重新创建问题。如果你看到不止一条消息……你可以考虑让行为主体静态化,这就需要更多的工作来确保内容始终是正确的内容。嗨,斯特凡,有一个去看结果:1)NGunDebug()不被刷新,但是当我点击浏览器后退按钮WChrome。{this.saltation=c | | | localStorage.getItem('saltation');})无法刷新(2)在page1组件中添加了逻辑localStorage.setItem('saltation',this.saltation));然后用户填写表单并转到摘要页面。摘要页面中ngOnInit第1行的Alert()确认从localstrorage检索数据,但saltation.subscribe(c=>{this.saltation=c | | | | localStorage.get('saltation');})不显示数据。在第1页组件中设置数据可以使用localStorage.getItem()在摘要页中使用数据。但是,刷新后,saltation.subscribe(c=>{this.saltation=c | | | | localStorage.get('saltation');});不工作。刷新似乎会删除以前发布的内容。能否添加console.log(localStorage.get('sallation'))在订阅中,当您完成从第一步到摘要的整个过程,然后刷新页面时?您还可以使用浏览器开发工具查看本地存储中设置的内容。早上好,Stefan,控制台中出现错误。TypeError:无法读取SummaryComponent.ngonit的undefined属性“subscribe”(summary.component.ts:67)刷新后出现问题。this.userService.sallation未定义。看起来数据服务变量需要在页面刷新后重新初始化。在summary组件中,我定义了一个变量未定义;然后检查(this.userService.sallation==未定义){this.userService=新userService(..).但是UserService有构造函数(私有http:HttpClient)看起来很混乱。你有什么建议吗?我需要重新初始化服务吗谢谢你的评论和编辑的帖子。我想,我正在本地存储中成功地设置变量。问题是UserService变量显示为如上所述的未定义。我需要重新初始化服务吗?如何最好地使用HttpClient参数?是这是一个好方法吗?
@Injectable({
providedIn: 'root'
})
export class UserService {
//Details Page 1
public salutation: BehaviorSubject<string> = new BehaviorSubject('');
public firstName: BehaviorSubject<string> = new BehaviorSubject('');
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));
}