繁体   English   中英

如何在 Angular 8 中创建动态下拉菜单

[英]How to create dynamic dropdowns in Angular 8

在我的 UI 中,每一行都有 level1、level2 和 level3 下拉菜单以及“添加级别”按钮。

我想单击“添加级别”按钮,它将在同一行中添加一组新的三个下拉菜单 level1、level2 和 level3。 就像用户单击“添加级别”按钮一样,每次它都会在同一行中动态添加新的下拉列表。

其他行下拉菜单不会对此产生影响。

任何人都可以帮助修改我的旧代码以作为我的预期输出。

StackBlitz 代码 URL

请参阅所附图片,了解我对 level1 level2 和 level3 下拉菜单的预期输出

在此处输入图像描述

它总是一样的。 要使用 ReactiveForms 控制任何对象,您可以为 Object 创建一个 FormGroup,为数组创建一个 FormArray。 如果 Array 是一个对象,则创建 FormGroup 的 FormArray,否则创建 FormGroup 的 FormArray

首先是决定数据的结构,因为“级别”是一个数组,您的数据可以是,例如

{
  "plannedProduction": 210468,
  "factORLossTree": [
    {
      "skuid": "000000000034087070",
      "skuDescription": "SUNLIGHT DESTINY HW PWD YELLOW 8X900G",
      "productionOrderNo": "X49033251",
      "category": "Fabric Cleaning",
      "levels": [
        {
          "level1": "",
          "level2": "",
          "level3": ""
        }
        ....
      ]
    },
    {
      "skuid": "000000000067141695",
      "skuDescription": "SUNLIGHT DESTINY YELLOW 24X170G",
      "productionOrderNo": "X49039793",
      "category": "Fabric Cleaning",
      "levels": [
        {
          "level1": "",
          "level2": "",
          "level3": ""
        }
        ....
      ]
    },
    ....
   ]
}

与往常一样,你有一个 FormArray,你使用你的代码中仍然有的 getter (*)

  get lossFormArray() {
    return this.orLosstreeForm.get('factORLossTree') as FormArray;
  }

因为我们在 FormArray 中有一个 FormArray 来获取内部 FormArray,所以我们需要另一个“getter”。 好吧,不能成为 getter,因为我们需要将 formArray 的“索引”作为参数传递

  getLevels(index:number)
  {
    return this.lossFormArray.at(index).get('levels') as FormArray;
  }

我们还可以使用一个辅助函数,该函数返回 index 处的 formArray 的值以简化 .html

  getItemValue(index:number)
  {
    return this.lossFormArray.at(index).value;
  }

最后我们添加一个函数来创建 formGroup “级别”

