Angular 2 - 如何使用下拉列表的值生成表单?

Posted

技术标签:

【中文标题】Angular 2 - 如何使用下拉列表的值生成表单?【英文标题】:Angular 2 - how to generate forms with the values of a dropdown list? 【发布时间】:2018-07-04 13:56:55 【问题描述】:

我需要一些建议来在我的 angular2 应用程序中实现表单。

我有一个情境对象,它包含三个重要的东西:id、name、type 在一个表单中,我创建了一个带有情况名称的下拉列表(我使用服务来获取列表并使用 ngFor 指令来显示) 根据所选情况的类型,我用那些自己的formControls构建了一个formGroup(我在下拉列表中使用了onChange函数) 我使用类型来显示模板中的新输入(许多情况可以具有相同的类型)。 我的模板中有此代码的问题,当我选择一个值时,所选值不再出现...

下面是我的代码的 sn-p,以了解我在说什么:

模板

<form [formGroup]="myForm" (ngSubmit)="saveForm()" novalidate> 
  <select class="form-control" [(ngModel)]="selectedSituation" (change)="onChangeSituation()" formControlName="name">
   <option [ngValue]="situation" *ngFor="let situation of situationsArray">situation.name</option>  
  </select>

  <div *ngIf="selectedSituation?.type == 1">
     <!-- some fields -->
  </div>

  <div *ngIf="selectedSituation?.type == 2">
     <!-- other fields -->
  </div>
</form>

组件

situationsArray: string[];
selectedSituation: any;
type: any;

constructor(
    private _fb: FormBuilder
)  

createDefaultForm()
  this.myForm = this._fb.group(
    name: ['', Validators.required]
    // inputs not concerning by dropdown list
  );


createType1Form()
  this.myForm = this._fb.group(
    name: ['', Validators.required]
    // inputs for type = 1
  );


createType2Form()
  this.myForm = this._fb.group(
    name: ['', Validators.required]
    // inputs for type = 2
  );


ngOnInit()
  this.createDefaultForm();   // a formGroup for the inputs who aren't concerned by the dropdwon list
  this.getListSituations();   // a service to get the situations list


onChangeSituation(): void  
  console.log(this.selectedSituation);
  if(this.selectedSituation.type == 1) 
    this.createJobForm();
     else 
      if(this.selectedSituation.type == 2) 
        this.createPeForm();
       else 
        if(this.selectedSituation.type == 3) 
          this.createPeaForm();
         else 
          this.createDefaultForm();

您对显示问题有任何想法吗? 也许我使用了错误的做法......

我现在被困了一段时间,欢迎您的所有建议,谢谢。

【问题讨论】:

【参考方案1】:

问题:

您在构建表单时正在重置 name 表单控件

您正在使用一个对象作为选择的值。即使您没有上述问题,Angular 也无法在不相互引用的情况下匹配对象值。

其次,就像其他答案中提到的那样,不要混合模板驱动和反应式表单,它们真的不适合。

我要做的是更改选择,例如您正在寻找的type,然后为条件字段创建一个子表单组。这样,您只需切换子组,而无需重建所有常见(如果有的话)字段。所以像....(缩短的代码)

createDefaultForm() 
  this.myForm = this._fb.group(
    name: ['', Validators.required],
    // other inputs
    subGroup: this._fb.group()
  );

您选择切换子组的选项:

<select class="form-control" (change)="createSubForm()" formControlName="name">
 <option [ngValue]="situation.type" *ngFor="let situation of situationsArray">
   situation.name
 </option>  

然后是方法createSubGroup

createSubForm() 
  if (this.myForm.controls.name.value === 1) 
    this.myForm.setControl('subGroup', this.createType1Form())
   else 
    this.myForm.setControl('subGroup', this.createType2Form())
  


createType1Form() 
  return this._fb.group(
    name1: ['type1', Validators.required]
    // inputs for type = 1
  );


createType2Form() 
  return this._fb.group(
    name2: ['type2', Validators.required]
    // inputs for type = 2
  );

展示此内容的 StackBlitz:DEMO

【讨论】:

【参考方案2】:

您将反应驱动的表单构建与模板驱动的表单构建混合在一起。

指令“[(ngModel)]”用于模板驱动的表单。

你需要把模板改成这样:

  <select class="form-control" formControlName="name">
    <option [value]="situation.type" *ngFor="let situation of situationsArray">
      situation.name
    </option>  
  </select>

This will display situation.name's in the dropdown, and when one is selected, the value of the formControl will be set to situation.type.

在您的 ngOnInit 中:

this.myForm.controls['name'].valueChanges.subscribe(
  value => 
    console.log(value);
    onChangeSituation(value);
  
);

然后将您的 onChangeSituation() 更改为:

onChangeSituation(newValue: number): void
  switch(newValue) 
    case 1:
      this.createJobForm();
      break;
    case 2:
      this.createPeForm();
      break;
    case 3:
      this.createPeaForm();
      break;
    default:
      this.createDefaultForm();
      break;
  

我假设 newValue 是一个数字。

编辑

但是,使用此解决方案,由于您创建了对表单控件的 valueChanges 的订阅,因此在销毁组件时需要取消订阅。有几种方法可以实现这一目标。问题描述为here。

推荐的解决方案描述为here。所以我会这样做:

在您的组件中添加一个新变量(主题):

destroy$: Subject<boolean> = new Subject<boolean>();

将订阅行修改为:

this.myForm.controls['name'].valueChanges.takeUntil(this.destroy$).subscribe(

添加 ngOnDestroy 方法:

  ngOnDestroy() 
    this.destroy$.next(true);
    // Now let's also unsubscribe from the subject itself:
    this.destroy$.unsubscribe();
  

并修改你的组件类的签名来实现它:

export class MyComponent implements OnInit, OnDestroy 

还有另一个解决方案 here 用于销毁订阅以及更多 here - 我建议阅读 cmets 和那里的各种答案。

【讨论】:

【参考方案3】:

我认为问题在于表单内部。每次您构建一个新表单时,您都会生成一个新的选择,但这没有任何价值。尝试将选择移出

【讨论】:

以上是关于Angular 2 - 如何使用下拉列表的值生成表单?的主要内容,如果未能解决你的问题,请参考以下文章

根据下拉列表的值创建 2 个下拉列表和一个表

如何根据下拉列表选择的值更改表中的数据

Angular / RxJs对一个observable的多个订阅

我如何从 mvc 的剑道 ui 网格的下拉列表中获取选定的值

如何在下拉列表中获取每个项目的不同悬停值?

如何在 asp.net 中使用 select2 返回下拉列表的值?