如何在@ngrx/store中存储状态并保留Angular表单数据?
解决Angular步骤切换时表单数据丢失问题
问题根源
当前NgRx仅维护了步骤切换的状态,但表单数据未被持久化到Store中。当通过ng-container切换组件时,组件会被销毁重建,导致表单数据重置。另外,SharedService中获取步骤的选择器路径错误,应该选择currentStep而非step。
具体修复步骤
1. 更新AppState与Actions
首先扩展状态模型,加入表单数据字段,并创建对应的更新动作:
app.actions.ts
import { createAction, props } from '@ngrx/store'; import { Step } from './main'; export const setCurrentStep = createAction( '[App] Set Current Step', props<{ step: Step }>() ); // 添加更新表单数据的action export const updateFormData = createAction( '[App] Update Form Data', props<{ formData: any }>() // 建议替换为具体的表单数据类型,比如interface FormData { name: string; email: string; } );
app.state.ts
import { Step } from './main'; // 定义表单数据的接口,替换为实际的表单字段 export interface FormData { // 示例字段,根据实际表单调整 name: string; email: string; } export interface AppState { currentStep: Step; formData: FormData; // 添加表单数据状态 }
2. 更新Reducer处理表单数据
修改reducer,初始化表单数据,并处理updateFormData动作:
app.reducer.ts
import { createReducer, on } from '@ngrx/store'; import { setCurrentStep, updateFormData } from './app.actions'; import { AppState, FormData } from './app.state'; import { Step } from './main'; // 初始化表单数据 const initialFormData: FormData = { name: '', email: '' }; export const initialState: AppState = { currentStep: 1, formData: initialFormData }; export const appReducer = createReducer( initialState, on(setCurrentStep, (state, { step }) => ({ ...state, currentStep: step, })), // 添加处理表单数据更新的逻辑 on(updateFormData, (state, { formData }) => ({ ...state, formData: { ...state.formData, ...formData } // 合并更新,保留原有字段 })) );
3. 修正SharedService的选择器并添加表单数据方法
修复步骤选择器的错误路径,同时添加操作表单数据的方法:
shared-service.service.ts
import { Injectable } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { AppState, FormData } from './app.state'; import { Observable } from 'rxjs'; import { setCurrentStep, updateFormData } from './app.actions'; import { Step } from './main'; @Injectable() export class SharedServiceService { constructor(private store: Store<AppState>) {} setCurrentStep(step: Step) { this.store.dispatch(setCurrentStep({ step })); } // 修复选择器路径,改为currentStep getCurrentStep(): Observable<Step> { return this.store.pipe(select(state => state.currentStep)); } // 添加更新表单数据的方法 updateFormData(formData: Partial<FormData>) { this.store.dispatch(updateFormData({ formData })); } // 添加获取表单数据的方法 getFormData(): Observable<FormData> { return this.store.pipe(select(state => state.formData)); } }
4. 在Comp1组件中绑定表单数据到Store
修改Comp1组件,在表单数据变化时同步到Store,初始化时从Store加载数据:
comp-1.component.ts
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { SharedServiceService } from 'src/shared-service.service'; import { FormData } from 'src/app.state'; @Component({ selector: 'app-comp-1', templateUrl: './comp-1.component.html', }) export class Comp1Component implements OnInit { form: FormGroup; constructor( private fb: FormBuilder, private sharedService: SharedServiceService ) { this.form = this.fb.group({ name: [''], email: [''] }); } ngOnInit(): void { // 从Store加载表单数据,回显到表单 this.sharedService.getFormData().subscribe(formData => { this.form.patchValue(formData); }); // 监听表单变化,同步到Store this.form.valueChanges.subscribe(formData => { this.sharedService.updateFormData(formData); }); } goToNextStep() { this.sharedService.setCurrentStep(2); } }
5. 可选优化:避免组件销毁
如果不想依赖Store持久化,也可以通过调整ng-container的渲染逻辑,使用[hidden]替代*ngIf,这样组件不会被销毁,数据会保留:
<ng-container [hidden]="currentStep !== 1"> <app-comp-1></app-comp-1> </ng-container> <ng-container [hidden]="currentStep !== 2"> <app-comp-2></app-comp-2> </ng-container>
但这种方式会让组件始终存在于DOM中,对于复杂组件可能影响性能,推荐优先使用Store持久化的方案。
内容的提问来源于stack exchange,提问作者Netranjit Borgohain
相关产品推荐
相关产品推荐

