庚子说 發表於 2019-12-13 17:53:00

Angular 动态表单(根据选择联动显示)

<h1 id="angular-动态表单根据选择联动显示">Angular 动态表单(根据选择联动显示)</h1>
<h3 id="首先">首先</h3>
<p>记录一下刚刚完成的一个功能</p>
<p>需求是根据固定的层级结构做动态联动,在网上找了很多动态表单的相关教程,大部分都是在最开始加载就生成表单.而我的需求是需要在选择了父级之后再展示父级下的选项</p>
<blockquote>
<p>参考了大佬的修仙之路 和 动态生成表单感谢~</p>
</blockquote>
<h3 id="实现">实现</h3>
<ol>
<li>
<h5 id="准备阶段">准备阶段</h5>
<p>配置好已知的层级结构</p>
<pre><code class="language-json">const itemConfig = [{
      'key': 'tr069',
      'type': 'parent',// parent =&gt;含有子级item=&gt;最底层级
      'item_type': 'select',// 本层级的类型 parent 默认为select
      'children': [
            {
                'key': 'url',
                'type': 'item',
                'item_type': 'input',
                'value': ''
            },
            {
                'key': 'username',
                'type': 'item',
                'item_type': 'input',
                'value': ''
            },
            {
                'key': 'password',
                'type': 'item',
                'item_type': 'input',
                'value': ''
            },
            {
                'key': 'data',
                'type': 'item',
                'item_type': 'object',
                'value': {
                  'key': '',
                  'value': ''
                }
            }
      ]
    },{
      'key': 'gateway',
      'type': 'parent',
      'item_type': 'select',
      'children': [
            {
                'key': 'gw',
                'type': 'item',
                'item_type': 'input',
                'value': ''
            }
      ]

    },{
      'key': 'optimy',
      'type': 'parent',
      'item_type': 'select',
      'children': [
            {
                'key': 'enable',
                'type': 'item',
                'item_type': 'select',
                'value':
            }
      ]

    },
];
</code></pre>
<p>页面上创建初始层级</p>
<p>在初始表单选项上绑定change事件</p>
<pre><code class="language-html">&lt;form autocomplete="off" ="itemForm" fxLayout="column"&gt;
    &lt;div fxLayout="row" fxLayoutAlign="center center"&gt;
      &lt;mat-label&gt;Group:&lt;/mat-label&gt;
      &lt;mat-form-field appearance="outline"&gt;
          &lt;mat-select formControlName="group"                           (selectionChange)="changeSelect($event.value,'group')"&gt;
            &lt;mat-option *ngFor="let item of itemConfig" ="item"&gt;
            {{item.key}}
            &lt;/mat-option&gt;
          &lt;/mat-select&gt;
            
      &lt;/mat-form-field&gt;
        &lt;/div&gt;
&lt;/form&gt;
</code></pre>
<p>页面配置表单的初始选项</p>
<pre><code class="language-js">itemForm: FormGroup;

// 根据父级的选择 展示的item列表
itemPushDom = [];

ngOnInit(): void {
    this.itemForm = this.createFrom();
}

createFrom(): any {
    const group = this._formBuilder.group({
      'group': this._formBuilder.control('')
    });
    return group;
}
</code></pre>
</li>
<li>
<h5 id="实现动态插入">实现动态插入</h5>
<p>通过之前的操作 现在我们的页面上已经能看到初始的选项了</p>
<p>接下来就是实现动态插入 , 其实简单来说就是分为两个步骤: Dom插入可选项 和 FormGroup添加项</p>
<p>再加上change父级之后清除之前的选择</p>
<h6 id="dom插入可选项">Dom插入可选项</h6>
<p>需要配合之前初始选项绑定的change事件 传递children的信息</p>
<p>html 上也需要配置好相关的可能出现的类型 通过ngSwtech 展示 (本例类型较少,只有select和input 如果类型较多可以参考官方文档的动态表单 通过component控制出现的类型)</p>
<h6 id="formgroup添加项">FormGroup添加项</h6>
<p>通过 addControl()/removeControl() 对FormGroup 表单项 进行添加和删除(也可以添加验证)</p>
<p>下面直接上代码</p>
<p>component.html   (放在上一段form里)</p>
<pre><code class="language-html">&lt;div fxLayout="row" fxLayoutAlign="center center" *ngFor="let newItem of itemPushDom"&gt;
      &lt;mat-label &gt;{{newItem.name}}:&lt;/mat-label&gt;
      &lt;mat-form-field appearance="outline" ="newItem.type"&gt;

          &lt;mat-select *ngSwitchCase="'select'" formControlName="{{newItem.name}}"
            (selectionChange)="changeSelect($event.value,newItem.name)" required&gt;
            &lt;mat-option *ngFor="let options of newItem.options" ="options.value"&gt;
            {{options.key}}
            &lt;/mat-option&gt;
          &lt;/mat-select&gt;

          &lt;input matInput *ngSwitchCase="'input'" formControlName="{{newItem.name}}" ="newItem.value" required&gt;

      &lt;/mat-form-field&gt;

&lt;/div&gt;
</code></pre>
<p>component.ts</p>
<pre><code class="language-js">changeSelect(item: any, itemName: string): void {

    // changeSelect 后检查是否需要删除原选项关联的item
    // 如果change的是父级的选项 递归删除已选
    this.checkItemDom(itemName);

    this.createItemDom(item, itemName);

}

createItemDom(item: any, itemName: string): void {

    // 动态添加FromControl
    this.addFromControl(item.key);


    const options = [];

    // 判断选择的item是否还有子级 (select)
    if (item.type === 'parent') { // 默认parent都是select


      // 查找子项点展示
      item.children.forEach(eleParent =&gt; {
      options.push({
          key: eleParent.key,
          value: eleParent
      });
      });

      this.addFromDom(item.key, itemName, item.item_type, '', options, item.type);

    } else if (item.type === 'item') {

      if (item.item_type === 'select') {
      item.value.forEach(eleItem =&gt; {
          options.push({
            key: eleItem,
            value: eleItem
          });
      });

      this.addFromDom(item.key, itemName, item.item_type, item.value, options, item.type);

      } else {// 这里可以扩展多种类型

      this.addFromDom(item.key, itemName, item.item_type, item.value, options, item.type);

      }

    }
}

// add/remove itemPushDom
// 保存item的name/type/parent 在二维数组中保存子父级关联

addFromDom(name: string, key: string, type: string, value: string, options: any, item_type: string): void {

    this.itemPushDom.push({
      parent: key,
      name: name,
      type: type,
      item: item_type,
      value: value,
      options: options
    });
}

    checkItemDom(itemName: string): any {

    for (let i = 0; i &lt; this.itemPushDom.length; i++) {

      if (this.itemPushDom.parent === itemName) {

      // 根据子父级关系 父级改变 查找相对应的子级删除 Dom和FormGroup
      this.checkItemDom(this.itemPushDom.name);
      this.delFromControl(this.itemPushDom.name);
      this.itemPushDom.splice(i, 1);

      }
    }

}



addFromControl(name: string): void {

    this.itemForm.addControl(name, this._formBuilder.control(''));

}

delFromControl(name: string): void {

    this.itemForm.removeControl(name);

}
</code></pre>
</li>
</ol>
<p>最后只需要 通过this.itemForm.value 就可以获得所选的值</p>
<p>或者保存itemPushDom</p><br><br>
来源:https://www.cnblogs.com/nhxz001/p/12036553.html
頁: [1]
查看完整版本: Angular 动态表单(根据选择联动显示)