在 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];
       }
    }

因此,表单的状态和每个步骤都准确地保存在它应该在的位置——在表单本身!