13

我可以想象以下在多步骤表单之间交换数据的方法:

1)为每个表单步骤创建一个组件,并通过@input,@output在组件之间交换数据(例如,您不能从step5更改为2)

data2)在新路由器中使用新属性(见这里)(例如,你不能从第5步更改为第2步))

3)一个共享服务(依赖注入)来存储数据(组件交互)(例如,你可以从第5步更改为第2步)

4) @ngrx/store 的新基础(还没有真正体验过)

您能否给出一些“获得的经验值”,您使用什么以及为什么?

4

2 回答 2

15

请参阅下面的我的编辑。


在我看来,严格来说,使用SessionStorage并不是解决这个问题的“角度”方式——共享服务是要走的路。在步骤之间实现路由会更好(因为每个组件都可以有自己的形式和您认为合适的不同逻辑:

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)]]);

  };

}; 

祝你好运。


编辑 2016 年 12 月 6 日


实际上,现在使用表单 API 已经有一段时间了,我不相信我以前的答案是实现这一目标的最佳方法。

一种更可取的方法是创建一个顶层,在它的属性下FormGroup将多步表单中的每个步骤作为它自己的FormControl(一个FormGroup或一个 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];
       }
    }

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

于 2016-09-23T11:22:05.610 回答
9

为什么不使用会话存储?例如,您可以使用这个静态辅助类(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);
  }

}

并且使用上面的类,您可以将您的对象与多步骤形式的数据一起使用并共享它(想法类似于许多后端框架中的“会话助手”,例如 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;
     }
}

然后在引导应用程序的主文件中:

...
return bootstrap(App, [
  ...
  SessionService
])
...

最后一步——关键:当你想在你的组件中使用你的单例服务时——不要把 int 放在提供者部分(这是由于 angular2 DI 行为——阅读上面关于单例服务的链接)。下面的示例从表格步骤 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)
  }

}

它应该看起来像这样。

于 2016-07-11T17:40:20.377 回答