createLevel() {
    return this.fb.group({
      level1: [''],
      level2: [''],
      level3: [''],
    });

我们现在要创建 formGroup 改变一下你的函数 setData

  setData() {
    const resp = {...}
    if (resp.factORLossTree.length > 0) {
      this.orLosstreeForm.patchValue({
        plannedProduction: resp.plannedVolume,
      });
      this.lossFormArray.clear();
      for (const item of resp.factORLossTree) {
        const data = {
          skuid: item.skuid,
          skuDescription: item.skuDescription,
          productionOrderNo: item.productionOrderNo,
          category: item.category,
         
          //see how transform the data to creaate the array "levels"
          levels: [
            {
              level1: item.level1,
              level2: item.level2,
              level3: item.level3,
            },
          ],
        };
        this.addItem(this.createLevelItem(data));
      }
    }
  }

还有你的函数 cteateLevelItem:

createLevelItem(data) {
    const formgrp = this.fb.group({
      skuid: ['', Validators.required],
      ...

      //see how levels is a formArray, at first with an unique element
      //we use the before function createLevel()
      levels: this.fb.array([this.createLevel()]),
    });
    if (data !== null) {
      formgrp.patchValue(data);
    }
    return formgrp;
  }

一个复杂的部分知道是.html,但我想展示如何创建一系列互斥的下拉列表。 就像这样SO ,但在这种情况下,我们将有一个数组数组。 别担心,让它变慢并不像看起来那么难

首先,我们有一个可能的级别并声明一个空数组

  allLevels = ['Level 1', 'Level 2', 'Level 3', 'Level 4', 'Level 5'];

  levelList: any[] = [];

然后我们将填充数组 levelList。 合适的地方是函数“createLevel”。 在这个函数中,我们订阅了组的 valueChanges。 但是我们需要知道级别的索引。 所以函数变得像

  createLevel(index: number) {

    //we are going to create some like
    //levelList[i][j][0], levelList[i][j][1], levelList[i][j][2]

    const j = this.orLosstreeForm && 
              this.lossFormArray && 
              this.lossFormArray.at(index)?
                   this.getLevels(index).controls.length:0;
    const group = this.fb.group({
      level1: [''],
      level2: [''],
      level3: [''],
    });
    group.valueChanges
      .pipe(startWith(null), takeUntil(this.active))
      .subscribe((res: any) => {
          res = res || { level1: null, level2: null };
          if (!this.levelList[index]) this.levelList[index] = [];

          this.levelList[index][j] = [];

          this.levelList[index][j][0] = this.allLevels;
          this.levelList[index][j][1] = this.allLevels.filter(
            (x) => x != res.level1
          );
          this.levelList[index][j][2] = this.allLevels.filter(
            (x) => x != res.level1 && x != res.level2
          );

          //And we check if there any repeat

          if (this.levelList[index][j][1].indexOf(res.level2) < 0)
            group.get('level2').setValue(null, { emitEvent: false });

          if (this.levelList[index][j][2].indexOf(res.level3) < 0)
            group.get('level3').setValue(null, { emitEvent: false });
      });
    return group;
  }

噗,我知道太大了,但请耐心等待,最后一部分是.html

<div style="background-color: white;">
  <form [formGroup]="orLosstreeForm" *ngIf="orLosstreeForm">
    ...
    <!-- Start of OR loss tree table -->
    <div class="selection-area" formArrayName="factORLossTree">
      <div
        *ngFor="let levelItem of lossFormArray.controls;let i=index" [formGroupName]="i"
      >
        <ng-container>
           ...here we can use getItemValue(i).skuDescription
              or getItemValue(i).skuid or ...

                  <div class="deviations" formArrayName="levels">

                      <div class="row" *ngFor="let group of getLevels(i).controls;
        let j=index" [formGroupName]="j">
                        <div class="col-md-3">
                          <mat-form-field>
                            <mat-label>Level 1</mat-label>
                            <mat-select
                              name="level1"
                              formControlName="level1"
                            >
                              <mat-option value="">--Select--</mat-option>
                                <mat-option
                                  *ngFor="let item of levelList[i][j][0]"
                                  [value]="item"
                                >
                                  {{ item }}
                                </mat-option>
                            </mat-select>
                          </mat-form-field>
                        </div>
                        <div class="col-md-3">
                          <mat-form-field>
                            <mat-label>Level 2</mat-label>
                            <mat-select
                              name="level2"
                              formControlName="level2"
                            >
                              <mat-option value="">--Select--</mat-option>
                                <mat-option
                                  *ngFor="let item of levelList[i][j][1]"
                                  [value]="item"
                                >
                                  {{ item }}
                                </mat-option>

                            </mat-select>
                          </mat-form-field>
                        </div>
                        <div class="col-md-3">
                          <mat-form-field>
                            <mat-label>Level 3</mat-label>
                            <mat-select name="level3"
                              formControlName="level3"
                            >
                              <mat-option value="">--Select--</mat-option>

                               <mat-option
                                  *ngFor="let item of levelList[i][j][2]"
                                  [value]="item"
                                >
                                  {{ item }}
                                </mat-option>
                            </mat-select>
                          </mat-form-field>
                        </div>

                        <div class="col-md-3">
                          <button
                            class="resetButton"
                            aria-describedby="Reset SKU"
                            (click)="getLevels(i).push(createLevel(i))"
                          >
                            Add Level
                          </button>
                        </div>
                    </div>
            ....
    </div>
  </form>
</div>

看看如何添加一组新的关卡,我们只需要

<button (click)="getLevels(i).push(createLevel(i))">
    Add Level
</button>

最后的堆栈闪电战

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM