代码之家  ›  专栏  ›  技术社区  ›  BBacon

基于数据源对象数组属性大小的角度材质表行跨列

  •  6
  • BBacon  · 技术社区  · 7 年前

    这是多远(短?)我有:

    https://stackblitz.com/edit/angular-wudscb

    上面Stackblitz中的例子“几乎”是我想要的,但是我不知道如何完成它。

    ...
    ===============================================
    ||     ||            ||            ||  row1  ||
    ||  1  ||  Hydrogen  ||   1.0079   ||========||
    ||     ||            ||            ||  row2  ||
    ===============================================
    ||     ||            ||            ||  row1  ||
    ||     ||            ||            ||========||
    ||  2  ||   Helium   ||   4.0026   ||  row2  ||
    ||     ||            ||            ||========||
    ||     ||            ||            ||  row3  ||
    ===============================================
    ||     ||            ||            ||  row1  ||
    ||  3  ||  Lithium   ||   6.941    ||========||
    ||     ||            ||            ||  row2  ||
    ===============================================
    ...
    

    以下是使用其他元数据格式的示例:

    https://stackblitz.com/edit/angular-lnahlh

    在我的Stackblitz(第一个链接)之后,我的问题是:

    我是不是太远了?

    如何根据行的长度['descriptions']大小循环行?

    我想为社区找到一个通用的解决方案。

    2 回复  |  直到 7 年前
        1
  •  18
  •   Just code    7 年前

    第一步:

        const originalData = [
          { id: 1, name: 'Hydrogen', weight: 1.0079, descriptions: ['row1', 'row2'] },
          { id: 2, name: 'Helium', weight: 4.0026, descriptions: ['row1', 'row2', 'row3'] },
          { id: 3, name: 'Lithium', weight: 6.941, descriptions: ['row1', 'row2'] },
          { id: 4, name: 'Beryllium', weight: 9.0122, descriptions: ['row1', 'row2', 'row3'] },
          { id: 5, name: 'Boron', weight: 10.811, descriptions: ['row1'] },
          { id: 6, name: 'Carbon', weight: 12.0107, descriptions: ['row1', 'row2', 'row3'] },
          { id: 7, name: 'Nitrogen', weight: 14.0067, descriptions: ['row1'] },
          { id: 8, name: 'Oxygen', weight: 15.9994, descriptions: ['row1'] },
          { id: 9, name: 'Fluorine', weight: 18.9984, descriptions: ['row1', 'row2', 'row3'] },
          { id: 10, name: 'Neon', weight: 20.1797, descriptions: ['row1', 'row2', 'row3'] },
        ]; //original data
    
        const DATA = originalData.reduce((current, next) => {
          next.descriptions.forEach(b => {
            current.push({ id: next.id, name: next.name, weight: next.weight, descriptions: b })
          });
          return current;
        }, []);//iterating over each one and adding as the description 
        console.log(DATA)
    
        const ELEMENT_DATA: PeriodicElement[] = DATA; //adding data to the element data
    

    第2步

    这将是因为它是你的第二个stackblitz链接。

     getRowSpan(col, index) {    
        return this.spans[index] && this.spans[index][col];
      }
    

      constructor() {
        this.cacheSpan('Priority', d => d.id);
        this.cacheSpan('Name', d => d.name);
        this.cacheSpan('Weight', d => d.weight);
      }
    
      /**
       * Evaluated and store an evaluation of the rowspan for each row.
       * The key determines the column it affects, and the accessor determines the
       * value that should be checked for spanning.
       */
      cacheSpan(key, accessor) {
        for (let i = 0; i < DATA.length;) {
          let currentValue = accessor(DATA[i]);
          let count = 1;
    
          // Iterate through the remaining rows to see how many match
          // the current value as retrieved through the accessor.
          for (let j = i + 1; j < DATA.length; j++) {
            if (currentValue != accessor(DATA[j])) {
              break;
            }
    
            count++;
          }
    
          if (!this.spans[i]) {
            this.spans[i] = {};
          }
    
          // Store the number of similar values that were found (the span)
          // and skip i to the next unique row.
          this.spans[i][key] = count;
          i += count;
        }
      }
    

    使用索引向下传递到rowspan并隐藏不需要的行

        <ng-container matColumnDef="id">
            <th mat-header-cell *matHeaderCellDef> Priority </th>
            <td mat-cell *matCellDef="let data;let i = dataIndex" [attr.rowspan]="getRowSpan('Priority',i)" [style.display]="getRowSpan('Priority', i) ? '' : 'none'">
             {{ data.id }} </td>
        </ng-container>
    
        <ng-container matColumnDef="name">
            <th mat-header-cell *matHeaderCellDef> Name </th>
            <td mat-cell *matCellDef="let data;let i = dataIndex" [attr.rowspan]="getRowSpan('Name',i)" [style.display]="getRowSpan('Name', i) ? '' : 'none'">
             {{ data.name }} </td>
        </ng-container>
    
        <ng-container matColumnDef="weight">
            <th mat-header-cell *matHeaderCellDef> Weight </th>
            <td mat-cell *matCellDef="let data;let i = dataIndex" [attr.rowspan]="getRowSpan('Weight',i)" [style.display]="getRowSpan('Weight', i) ? '' : 'none'">
             {{ data.weight }} </td>
        </ng-container>
    
        <ng-container matColumnDef="descriptions">
            <th mat-header-cell *matHeaderCellDef> Descriptions </th>
            <td mat-cell *matCellDef="let data"> {{ data.descriptions }} </td>
        </ng-container>
    
        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> 
    
    
    </table>
    

    Here is the demo

        2
  •  4
  •   BBacon    7 年前

    因为我对给出的答案不满意(尤其是 cacheSpan 实施)。

    我想出了更方便的方法,比如:

    export class TableBasicExample {
      displayedColumns = ['priority', 'status', 'dateCreated', 'testNumber', 'testCurrency', 'testTime'];
      dataSource = DATA;
    
      spans = {};
    
      constructor() {
        this.spans = Object.assign({}, {
          priority: this.spanDeep(['priority'], DATA),
          status: this.spanDeep(['priority', 'status'], DATA),
          dateCreated: this.spanDeep(['priority', 'status', 'dateCreated'], DATA)
        });
      }
    
      spanDeep(paths: string[] | null, data: any[]) {
        if (!paths.length) {
          return [...data]
            .fill(0)
            .fill(data.length, 0, 1);
        }
    
        const copyPaths = [...paths];
        const path = copyPaths.shift();
    
        const uniq = uniqWith(data, (a, b) => get(a, path) === get(b, path))
          .map(item => get(item, path));
    
        return uniq
          .map(uniqItem => this.spanDeep(copyPaths, data.filter(item => uniqItem === get(item, path))))
          .flat(paths.length);
      }
    
      getRowSpan(path, idx) {
        return this.spans[path][idx];
      }
    };
    

    工作示例如下: https://stackblitz.com/edit/angular-lnahlh-hw2d3b

        3
  •  1
  •   Nick Wang    7 年前

    我们必须说有多少行,但有些行是相同的 id 但是对于您的数据,可以说其中有一些行,并且描述是数组和可拆分的。这样的话JS就不知道有多少了 <tr> 应该在那里。

    2种方式: [{id, name, weight, countdescriptions, description},...] [attr.rowspan]='data.countdescriptions' 相反 [attr.rowspan]='getRowSpan(data.id)' 2-更新内容格式,如 <ul><li *ngFor... 在描述中 <td> [attr.rowspan] 属性。

        4
  •  -1
  •   Bruno Oliveira    6 年前

    有一些诀窍可以使这项工作。其他答案已经知道了,但我会尝试另一种方法。

    elements = [
        { id: 1, name: 'Hydrogen', weight: 1.0079, descriptions: ['row1', 'row2'] },
        { id: 2, name: 'Helium', weight: 4.0026, descriptions: ['row1', 'row2', 'row3'] },
        { id: 3, name: 'Lithium', weight: 6.941, descriptions: ['row1', 'row2'] }
    ]
    

    如果我们只展示其中一个元素,我们应该写:

    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
          <th>Weight</th>
          <th>Descriptions</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td rowspan="2">1</td>
          <td rowspan="2">Hidrogen</td>
          <td rowspan="2">1.0079</td>
          <td>row1</td>
        </tr>
        <tr>
          <td>row2</td>
        </tr>
      </tbody>
    </table
    

    enter image description here


    现在,如果我们想迭代数据,有些事情我们必须改变。

    技巧1

    如果我们使用 *ngFor 内部 tr 泰格,桌子会撞坏的。相反,我们只需要在 ng-container 标签。

    rowspan [attr.rowspan]

    技巧3

    *ngFor公司 )但只要显示它,如果指数高于0。

    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
          <th>Weight</th>
          <th>Descriptions</th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngFor="let e of elements">
          <tr>
            <td [attr.rowspan]="e.descriptions.length + 1">{{e.id}}</td>
            <td [attr.rowspan]="e.descriptions.length + 1">{{e.name}}</td>
            <td [attr.rowspan]="e.descriptions.length + 1">{{e.weight}}</td>
            <td>{{e.descriptions[0]}}</td>
          </tr>
          <tr *ngFor="let d of e.descriptions; let index = index">
            <td *ngIf="index>0">{{d}}</td>
          </tr>
        </ng-container>
      </tbody>
    </table>
    

    最后,我们有:

    enter image description here