Angular Material MatChipList - 如何在动态 FormArray 上使用它? [英] Angular Material MatChipList - how to use it on a Dynamic FormArray?

查看:32
本文介绍了Angular Material MatChipList - 如何在动态 FormArray 上使用它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

StackBlitz

这是我的 FormArray(变体):

this.productGroup = this.fb.group({姓名: '',变体:this.fb.array([这个.fb.group({类型: '',选项: ''})])})

我使用 MatChips 来存储字符串数组.这个数组需要传递给options:

<div [formGroupName]="i"><div class="row"><mat-form-field class="col-12"><input formControlName="type"></mat-form-field>

<div class="row"><mat-form-field class="col-12"><mat-chip-list #chipList><mat-chip *ngFor="let opt of typesOptions" [selectable]="true"[removable]="true" (removed)="removeOpt(opt)">{{选择}}<mat-icon matChipRemove>取消</mat-icon></mat-chip><input placeholder="Conjunto de opções deste Tipo"表单控件名称=选项"[matChipInputFor]="chipList"[matChipInputSeparatorKeyCodes]="separatorKeysCodes"[matChipInputAddOnBlur]="true"(matChipInputTokenEnd)="addOpt($event)"></mat-chip-list></mat-form-field>

<div class="row"><a href="javascript:" (click)="addItem()">添加变体</a><a href="javascript:" (click)="removeItem(i)" *ngIf="i > 0">删除变体 </a>

方法如下:

//动态方法添加项目():无效{this.variantsArray = this.productGroup.get('variants') as FormArray;this.variantsArray.push(this.fb.group({类型: '',选项: ''}));}删除项目(索引:数字){this.variantsArray.removeAt(index);}//MatChip 方法addOpt(item: number, event: MatChipInputEvent): void {const input = event.input;常量值 = event.value;//添加我们的水果if ((value || '').trim()) {this.typesOptions.push(value.trim());}//重置输入值如果(输入){输入值 = '';}}removeOpt(选择:字符串):无效{const index = this.typesOptions.indexOf(opt);如果(索引> = 0){this.typesOptions.splice(index, 1);}

我已成功将动态字段添加到我的 variants formArray.但是 MatChipList 对于每个动态字段都是相同的.我还需要使 MatChipList 动态化.有没有办法实现这一目标?就像改变 或类似的东西.

StackBlitz

解决方案

我不确定 dom 引用变量 #chiplist 是否有问题.看起来 matChipList 由 typesOptions 数组支持,但您只有一个数组.因此,每次添加 matChipList 组件时,它仍然与所有其他组件由相同的数组支持.您需要有一个 typesOptions 数组,一个数组数组.然后,当您添加项目时,您还将一个新的子数组推送到 typesOptions(并类似地为 removeItem 删除一个).

我还没有编写代码,只是查看代码的建议.

编辑 - 根据 James 的 stackblitz 编写了一个解决方案.

https://stackblitz.com/edit/angular-3od6rd-jkidxf

注意我没有详细研究删除变体如何保持在一起,理想情况下我可能想使用键/值对来跟踪使用 dom 输入元素 id 作为键的变体选项(在MatChipInputEvent),而不是依赖于外循环索引.

stackblitz 中的一些代码:

