角度材质表中的嵌套列和行内容投影

问题描述 投票:0回答:1

我正在尝试创建一个可重用的角度材质表,其中包含投影的列和行定义。 Angular 在其文档示例here中提到了这一点。单层内容投影工作得很好,但是(IMO)给“消费者”组件留下了大量重复性工作,所以我想为表格创建一个“包装器”组件来处理排序、分页、过滤和其他自定义功能。但我仍然希望能够从 Consumer 组件投影列和行定义,并且我似乎无法使嵌套内容投影工作,因为 Table 组件在其 @ContentChildren() 中找不到任何内容。这是代码,希望它会更有意义:)

表格组件

@Component({
  selector: 'app-table',
  template: `
    <table mat-table [dataSource]="dataSource">
      <ng-content />
    </table>
  `,
  standalone: true,
})
export class TableComponent<T> implements AfterContentInit {
  @ViewChild(MatTable, { static: true }) table: MatTable<T>;

  @ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>;
  @ContentChildren(MatHeaderRowDef) headerRowDefs: QueryList<MatHeaderRowDef>;
  @ContentChildren(MatRowDef) rowDefs: QueryList<MatRowDef<T>>;

  @Input() dataSource: MatTableDataSource<T>;

  ngAfterContentInit() {
    this.columnDefs.forEach((columnDef) => this.table.addColumnDef(columnDef));
    this.rowDefs.forEach((rowDef) => this.table.addRowDef(rowDef));
    this.headerRowDefs.forEach((headerRowDef) =>
      this.table.addHeaderRowDef(headerRowDef)
    );

    // query lists are empty with nested projection
    console.log(this.columnDefs, this.rowDefs, this.headerRowDefs);
  }
}

TableWrapper组件

@Component({
  selector: 'app-table-wrapper',
  template: `
    <app-table [dataSource]="dataSource">
      <ng-content />
    </app-table>
  `,
  standalone: true,
})
export class TableWrapperComponent<T> {
  @Input() dataSource: MatTableDataSource<T>;
}

消费者组件

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

@Component({
  selector: 'app-consumer',
  template: `
    <app-table-wrapper [dataSource]="dataSource">
      <ng-container matColumnDef="position">
        <th mat-header-cell *matHeaderCellDef> Position </th>
        <td mat-cell *matCellDef="let element"> {{ element.position }} </td>
      </ng-container>

      <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef> Name </th>
        <td mat-cell *matCellDef="let element"> {{ element.name }} </td>
      </ng-container>

      <ng-container matColumnDef="weight">
        <th mat-header-cell *matHeaderCellDef> Weight </th>
        <td mat-cell *matCellDef="let element"> {{ element.weight }} </td>
      </ng-container>

      <ng-container matColumnDef="symbol">
        <th mat-header-cell *matHeaderCellDef> Symbol </th>
        <td mat-cell *matCellDef="let element"> {{ element.symbol }} </td>
      </ng-container>

      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
    </app-table-wrapper>
  `,
  standalone: true,
})
export class ConsumerComponent<T> {
  dataSource: MatTableDataSource<PeriodicElement> = new MatTableDataSource([
    { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
    { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
    { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
    { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
    { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
    { position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' },
    { position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' },
    { position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' },
    { position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' },
    { position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' },
  ]);

  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
}

所以..我希望实现的是简单的嵌套内容投影,但正如我所说,表组件将这些查询列表为空。如果不是嵌套投影,同一段代码可以完美运行。拥有这个中间层 - 包装器组件将极大地受益于清理可重复的功能,同时保持表组件的干净和简单。有什么想法可以让这种事情与表格一起使用吗?

附注很抱歉没有 stackblitz 示例,它陷入了“Booting WebContainer”问题。 另外,抱歉,如果我在提问时搞砸了任何约定,这是我的第一篇文章,我不确定是否将其发布在这里或在 Angular github 问题页面上:/

angular angular-material angular-material-table angular-content-projection
1个回答
0
投票

使用投影列和行定义为 Angular Material Table 创建包装器组件的方法是正确的。但是,当使用嵌套内容投影时,您需要确保投影内容可以在包装器组件中正确访问。

在您的

TableWrapperComponent
中,您将内容投影到
app-table
中,但您还需要确保投影内容(即列和行定义)可在
TableComponent
内的
TableWrapperComponent
内访问。

以下是如何修改代码以实现嵌套内容投影:

  1. 更新
    TableWrapperComponent
    以将投影内容传递到
    TableComponent
@Component({
  selector: 'app-table-wrapper',
  template: `
    <app-table [dataSource]="dataSource">
      <ng-content></ng-content>
    </app-table>
  `,
  standalone: true,
})
export class TableWrapperComponent<T> {
  @Input() dataSource: MatTableDataSource<T>;
}
  1. 更新
    TableComponent
    以正确处理嵌套内容投影:
@Component({
  selector: 'app-table',
  template: `
    <table mat-table [dataSource]="dataSource">
      <ng-container *ngFor="let columnDef of columnDefs">
        <ng-container [matColumnDef]="columnDef.name">
          <th mat-header-cell *matHeaderCellDef>{{ columnDef.name }}</th>
          <td mat-cell *matCellDef="let element">{{ element[columnDef.name] }}</td>
        </ng-container>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
    </table>
  `,
  standalone: true,
})
export class TableComponent<T> implements AfterContentInit {
  @ViewChild(MatTable, { static: true }) table: MatTable<T>;

  @ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>;
  @ContentChildren(MatHeaderRowDef) headerRowDefs: QueryList<MatHeaderRowDef>;
  @ContentChildren(MatRowDef) rowDefs: QueryList<MatRowDef<T>>;

  @Input() dataSource: MatTableDataSource<T>;

  ngAfterContentInit() {
    this.columnDefs.forEach((columnDef) => this.table.addColumnDef(columnDef));
    this.rowDefs.forEach((rowDef) => this.table.addRowDef(rowDef));
    this.headerRowDefs.forEach((headerRowDef) =>
      this.table.addHeaderRowDef(headerRowDef)
    );

    // Ensure that the projected content is accessible
    console.log(this.columnDefs, this.rowDefs, this.headerRowDefs);
  }

  // Extract displayed column names
  get displayedColumns(): string[] {
    return this.columnDefs.map((columnDef) => columnDef.name);
  }
}

通过这些更改,

TableComponent
应正确处理来自
TableWrapperComponent
的嵌套内容投影,允许您在
ConsumerComponent
内定义列和行,并让表格正确呈现它们。确保根据您的具体要求调整任何其他逻辑。

如果您遇到任何问题或有其他疑问,请随时询问!

© www.soinside.com 2019 - 2024. All rights reserved.