Expand/Collapse table 行 - Angular 11 Material
Expand/Collapse table rows - Angular 11 Material
所以我正在尝试构建一个 Material data-table,在 Angular 中进行分页、排序和过滤,以显示存储在 Azure 存储帐户中的文件。您可以下载您在左侧的复选框中选择的文件。
我目前坚持的是下一步,即打开扩展并在您相应地单击其行时显示文件的描述。
我尝试遵循 this 教程和其他多个教程,但目前面临以下问题:
有效的是当我点击一行时会显示额外的数据,但是我希望它显示在该行的下方,而不是在同一行的旁边,并去掉右侧的空白table.
如能提供有关如何执行此操作的任何帮助,我们将不胜感激,谢谢!
我不知道这是否只是一个样式问题或其他问题,但我已经尝试解决这个问题很长时间了,并且确定我在某处遗漏了一些东西 and/or 做错了什么。
html
<table mat-table [dataSource]="dataSource" class="full-width-table" matSort multiTemplateDataRows>
<ng-container matColumnDef="select">
<th class="select-column" mat-header-cell *matHeaderCellDef>
<mat-checkbox color="primary" (change)="$event ? selectAllToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
<mat-icon class="download-button" title="Click here to download the selected files" (click)="downloadSelected()" *ngIf="selection.hasValue()">save_alt</mat-icon>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="createdOn">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created On </th>
<td mat-cell *matCellDef="let element"> {{element.createdOn | date:'shortDate'}} </td>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
<div class="element-detail" [@detailExpand]="element.isExpanded ? 'expanded' : 'collapsed'">
{{element.fileInfo}}
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let element; columns: displayedColumns;" class="element-row"
[class.expanded-row]="element.isExpanded" (click)="toggleRow(element)">
</tr>
<tr *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
</table>
ts
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { ApiService } from '../api.services';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { MatSort } from '@angular/material/sort';
import { IBlobData } from '../blob-data';
import { Subscription } from 'rxjs';
import { MatTableDataSource } from '@angular/material/table';
import { HttpErrorResponse } from '@angular/common/http';
import { SelectionModel } from '@angular/cdk/collections';
import { MatPaginator } from '@angular/material/paginator';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
animations: [
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class HomeComponent implements OnInit {
blobs: any;
filterBlobs: any[] = [];
filterTerm: string = '';
private subs = new Subscription();
displayedColumns: any[] = [ 'select', 'name', 'createdOn'];
selection = new SelectionModel<IBlobData>(true, []);
public dataSource!: MatTableDataSource<IBlobData>;
constructor(private api: ApiService) { }
// configure sorting and paginator
@ViewChild(MatSort, { static: false }) sort!: MatSort;
@ViewChild('paginator') paginator!: MatPaginator;
async ngOnInit() {
// subscribe to file data from api
this.subs.add(this.api.getBlobData()
.subscribe((res) => {
this.blobs = res;
this.dataSource = new MatTableDataSource<IBlobData>(this.blobs); /* fill table with blob data */
this.dataSource.paginator = this.paginator; /* pagination on table */
this.dataSource.sort = this.sort; /* sorting on table */
// filter on table
this.dataSource.filterPredicate = function (data, filter) {
return data.name.toLowerCase().includes(filter.toLowerCase());
}
},
(err: HttpErrorResponse) => {
console.log(err);
}));
}
ngOnDestroy() {
if (this.subs) {
this.subs.unsubscribe();
}
}
toggleRow(element: { isExpanded: boolean; }) {
element.isExpanded = !element.isExpanded;
}
}
// some functions unrelated to this post where removed
css
table {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
min-width: 500px;
}
th.mat-header-cell {
text-align: left;
max-width: 300px;
}
tr.mat-header-row {
height: 40px !important;
background-color: whitesmoke;
}
.select-column {
width: 10%;
}
.download-button {
margin-left: 15px;
border: none;
width: 5%;
cursor: pointer;
vertical-align: middle;
}
.detail-row {
height: 0;
min-height: auto;
display: inline-block;
width: 100%;
}
.element-row td {
border-bottom-width: 0;
}
.element-detail {
overflow: hidden;
display: flex;
width: 100%;
}
.detail-table {
background: #b7b7b773;
text-align: center;
}
解决方案:
我使用 material 中的 expansion panel 得到了我想要的结果。
html
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let element">
<mat-expansion-panel (opened)="element.isExpanded = true"
(closed)="element.isExpanded = false">
<mat-expansion-panel-header>
<mat-panel-title [ngClass]="element.isExpanded ? 'expanded-title': ''">
{{element.name}}
</mat-panel-title>
</mat-expansion-panel-header>
<p>{{element.fileInfo}}</p>
</mat-expansion-panel>
</td>
</ng-container>
css
/* overwrite default material styling */
.mat-expansion-panel {
box-shadow: none !important;
padding: 0 !important;
}
.mat-expansion-panel-header {
padding: 0 20px 0 0!important;
}
.mat-expansion-panel-body {
padding: 0 !important;
}
ts
/* in my data file */
export interface IData {
name: string,
createdOn: string,
fileInfo: string
isExpanded: boolean;
}
/* in component.ts file */
isExpanded = false;
您可以使用 MatExpensionPanel,这里有示例 https://material.angular.io/components/expansion/examples。
所以我正在尝试构建一个 Material data-table,在 Angular 中进行分页、排序和过滤,以显示存储在 Azure 存储帐户中的文件。您可以下载您在左侧的复选框中选择的文件。
我目前坚持的是下一步,即打开扩展并在您相应地单击其行时显示文件的描述。 我尝试遵循 this 教程和其他多个教程,但目前面临以下问题:
如能提供有关如何执行此操作的任何帮助,我们将不胜感激,谢谢! 我不知道这是否只是一个样式问题或其他问题,但我已经尝试解决这个问题很长时间了,并且确定我在某处遗漏了一些东西 and/or 做错了什么。
html
<table mat-table [dataSource]="dataSource" class="full-width-table" matSort multiTemplateDataRows>
<ng-container matColumnDef="select">
<th class="select-column" mat-header-cell *matHeaderCellDef>
<mat-checkbox color="primary" (change)="$event ? selectAllToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
<mat-icon class="download-button" title="Click here to download the selected files" (click)="downloadSelected()" *ngIf="selection.hasValue()">save_alt</mat-icon>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="createdOn">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created On </th>
<td mat-cell *matCellDef="let element"> {{element.createdOn | date:'shortDate'}} </td>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
<div class="element-detail" [@detailExpand]="element.isExpanded ? 'expanded' : 'collapsed'">
{{element.fileInfo}}
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let element; columns: displayedColumns;" class="element-row"
[class.expanded-row]="element.isExpanded" (click)="toggleRow(element)">
</tr>
<tr *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
</table>
ts
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { ApiService } from '../api.services';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { MatSort } from '@angular/material/sort';
import { IBlobData } from '../blob-data';
import { Subscription } from 'rxjs';
import { MatTableDataSource } from '@angular/material/table';
import { HttpErrorResponse } from '@angular/common/http';
import { SelectionModel } from '@angular/cdk/collections';
import { MatPaginator } from '@angular/material/paginator';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
animations: [
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class HomeComponent implements OnInit {
blobs: any;
filterBlobs: any[] = [];
filterTerm: string = '';
private subs = new Subscription();
displayedColumns: any[] = [ 'select', 'name', 'createdOn'];
selection = new SelectionModel<IBlobData>(true, []);
public dataSource!: MatTableDataSource<IBlobData>;
constructor(private api: ApiService) { }
// configure sorting and paginator
@ViewChild(MatSort, { static: false }) sort!: MatSort;
@ViewChild('paginator') paginator!: MatPaginator;
async ngOnInit() {
// subscribe to file data from api
this.subs.add(this.api.getBlobData()
.subscribe((res) => {
this.blobs = res;
this.dataSource = new MatTableDataSource<IBlobData>(this.blobs); /* fill table with blob data */
this.dataSource.paginator = this.paginator; /* pagination on table */
this.dataSource.sort = this.sort; /* sorting on table */
// filter on table
this.dataSource.filterPredicate = function (data, filter) {
return data.name.toLowerCase().includes(filter.toLowerCase());
}
},
(err: HttpErrorResponse) => {
console.log(err);
}));
}
ngOnDestroy() {
if (this.subs) {
this.subs.unsubscribe();
}
}
toggleRow(element: { isExpanded: boolean; }) {
element.isExpanded = !element.isExpanded;
}
}
// some functions unrelated to this post where removed
css
table {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
min-width: 500px;
}
th.mat-header-cell {
text-align: left;
max-width: 300px;
}
tr.mat-header-row {
height: 40px !important;
background-color: whitesmoke;
}
.select-column {
width: 10%;
}
.download-button {
margin-left: 15px;
border: none;
width: 5%;
cursor: pointer;
vertical-align: middle;
}
.detail-row {
height: 0;
min-height: auto;
display: inline-block;
width: 100%;
}
.element-row td {
border-bottom-width: 0;
}
.element-detail {
overflow: hidden;
display: flex;
width: 100%;
}
.detail-table {
background: #b7b7b773;
text-align: center;
}
解决方案: 我使用 material 中的 expansion panel 得到了我想要的结果。
html
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let element">
<mat-expansion-panel (opened)="element.isExpanded = true"
(closed)="element.isExpanded = false">
<mat-expansion-panel-header>
<mat-panel-title [ngClass]="element.isExpanded ? 'expanded-title': ''">
{{element.name}}
</mat-panel-title>
</mat-expansion-panel-header>
<p>{{element.fileInfo}}</p>
</mat-expansion-panel>
</td>
</ng-container>
css
/* overwrite default material styling */
.mat-expansion-panel {
box-shadow: none !important;
padding: 0 !important;
}
.mat-expansion-panel-header {
padding: 0 20px 0 0!important;
}
.mat-expansion-panel-body {
padding: 0 !important;
}
ts
/* in my data file */
export interface IData {
name: string,
createdOn: string,
fileInfo: string
isExpanded: boolean;
}
/* in component.ts file */
isExpanded = false;
您可以使用 MatExpensionPanel,这里有示例 https://material.angular.io/components/expansion/examples。