export class ChipsOverviewExample {产品组:表单组;变体数组:表格数组;类型选项数组:字符串[][] = [];readonly separatorKeysCodes: number[] = [ENTER, COMMA];构造函数(私有 fb:FormBuilder){}ngOnInit() {this.productGroup = this.fb.group({姓名: '',变体:this.fb.array([这个.fb.group({类型: '',选项: ''})]),});this.typesOptionsArray.push([]);}保存产品(形式:FormGroup){控制台日志(表单);}//向 FormArray 添加新项添加项目():无效{this.variantsArray = this.productGroup.get('variants') as FormArray;this.variantsArray.push(this.fb.group({类型: '',选项: ''}));this.typesOptionsArray.push([]);}删除项目(索引:数字){this.variantsArray.removeAt(index);}addOpt(event: MatChipInputEvent, index: number): void {const input = event.input;常量值 = event.value;//添加我们的水果if ((value || '').trim()) {this.typesOptionsArray[index].push(value.trim());}//重置输入值如果(输入){输入值 = '';}}removeOpt(opt: string, index: number): void {const optIndex = this.typesOptionsArray[index].indexOf(opt);如果 (optIndex >= 0) {this.typesOptionsArray[index].splice(optIndex, 1);}}}

StackBlitz

Here is my FormArray (variants):

this.productGroup = this.fb.group({
    name: '',
    variants: this.fb.array([
      this.fb.group({
        type: '',
        options: ''
      })
    ])
})

I'm using MatChips to store a string array. This array needs to be passed to options:

<div formArrayName="variants" *ngFor="let item of productGroup.controls['variants'].controls; let i = index;">
  <div [formGroupName]="i">
    <div class="row">
      <mat-form-field class="col-12">
        <input formControlName="type">
      </mat-form-field>
    </div>
    <div class="row">
      <mat-form-field class="col-12">
        <mat-chip-list #chipList>
          <mat-chip *ngFor="let opt of typesOptions" [selectable]="true"
                    [removable]="true" (removed)="removeOpt(opt)">
            {{opt}}
            <mat-icon matChipRemove>cancel</mat-icon>
          </mat-chip>
          <input placeholder="Conjunto de opções deste Tipo"
                  formControlName="options"
                  [matChipInputFor]="chipList"
                  [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
                  [matChipInputAddOnBlur]="true"
                  (matChipInputTokenEnd)="addOpt($event)">
        </mat-chip-list>
      </mat-form-field>
    </div>
  </div>
  <div class="row">
    <a href="javascript:" (click)="addItem()"> Add Variants </a>
    <a href="javascript:" (click)="removeItem(i)" *ngIf="i > 0"> Remove Variants </a>
  </div>
</div>

Here is the methods:

// Dynamic Methods
  addItem(): void {
    this.variantsArray = this.productGroup.get('variants') as FormArray;
    this.variantsArray.push(this.fb.group({
      type: '',
      options: ''
    }));
  }
  removeItem(index: number) {
    this.variantsArray.removeAt(index);
  }

// MatChip Methods
  addOpt(item: number, event: MatChipInputEvent): void {
    const input = event.input;
    const value = event.value;
    // Add our fruit
    if ((value || '').trim()) {
      this.typesOptions.push(value.trim());
    }
    // Reset the input value
    if (input) {
      input.value = '';
    }
  }
  removeOpt(opt: string): void {
    const index = this.typesOptions.indexOf(opt);
    if (index >= 0) {
      this.typesOptions.splice(index, 1);
    }

I'm successfully adding dynamic fields to my variants formArray. However MatChipList is the same for every dynamic field. I need to make MatChipList dynamic as well. Is there a way to achieve this? Like changing <mat-chip-list #chipList+i> or something like that.

EDIT: StackBlitz

解决方案

I'm not sure the dom reference variable #chiplist is the issue. It looks like the matChipList is backed by the typesOptions array, but you only have one array. So every time you add a matChipList component it is still being backed by the same array as all the others. You need to have an array of typesOptions, an array of arrays. Then when you addItem, you also push a new sub array to typesOptions (and similarly remove one for removeItem).

I haven't coded this up, just a suggestion from looking at the code.

Edit - coded up a solution based on James's stackblitz.

https://stackblitz.com/edit/angular-3od6rd-jkidxf

Note I haven't looked in detail at how the delete variant holds together, ideally I'd probably like to use a key/value pair to track the variant options using the dom input element id as the key (which is in the MatChipInputEvent), instead of relying on the outer loop index.

Some code from the stackblitz:

export class ChipsOverviewExample {
  productGroup: FormGroup;
  variantsArray: FormArray;
  typesOptionsArray: string[][] = [];
  readonly separatorKeysCodes: number[] = [ENTER, COMMA];

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.productGroup = this.fb.group({
      name: '',
      variants: this.fb.array([
        this.fb.group({
          type: '',
          options: ''
        })
      ]),
    });
    this.typesOptionsArray.push([]);
  }

  saveProduct(form: FormGroup) {
    console.log(form);
  }

  // Add new item to FormArray
  addItem(): void {
    this.variantsArray = this.productGroup.get('variants') as FormArray;
    this.variantsArray.push(this.fb.group({
      type: '',
      options: ''
    }));

    this.typesOptionsArray.push([]);
  }

  removeItem(index: number) {
    this.variantsArray.removeAt(index);
  }

  addOpt(event: MatChipInputEvent, index: number): void {
    const input = event.input;
    const value = event.value;
    // Add our fruit
    if ((value || '').trim()) {
      this.typesOptionsArray[index].push(value.trim());

    }
    // Reset the input value
    if (input) {
      input.value = '';
    }
  }

  removeOpt(opt: string, index: number): void {
    const optIndex = this.typesOptionsArray[index].indexOf(opt);
    if (optIndex >= 0) {
      this.typesOptionsArray[index].splice(optIndex, 1);
    }
  }
}

这篇关于Angular Material MatChipList - 如何在动态 FormArray 上使用它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