我正在尝试从https://material.angular.io/components/table/examples实现Table with expandable rows
,但出现此错误:
There can only be one default row without a when predicate function.
此错误来自以下事实:我有两个<tr mat-row ...
,两个都没有when谓词(根据示例)。如果我删除了一个,则错误消失了。
通过我自己的调查,我发现此功能是Material的新功能。我升级到@ angular / material @ latest和@ angular / cdk @ latest,仍然出现错误。
有人知道我必须做什么来实现表格吗,如文档中的示例所示? https://material.angular.io/components/table/examples
我的版本:
Angular CLI: 6.0.8
Node: 8.11.2
OS: win32 x64
Angular: 6.0.4
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.6.8
@angular-devkit/build-angular 0.6.8
@angular-devkit/build-optimizer 0.6.8
@angular-devkit/core 0.6.8
@angular-devkit/schematics 0.6.8
@angular/cdk 6.3.1
@angular/cli 6.0.8
@angular/flex-layout 6.0.0-beta.16
@angular/material 6.3.1
@ngtools/webpack 6.0.8
@schematics/angular 0.6.8
@schematics/update 0.6.8
rxjs 6.2.0
typescript 2.7.2
webpack 4.8.3
答案 0 :(得分:37)
事实证明,我在multiTemplateDataRows
标签中缺少指令<table>
:
<table mat-table [dataSource]="licenses" multiTemplateDataRows ...
答案 1 :(得分:8)
如果您的when
谓词中的函数未定义,也会出现此错误。所以如果你有
<mat-tree-node *matTreeNodeDef="let node; when: hasChild">
和hasChild
未定义,您会收到该错误。
答案 2 :(得分:3)
我有同样的问题。我将@ angular / cdk和@ angular / material更新为6.4.7。而且一切正常。当然,您也需要multiTemplateDataRows attr
答案 3 :(得分:0)
尝试这样:
wrapper-table.ts
import { SelectionModel } from '@angular/cdk/collections';
import { AfterContentInit, Component, ContentChildren, Input, QueryList, TemplateRef, ViewChild } from '@angular/core';
import { MatColumnDef, MatHeaderRowDef, MatRowDef, MatTable, MatTableDataSource } from '@angular/material/table';
@Component({
selector: 'ui-wrapper-table',
templateUrl: './wrapper-table.component.html',
styleUrls: ['./wrapper-table.component.scss']
})
export class WrapperTable<T> implements AfterContentInit {
@ContentChildren(MatHeaderRowDef) headerRowDefs: QueryList<MatHeaderRowDef>;
@ContentChildren(MatRowDef) rowDefs: QueryList<MatRowDef<T>>;
@ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>;
@ViewChild(MatTable, { static: true }) table: MatTable<T>;
@Input() columns: string[];
@Input() dataSource: MatTableDataSource<T>;
@Input() contextTemplate: TemplateRef<any>;
@Input() selection: SelectionModel<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));
}
isAllSelected() {
const numSelected = this.selection && this.selection.selected.length || 0;
const numRows = this.dataSource && this.dataSource.data.length || 0;
return numSelected === numRows;
}
masterToggle() {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.data.forEach(row => this.selection.select(row));
}
checkboxLabel(row?: T): string {
if (!row) {
return `${this.isAllSelected() ? 'select' : 'deselect'} all`;
}
return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row`;
}
}
wrapper-table.html
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-content></ng-content>
<!-- Select Column -->
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection?.hasValue() && isAllSelected()"
[indeterminate]="selection?.hasValue() && !isAllSelected()" [aria-label]="checkboxLabel()">
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(row) : null"
[checked]="selection?.isSelected(row)" [aria-label]="checkboxLabel(row)">
</mat-checkbox>
</td>
</ng-container>
<!-- Id Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> # </th>
<td mat-cell *matCellDef="let element"> {{element.id}} </td>
</ng-container>
<!-- Created Column -->
<ng-container matColumnDef="created">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Criação </th>
<td mat-cell *matCellDef="let element"> {{element.created.toDate() | date}} </td>
</ng-container>
<!-- Context Column -->
<ng-container matColumnDef="context">
<th mat-header-cell *matHeaderCellDef> Contexto </th>
<td mat-cell *matCellDef="let element">
<ng-container *ngTemplateOutlet="contextTemplate;context:{row:element}"></ng-container>
</td>
</ng-container>
</table>
companies.component.ts
import { SelectionModel } from '@angular/cdk/collections';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatSort, MatTableDataSource } from '@angular/material';
import { CompanyModel, GetAllCompaniesUsecase } from '@apps-waves/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'wave-companies',
templateUrl: './companies.component.html',
styleUrls: ['./companies.component.scss']
})
export class CompaniesComponent implements OnInit, OnDestroy {
displayedColumns: string[] = ['select', 'name', 'companyType', 'created', 'context'];
dataSource: MatTableDataSource<CompanyModel>;
selection: SelectionModel<CompanyModel>;
@ViewChild('sort', { static: false }) sort: MatSort;
onDestroy = new Subject<void>();
constructor(
private getAllCompanies: GetAllCompaniesUsecase
) { }
ngOnInit() {
this.getAllCompanies.execute()
.pipe(takeUntil(this.onDestroy))
.subscribe(companies => {
this.dataSource = new MatTableDataSource(companies);
this.selection = new SelectionModel<CompanyModel>(true, []);
this.dataSource.sort = this.sort;
})
}
onClick(company: CompanyModel) {
console.log(company);
}
ngOnDestroy() {
this.onDestroy.next();
this.onDestroy.complete();
}
}
companies.html
<ui-wrapper-table
[dataSource]="dataSource"
[columns]="displayedColumns"
[selection]="selection"
matSort #sort="matSort"
[contextTemplate]="rowContext">
<!-- Custom column definition to be provided to the wrapper table. -->
<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="companyType">
<th mat-header-cell *matHeaderCellDef> Segmento </th>
<td mat-cell *matCellDef="let element"> {{element.companyType}} </td>
</ng-container>
<!-- Custom row definitions to be provided to the wrapper table. -->
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns; "></tr>
</ui-wrapper-table>
<ng-template #rowContext let-element="row">
<button type="button" mat-icon-button (click)="onClick(element)">
<mat-icon>edit</mat-icon>
</button>
</ng-template>
<pre>{{selection?.selected | json}}</pre>
它的工作非常酷
答案 4 :(得分:0)
您的模板
OptimizeResult
,并且您的组件应具有名为mat-tree-node(*matTreeNodeDef="let node;when: hasChild", matTreeNodePadding)
hasChild