最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular Material MatChipList - how to use it on a Dynamic FormArray? - Stack Overflow

programmeradmin2浏览0评论

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

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

Share Improve this question edited Nov 3, 2018 at 2:15 James asked Nov 1, 2018 at 21:49 JamesJames 1,2294 gold badges18 silver badges33 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

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 ponent 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./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);
    }
  }
}

try to make the formGroup as a new ponent and input formGroup to it(not formGroupName).

<div formArrayName="variants" *ngFor="let item of productGroup.controls['variants'].controls; let i = index;">
  <variant [varientGroup]="item"><varient>
  <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>

varient ponent.html

<div [formGroup]="varientGroup">
 <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"
              [matChipInputFor]="chipList"
              [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
              [matChipInputAddOnBlur]="true"
              (matChipInputTokenEnd)="addOpt($event)">
      </mat-chip-list>
    </mat-form-field>
  </div>
</div>

in varient.ponent.ts

@Input()varientGroup: FormGroup
发布评论

评论列表(0)

  1. 暂无评论