在 formArray Angular 中选择独立的选项

Posted

技术标签:

【中文标题】在 formArray Angular 中选择独立的选项【英文标题】:select option independent in formArray Angular 【发布时间】:2022-01-13 01:25:34 【问题描述】:

晚上好,我有一个问题,我使用的是反应式表单,使用 FormArray,我有一个按钮可以根据需要多次添加 2 个选项,问题是这些选项是 matselects,我在其中一个选择中使用一个事件(更改),问题是第一次添加选项 onchange 工作正常,但是当添加选项超过 2 倍时,之前在 matselects 中选择的值会发生变化,因为创建的 select 的 onchange 是 re -执行。 我想知道是否有办法在 formArray 的每次迭代中独立使用该事件

组件.ts

alicuotaForm: FormGroup;
  value = this.fb.group(
    manzana: ['', Validators.required],
    villa: ['', Validators.required],
  );
  nregistros: number;

 ngOnInit() 
    this.alicuotaForm = this.fb.group(
      times: this.fb.array([]),
    );
  

//event onchange
  getVillas(value) 
    console.log('valor: ', value.value);
    this.filtro = this.villas.filter((x) => x.manzana == value.value);
  
  addGroup() 
    const val = this.fb.group(
      manzana: ['', Validators.required],
      villa: ['', Validators.required],
    );
    const alicuotaForm = this.alicuotaForm.get('times') as FormArray;
    alicuotaForm.push(val);
    this.nregistros = alicuotaForm.length;
  

  removeGroup(index) 
    const alicuotaForm = this.alicuotaForm.get('times') as FormArray;
    alicuotaForm.removeAt(index);
  

  trackByFn(index: any, item: any) 
    return index;
  

component.html

<div class="container">
  <div class="row">
    <div class="col-col-6">
      <label class="transparente"></label>
      <button (click)="addGroup()" type="button" class="btn btn-success">
        Agregar Campos
      </button>
    </div>
    <br />
    <form [formGroup]="alicuotaForm">
      <ng-container
        formArrayName="times"
        *ngFor="
          let time of alicuotaForm.controls.times?.value;
          let i = index;
          trackBy: trackByFn
        "
      >
        <ng-container [formGroupName]="i" style="margin-bottom: 10px;">
          Iteracion  i + 1 
          <div class="col-col-6">
            <label>Manzana</label>
            <select
              formControlName="manzana"
              class="form-control custom-select"
              (change)="getVillas($event.target)"
            >
              >
              <option *ngFor="let ur of manzanas">
                 ur.manzana 
              </option>
            </select>
          </div>
          <br />

          <div class="col-sm">
            <label>Villa</label>
            <select formControlName="villa" class="form-control custom-select">
              <option *ngFor="let ur of filtro" value=" ur.villa ">
                 ur.villa 
              </option>
            </select>
          </div>
          <br />
          ------------------------------------------------------------------------<br /> </ng-container
      ></ng-container>
    </form>
  </div>
</div>

我不知道我能做什么或者你会建议我解决什么 我的问题,非常感谢

stackblitz 中的代码 Stackblitz

【问题讨论】:

【参考方案1】:

您必须为 filtro 创建单独的值,您可以从以下代码中获得帮助

HTML

<hello name=" name "></hello>
<p>Start editing to see some magic happen :)</p>
<div class="container">
 <div class="row">
<div class="col-col-6">
  <label class="transparente"></label>
  <button (click)="addGroup()" type="button" class="btn btn-success">
    Agregar Campos filtro
  </button>
</div>
<br />
<form [formGroup]="alicuotaForm">
  <ng-container
    formArrayName="times"
    *ngFor="
      let time of alicuotaForm.controls.times?.value;
      let i = index;
      trackBy: trackByFn
    "
  >
    <ng-container [formGroupName]="i" style="margin-bottom: 10px;">
      Iteracion  i + 1 
      <div class="col-col-6">
        <label>Manzana</label>
        <select
          formControlName="manzana"
          class="form-control custom-select"
          (change)="getVillas($event.target, i)"
        >
          >
          <option *ngFor="let ur of manzanas">
             ur.manzana 
          </option>
        </select>
      </div>
      <br />

      <div class="col-sm">
        <label>Villa</label>
        <select formControlName="villa" class="form-control custom-select">
          <option *ngFor="let ur of filtro[i]" value=" ur.villa ">
             ur.villa 
          </option>
        </select>
      </div>
      <br />
      ------------------------------------------------------------------------<br /> </ng-container
  ></ng-container>
