在 Angular2 中的多步表单之间交换数据:经过验证的方法是什么?
Exchange Data between multi step forms in Angular2: What is the proven way?
我可以想象以下方法在多步骤表单之间交换数据:
1) 为每个表单步骤创建一个组件,并通过@input、@output 在组件之间交换数据(例如,您不能从第 5 步更改为第 2 步)
2) 在新路由器中使用新的 属性 data
()(例如,您不能从第 5 步更改为第 2 步))
3) 共享服务 (Dependency Injection) to store data (Component Interaction)(例如,您可以从第 5 步更改为第 2 步)
4) @ngrx/store的新手(还没真正体验过)
你能给一些吗"gained experience values",你用什么,为什么?
为什么不使用会话存储?例如你可以使用这个静态助手 class (TypeScript):
export class Session {
static set(key:string, value:any) {
window.sessionStorage.setItem(key, JSON.stringify(value));
}
static get(key:string) {
if(Session.has(key)) return JSON.parse(window.sessionStorage[key])
return null;
}
static has(key:string) {
if(window.sessionStorage[key]) return true;
return false;
}
static remove(key:string) {
Session.set(key,JSON.stringify(null)); // this line is only for IE11 (problems with sessionStorage.removeItem)
window.sessionStorage.removeItem(key);
}
}
并使用上面的 class,您可以将您的对象与多步骤形式的数据放在一起并共享它(想法类似于 'session helper' 在许多后端框架中,例如 php laravel).
另一种方法是创建 。它看起来像那样(为了清楚起见,非常简单)(我没有测试下面的代码,我从头开始):
import { Injectable } from '@angular/core';
@Injectable()
export class SessionService {
_session = {};
set(key:string, value:any) {
this._session[key]= value; // You can also json-ize 'value' here
}
get(key:string) {
return this._session[key]; // optionally de-json-ize here
}
has(key:string) {
if(this.get(key)) return true;
return false;
}
remove(key:string) {
this._session[key]=null;
}
}
然后在 bootstrap 应用程序所在的主文件中:
...
return bootstrap(App, [
...
SessionService
])
...
最后一步 - 关键:当你想在你的组件中使用单例服务时 - 不要将 int 放在提供者部分(这是由于 angular2 DI 行为 - 阅读上面 link 关于单例服务)。下面的示例从表单步骤 2 转到步骤 3:
import {Component} from '@angular/core';
import {SessionService} from './sessionService.service';
...
@Component({
selector: 'my-form-step-2',
// NO 'providers: [ SessionService ]' due to Angular DI behavior for singletons
template: require('./my-form-step-2.html'),
})
export class MyFormStep2 {
_formData = null;
constructor(private _SessionService: SessionService) {
this._formData = this._SessionService.get('my-form-data')
}
...
submit() {
this._SessionService.set('my-form-data', this._formData)
}
}
看起来应该是这样的。
请参阅下面我的编辑。
在我看来,使用 SessionStorage
并不是严格意义上的 'angular' 方法——共享服务才是解决之道。在步骤之间实现路由会更好(因为每个组件都可以有自己的形式和不同的逻辑,如您所见:
const multistepRoutes: Routes = [
{
path: 'multistep',
component: MultistepComponent,
children: [
{
path: '',
component: MultistepBaseComponent,
},
{
path: 'step1',
component: MultistepStep1Component
},
{
path: 'step2',
component: MultistepStep2Component
}
]
}
];
服务 multistep.service
可以保存模型并为组件实现逻辑:
import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router';
@Injectable()
export class MultistepService {
public model = {};
public baseRoute = '/multistep';
public steps = [
'step1',
'step2'
];
constructor (
@Inject(Router) public router: Router) { };
public getInitialStep() {
this.router.navigate([this.baseRoute + '/' + this.steps[0]]);
};
public goToNextStep (direction /* pass 'forward' or 'backward' to service from view */): any {
let stepIndex = this.steps.indexOf(this.router.url.split('/')[2]);
if (stepIndex === -1 || stepIndex === this.steps.length) return;
this.router.navigate([this.baseRoute + '/' + this.steps[stepIndex + (direction === 'forward' ? 1 : -1)]]);
};
};
祝你好运。
编辑 12/6/2016
实际上,现在使用表单 API 一段时间后,我认为我之前的回答不是实现此目的的最佳方法。
一种更可取的方法是创建一个顶层 FormGroup
,它在您的多步骤表单中的每个步骤都是它自己的 FormControl
(或者 FormGroup or a FormArray)在其 controls
属性。在这种情况下,顶级表单将是表单状态的单一真实来源,并且创建的每个步骤(ngOnInit /构造函数)都能够从顶级读取其各自步骤的数据FormGroup
.见伪代码:
const topLevelFormGroup = new FormGroup({
step1: new FormGroup({fieldForStepOne: new FormControl('')}),
step2: new FormGroup({fieldForStepTwo}),
// ...
});
...
// Step1Component
class Step1Component {
private stepName: string = 'step1';
private formGroup: FormGroup;
constructor(private topLevelFormGroup: any /* DI */) {
this.formGroup = topLevelFormGroup.controls[this.stepName];
}
}
因此,表单的状态和每个步骤都准确地保存在它应该在的位置——在表单本身!
我可以想象以下方法在多步骤表单之间交换数据:
1) 为每个表单步骤创建一个组件,并通过@input、@output 在组件之间交换数据(例如,您不能从第 5 步更改为第 2 步)
2) 在新路由器中使用新的 属性 data
(
3) 共享服务 (Dependency Injection) to store data (Component Interaction)(例如,您可以从第 5 步更改为第 2 步)
4) @ngrx/store的新手(还没真正体验过)
你能给一些吗"gained experience values",你用什么,为什么?
为什么不使用会话存储?例如你可以使用这个静态助手 class (TypeScript):
export class Session {
static set(key:string, value:any) {
window.sessionStorage.setItem(key, JSON.stringify(value));
}
static get(key:string) {
if(Session.has(key)) return JSON.parse(window.sessionStorage[key])
return null;
}
static has(key:string) {
if(window.sessionStorage[key]) return true;
return false;
}
static remove(key:string) {
Session.set(key,JSON.stringify(null)); // this line is only for IE11 (problems with sessionStorage.removeItem)
window.sessionStorage.removeItem(key);
}
}
并使用上面的 class,您可以将您的对象与多步骤形式的数据放在一起并共享它(想法类似于 'session helper' 在许多后端框架中,例如 php laravel).
另一种方法是创建
import { Injectable } from '@angular/core';
@Injectable()
export class SessionService {
_session = {};
set(key:string, value:any) {
this._session[key]= value; // You can also json-ize 'value' here
}
get(key:string) {
return this._session[key]; // optionally de-json-ize here
}
has(key:string) {
if(this.get(key)) return true;
return false;
}
remove(key:string) {
this._session[key]=null;
}
}
然后在 bootstrap 应用程序所在的主文件中:
...
return bootstrap(App, [
...
SessionService
])
...
最后一步 - 关键:当你想在你的组件中使用单例服务时 - 不要将 int 放在提供者部分(这是由于 angular2 DI 行为 - 阅读上面 link 关于单例服务)。下面的示例从表单步骤 2 转到步骤 3:
import {Component} from '@angular/core';
import {SessionService} from './sessionService.service';
...
@Component({
selector: 'my-form-step-2',
// NO 'providers: [ SessionService ]' due to Angular DI behavior for singletons
template: require('./my-form-step-2.html'),
})
export class MyFormStep2 {
_formData = null;
constructor(private _SessionService: SessionService) {
this._formData = this._SessionService.get('my-form-data')
}
...
submit() {
this._SessionService.set('my-form-data', this._formData)
}
}
看起来应该是这样的。
请参阅下面我的编辑。
在我看来,使用 SessionStorage
并不是严格意义上的 'angular' 方法——共享服务才是解决之道。在步骤之间实现路由会更好(因为每个组件都可以有自己的形式和不同的逻辑,如您所见:
const multistepRoutes: Routes = [
{
path: 'multistep',
component: MultistepComponent,
children: [
{
path: '',
component: MultistepBaseComponent,
},
{
path: 'step1',
component: MultistepStep1Component
},
{
path: 'step2',
component: MultistepStep2Component
}
]
}
];
服务 multistep.service
可以保存模型并为组件实现逻辑:
import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router';
@Injectable()
export class MultistepService {
public model = {};
public baseRoute = '/multistep';
public steps = [
'step1',
'step2'
];
constructor (
@Inject(Router) public router: Router) { };
public getInitialStep() {
this.router.navigate([this.baseRoute + '/' + this.steps[0]]);
};
public goToNextStep (direction /* pass 'forward' or 'backward' to service from view */): any {
let stepIndex = this.steps.indexOf(this.router.url.split('/')[2]);
if (stepIndex === -1 || stepIndex === this.steps.length) return;
this.router.navigate([this.baseRoute + '/' + this.steps[stepIndex + (direction === 'forward' ? 1 : -1)]]);
};
};
祝你好运。
编辑 12/6/2016
实际上,现在使用表单 API 一段时间后,我认为我之前的回答不是实现此目的的最佳方法。
一种更可取的方法是创建一个顶层 FormGroup
,它在您的多步骤表单中的每个步骤都是它自己的 FormControl
(或者 FormGroup or a FormArray)在其 controls
属性。在这种情况下,顶级表单将是表单状态的单一真实来源,并且创建的每个步骤(ngOnInit /构造函数)都能够从顶级读取其各自步骤的数据FormGroup
.见伪代码:
const topLevelFormGroup = new FormGroup({
step1: new FormGroup({fieldForStepOne: new FormControl('')}),
step2: new FormGroup({fieldForStepTwo}),
// ...
});
...
// Step1Component
class Step1Component {
private stepName: string = 'step1';
private formGroup: FormGroup;
constructor(private topLevelFormGroup: any /* DI */) {
this.formGroup = topLevelFormGroup.controls[this.stepName];
}
}
因此,表单的状态和每个步骤都准确地保存在它应该在的位置——在表单本身!