Как реализовать зависимую <select>внутри HTML таблицу - PullRequest
4 голосов
/ 20 июня 2020

Я реализовал таблицу, подобную приведенной ниже. Доступны для редактирования два столбца, в которых мы можем выбирать значения из раскрывающегося списка. Я реализовал это, используя HTML select. Значения в «Уровне категории 2» зависят от значения, которое я выбираю в столбце «Уровень категории 1».

Когда я выбираю значение в столбце «Уровень категории 1» определенной строки, все значения строки в столбце «Категория уровня 2» меняются, но я хотел бы изменить значение «Категория уровня 2» только для этой конкретной строки.

table

stackblitz link .

Ответы [ 2 ]

4 голосов
/ 20 июня 2020

Вы можете создать каждую строку в таблице как компонент, скажем my-row.component, и использовать его как атрибут в tr. после этих изменений

app.component. html

<div>
  <table style="width:100%">
        <th *ngFor = "let column of headers">
            {{column}}
        </th>
        <th>
            Category tier 1
        </th>
        <th>
            Category tier 2
        </th>
        <ng-container *ngFor = "let row of rows">
        <tr [headers]="headers" [row]="row" [categories]="categories" [category_tier1]="category_tier1" app-my-row></tr>   
        </ng-container>
    </table>
</div>

app.component.ts

import { Component, VERSION } from '@angular/core';
interface Category{
    category_id: number;
    tier1: string;
    tier2: string;
}
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  categories:Category[]=[
    {
    "category_id": 2,
    "tier1": "ABC",
    "tier2": "A"
    },
    {
    "category_id": 3,
    "tier1": "ABC",
    "tier2": "B"
    },
    {
    "category_id": 4,
    "tier1": "ABC",
    "tier2": "C"
    },
    {
    "category_id": 5,
    "tier1": "DE",
    "tier2": "D"
    },
    {
    "category_id": 6,
    "tier1": "DE",
    "tier2": "E"
    },
    {
    "category_id": 7,
    "tier1": "FG",
    "tier2": "F"
    },
    {
    "category_id": 8,
    "tier1": "FG",
    "tier2": "G"
    }
    ];
      category_tier1:string[]=[];
      category_tier2:string[]=[];

      headers=["Firstname","Lastname","Age"];

      rows=[
        {
          "Firstname":"Jill",
          "Lastname":"Smith",
          "Age":"50"
        },
        {
          "Firstname":"Eve",
          "Lastname":"Jackson",
          "Age":"94"
        },
        {
          "Firstname":"John",
          "Lastname":"Doe",
          "Age":"80"
        }
  ];

  constructor(){
    for(let i in this.categories){
                this.category_tier1.push(this.categories[i].tier1);
              }
              this.category_tier1=Array.from(new Set(this.category_tier1));
  }

}

app.component. css

table, th {
    border: 1px solid black;
    border-collapse: collapse;
    table-layout: fixed; width: 100%
  }
  th {
    padding: 15px;
    overflow: hidden;
  }

my-row.component. html

<td *ngFor="let column of headers">
    {{row[column]}}
</td>
<td>
    <select (change)="selectTier1($event)">
                  <option *ngFor="let c of category_tier1" [value]="c">{{c}}</option>
                </select>
</td>
<td>
    <select (change)="selectTier2($event)">
                <option *ngFor="let c of category_tier2" [value]="c">{{c}}</option>
              </select>
</td>

my-row.component. ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: '[app-my-row]',
  templateUrl: './my-row.component.html',
  styleUrls: ['./my-row.component.css']
})
export class MyRowComponent implements OnInit {
  @Input() public headers;
  @Input() public row;
  @Input() public categories;
  @Input() public category_tier1;
  public category_tier2;
  constructor() { }

  ngOnInit() {
  }
  selectTier1(event){
    this.category_tier2=[];
    for(let c in this.categories){
      if(this.categories[c].tier1===event.target.value){
        this.category_tier2.push(this.categories[c].tier2);
      }
    }
  }
  selectTier2(event){

  }
}

my-row.component. css

 td {
    padding: 5px;
    overflow: hidden;
  }

select {
    border: 0;
    height: 60%;
    width: 100%;
}

td {
    border: 1px solid black;
    border-collapse: collapse;
    table-layout: fixed; width: 100%
  }

При использовании вышеуказанного подхода каждая строка получит свой отдельный массив уровня 2 .

Рабочий стекблитц: - https://stackblitz.com/edit/angular-ivy-dcjc1y

1 голос
/ 20 июня 2020

Измените 3 места в вашем коде:

  • Определите категории 2 уровня как массив массива вместо строки:

      categories_tier2:string[][] = []; // replace category_tier2:string[] = []
    
  • In HTML, измените код для рендеринга выбора уровня 2 и передайте индекс строки в обработчик события выбора уровня 1:

    <tr *ngFor = "let row of rows; index as i">  // Use row index here
        <td  *ngFor = "let column of headers">
          {{row[column]}}
        </td>
        <td>
            <select (change)="selectTier1($event,i)"> // Pass row index to handler
              <option *ngFor="let c of category_tier1" [value]="c">{{c}}</option>
            </select>
        </td>
        <td>
          <select (change)="selectTier2($event)">  // Adjust to changed array
            <option *ngFor="let c of categories_tier2[i]" [value]="c">{{c}}</option>
          </select>
        </td>
      </tr> 
    

Затем в обработчике выбора уровня 1 используйте индекс строки для визуализации правильный список tier2:

    selectTier1(event, i){
        this.categories_tier2[i]=[];
        for (let c of this.categories){
           if (c.tier1===event.target.value) {
             this.categories_tier2[i].push(c.tier2);
           }
        }
     }
...