</form>

打字稿

  import  Component, VERSION  from '@angular/core';
  import 
    FormControl,
    FormGroup,
    FormBuilder,
    FormArray,
    Validators,
    FormGroupDirective,
  from '@angular/forms';

  @Component(
    selector: 'my-app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
  )
 export class AppComponent 
name = 'Angular ' + VERSION.major;
villas = [
   manzana: '1', villa: '10' ,
   manzana: '1', villa: '20' ,
   manzana: '1', villa: '30' ,
   manzana: '2', villa: '40' ,
   manzana: '2', villa: '50' ,
   manzana: '2', villa: '60' ,
   manzana: '3', villa: '70' ,
   manzana: '3', villa: '80' ,
   manzana: '3', villa: '90' ,
];
filtro: any[]=[];
manzanas = [ manzana: '1' ,  manzana: '2' ,  manzana: '3' ];
alicuotaForm: FormGroup;
value = this.fb.group(
  manzana: ['', Validators.required],
  villa: ['', Validators.required],
);
nregistros: number;

constructor(private fb: FormBuilder) 

ngOnInit() 
  this.alicuotaForm = this.fb.group(
    times: this.fb.array([]),
  );

getVillas(value,index) 
  console.log('valor: ', value.value);
  this.filtro[index] = this.filtro[index].filter(x => x.manzana === value.value);

addGroup() 
  const val = this.fb.group(
    manzana: ['', Validators.required],
    villa: ['', Validators.required],
  );
  
  const alicuotaForm = this.alicuotaForm.get('times') as FormArray;
  alicuotaForm.push(val);
  this.nregistros = alicuotaForm.length;
  this.filtro.push(null);
  this.filtro[this.nregistros-1]=[...this.villas];


removeGroup(index) 
  const alicuotaForm = this.alicuotaForm.get('times') as FormArray;
  alicuotaForm.removeAt(index);


trackByFn(index: any, item: any) 
  return index;

  

【讨论】:

【参考方案2】:

据我所知,您的主要问题是您有一个变量filtro,您试图将其用于FormArray 中的所有元素。您可以:

    (我推荐)创建自定义Pure 管道以返回过滤后的别墅列表。纯管道只会在值发生变化时执行,而不是在每个绘制周期中执行。
import  Pipe, PipeTransform  from '@angular/core';

@Pipe( name: 'arrayFilter' )
export class ArrayFilterPipe implements PipeTransform 
  transform(arr: any[], property: string, value: any): any 
    return arr.filter((x) => x[property] === value);
  

然后你在你的模板中使用它(不要忘记在你的模块中声明它):

<select formControlName="villa" class="form-control custom-select">
  <option
    *ngFor="let ur of (villas | arrayFilter: 'manzana': time.manzana)"
    value=" ur.villa "
  >
     ur.villa 
  </option>
</select>

打字稿:

addGroup() 
    // either provide a '' option to this.manzanas, or set manzana: '1' to avoid expression after checked errors
    const val = this.fb.group(
      manzana: ['1', Validators.required],
      villa: ['', Validators.required],
    );
    const alicuotaForm = this.alicuotaForm.get('times') as FormArray;
    alicuotaForm.push(val);
    this.nregistros = alicuotaForm.length;
  

有关详细信息,请参阅Pipes。

    在您的组上创建另一个名为filtro 的表单控件,并在getVillas 函数中设置它的值。然后,当您为表单控件 villa 执行 *ngFor 时,您将引用此表单控件的值 在您的组件中创建一个函数,根据数组项的 manzana 过滤别墅(不推荐,因为这会重新计算每个绘制周期)。

【讨论】:

以上是关于在 formArray Angular 中选择独立的选项的主要内容,如果未能解决你的问题,请参考以下文章

无法根据角度formarray下拉选择显示/隐藏div [关闭]

FormArray 和 formGroup 中的 Angular Material mat-select

如何在 FormArray 中设置 FormControl 的值

在 Angular 2+ 中对 FormArray 对象进行排序的理想方法是啥?

Angular 2在formArrays上找不到具有未指定名称属性的控件

从 Angular 中的 FormArray 中删除所有项目