Angular材质表为每条记录添加一行,同时在Angular 9中实现行代码的扩展



我正处于学习angular 9的初始阶段。我有一个垫子表,每行都有一个图标,我正在尝试编写代码,以便在单击图标时扩展特定的行。我下面的代码运行良好,但在加载页面时,中的每条记录都会添加一行额外的代码

import { Component, OnInit, ViewChild, ChangeDetectorRef, ElementRef } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { LoginService } from '../login.service';
import { MatTableDataSource } from '@angular/material/table';
import { Candidate } from '.././Models/candidate.model';
@Component({
selector: 'app-candidates',
templateUrl: './candidates.component.html',
styleUrls: ['./candidates.component.scss'],
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 CandidatesComponent implements OnInit {

columnsToDisplay: string[] = ['arrow', 'reference', 'name', 'date', 'grade', 'location', 'status', 'action'];
dataSource = new MatTableDataSource();
expandedElement: Candidate | null;
categories = [
{ value: 'category', viewValue: 'category' },
{ value: 'C1', viewValue: 'grade3' },
{ value: 'C2', viewValue: 'grade4' },
{ value: 'C3A', viewValue: 'grade2' },
];
constructor(private loginService: LoginService) { }
ngOnInit(): void {
// this.loginService.getCandidates().subscribe(results => {
//   console.log("inisde candidate ts ===>", results);
//   if (!results) { return };
//   this.dataSource.data = results;
// });
this.dataSource.data=[
{
"referenceId": "ENk2N789",
"firstName": "heidi",
"middleName": null,
"lastName": null,
"grade": "ITA",
"location": "Chennai",
"status": "New",
"emailId": "heidi@gmail.com",
"phone": "97 9884729272",
"empId": "135124",
"reportingAddress": "Chennai Siruseri",
"startDate": "2020-07-06T16:48:33.743+00:00",
"confirmDate": null,
"taggedBuddy": "yes",
"isExpanded" : false
},
{
"referenceId": "QWK2N789",
"firstName": "nemo",
"middleName": null,
"lastName": null,
"grade": "C!",
"location": "Hyderabad",
"status": "New",
"emailId": "nemo@gmail.com",
"phone": "97 9245367234",
"empId": "123456",
"reportingAddress": "Chennai Siruseri",
"startDate": "2020-07-06T16:48:33.743+00:00",
"confirmDate": null,
"taggedBuddy": "yes",
"isExpanded" : false
},
{
"referenceId": "ESR2N789",
"firstName": "minion",
"middleName": null,
"lastName": null,
"grade": "ITA",
"location": "Chennai",
"status": "New",
"emailId": "minion@tcs.com",
"phone": "97 9245677234",
"empId": "1332130",
"reportingAddress": "Chennai Siruseri",
"startDate": "2020-07-06T16:48:33.743+00:00",
"confirmDate": null,
"taggedBuddy": "yes",
"isExpanded" : false
}
]
}
approveCandidate() {
console.log("approve ta gbuddy");
}
tagBuddy() {
console.log("gettign ta gbuddy");
}
}
.table-bg1{
top: 57px;
left: 0px;
width: 1366px;
height: 268px;
background: url('../../assets/images/Diversity-Img.png') rgba(0, 0, 0, 0.36) 0% 0% no-repeat padding-box;
background-size: cover;
background-blend-mode: multiply;
margin-top: 57px;   
//opacity: 0.36;
}
a{
text-decoration: none;
}
.cand_heading{
top: 152px;
left: 165px;
width: 230px;
height: 61px;
text-align: center;
font: Bold 50px/61px Calibri;
letter-spacing: 0px;
color: #FFFEFE;
position: absolute;
//opacity: 1;
}
.table-bg2{
top: 325px;
left: 0px;
width: 1366px;
height: 702px;
background: url('../../assets/images/shutterstock_709202158.png') rgba(0, 0, 0, 0.36) 0% 0% no-repeat padding-box;
background-size: cover;
background-blend-mode: multiply;  
// opacity: 0.36;
}
.table_layout{
top: 484px;
left: 30px;
width: 1296px;
height: 393px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border-radius: 47px 47px 38px 38px;
opacity: 1;
margin: 21px 40px 89px 30px;
}
.table_header{
top: 484px;
left: 30px;
width: 1296px;
height: 62px;
background: transparent linear-gradient(180deg, #2B74F3 0%, #163A7A 100%) 0% 0% no-repeat padding-box;
border-radius: 38px 38px 0px 0px;
opacity: 1;
}
.column {
float: left;
width: 286px;
padding: 5px;
}
/* Clearfix (clear floats) */
.row::after {
content: "";
clear: both;
display: block;
}
.approve_link {
top: 558px;
left: 1104px;
width: 70px;
height: 20px;
text-align: left;
font: Regular 14px/20px Source Sans Pro;
letter-spacing: 0px;
color: #2D81B7;
opacity: 1;
}
.buddy_tag_link {
top: 559px;
left: 1189px;
width: 101px;
height: 20px;
text-align: left;
font: Regular 14px/20px Source Sans Pro;
letter-spacing: 0px;
color: #2D81B7;
opacity: 1;
}
.catg_dd{
top: 389px;
left: 111px;
width: 315px;
height: 42px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border: 1px solid #707070;
border-radius: 21px;
opacity: 1;
margin: 64px 43px 0px 81px;   
}
.ref_id_input {
top: 389px;
left: 469px;
width: 315px;
height: 42px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border: 1px solid #707070;
border-radius: 21px;
opacity: 1;
margin: 64px 43px 0px 0px;
}
.records_dd{
top: 389px;
left: 827px;
width: 173px;
height: 42px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border: 1px solid #707070;
border-radius: 21px;
opacity: 1;
margin: 64px 43px 0px 0px;
}
.search {
top: 389px;
left: 1043px;
width: 173px;
height: 42px;
background: transparent linear-gradient(180deg, #21BF36 0%, #11601B 100%) 0% 0% no-repeat padding-box;
border-radius: 21px;
opacity: 1;
margin: 64px 0px 0px 0px;
}
.export_btn {
top: 962px;
left: 53px;
width: 173px;
height: 42px;
color: white;
background: transparent linear-gradient(180deg, #21BF36 0%, #11601B 100%) 0% 0% no-repeat padding-box;
border-radius: 21px;
margin: 0px 0px 23px 53px;
opacity: 1;
}
mat-icon {
cursor: pointer;
}
.expandIcon{
left: 53px;
width: 20px;
height: 20px;
background:#149AEF  0% 0% no-repeat padding-box;
opacity: 1;
border-radius: 10px;
}
//table css properties
table {
width: 100%;
}
tr.candidate-detail-row {
height: 0;
}
tr.candidate-element-row:not(.candidate-expanded-row):hover {
background: whitesmoke;
}
tr.candidate-element-row:not(.candidate-expanded-row):active {
background: #efefef;
}
.candidate-element-row td {
border-bottom-width: 0;
}
.candidate-element-detail {
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background-color: #e1e1e1;
box-shadow: inset 2px 3px 8px #c1c1c1;
border-radius: 8px;
}
<app-header></app-header>
<div class="table-bg1">
<span class="cand_heading">Candidates</span>
</div>
<div class="table-bg2">
<div class="row">
<div class="column catg_dd">
<mat-form-field class="">
<mat-select>
<mat-option *ngFor="let category of categories" [value]="category.value">
{{ category.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="column ref_id_input">
<mat-form-field class="">
<mat-label>Reference ID</mat-label>
<input matInput placeholder="Reference ID" value="">
</mat-form-field>
</div>
<div class="column records_dd">
<mat-form-field class="">
<mat-select>
<mat-option *ngFor="let category of categories" [value]="category.value">
{{ category.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="column search">
<button type="submit">Search</button>
</div>
</div>
<div class="row">
<table mat-table class="table_layout" [dataSource]="dataSource" multiTemplateDataRows>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="arrow">
<th mat-header-cell *matHeaderCellDef mat-sort-header></th>
<td mat-cell *matCellDef="let element">
<mat-icon class="expandIcon" (click)="element.isExpanded = !element.isExpanded">
{{expandedElement === element ? '-' : '+'}}</mat-icon>
</td>
</ng-container>
<ng-container matColumnDef="reference">
<th mat-header-cell *matHeaderCellDef>Reference</th>
<td mat-cell *matCellDef="let element"> {{element.referenceId}}
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *matCellDef="let element"> {{element.firstName}}
{{element.middleName}} {{element.lastName}}
</td>
</ng-container>
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef>Date</th>
<td mat-cell *matCellDef="let  element"> {{element.startDate |date: 'dd/MM/yyyy'}}
</td>
</ng-container>
<ng-container matColumnDef="grade">
<th mat-header-cell *matHeaderCellDef>Grade</th>
<td mat-cell *matCellDef="let  element"> {{element.grade}} </td>
</ng-container>
<ng-container matColumnDef="location">
<th mat-header-cell *matHeaderCellDef>Location</th>
<td mat-cell *matCellDef="let element"> {{element.location}} </td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef>Status</th>
<td mat-cell *matCellDef="let  element"> {{element.status}} </td>
</ng-container>
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef>Action</th>
<td mat-cell *matCellDef="let element">
<a (click)="approveCandidate()" class="approve_link">Approve</a>
<a (click)="tagBuddy()" class="buddy_tag_link">Buddy Tagging</a>
</td>
</ng-container>
<!-- Template for details row -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
<div class="row candidate-element-detail"
[@detailExpand]="element.isExpanded ? 'expanded' : 'collapsed'">
<div class="row" style="margin-left: 150px;">
<div class="column">
<span> Email ID: {{element.emailId}}</span>
</div>
<div class="column">
<span> Employee ID: {{element.empId}}</span>
</div>
<div class="column">
<span> Start Date:{{element.startDate |date: 'dd/MM/yyyy'}}</span>
</div>
</div>
<div class="row" style="margin-left: 150px;">
<div class="column">
<span> Phone: {{element.phone}}</span>
</div>
<div class="column">
<p>Reporting Address: {{element.reportingAddress}}</p>
</div>
<div class="column">
<span>Confirmation Date:{{element.confirmDate |date: 'dd/MM/yyyy'}}</span>
</div>
</div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay;sticky: true" class="table_header"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;" class="candidate-element-row"
[class.candidate-expanded-row]="element.isExpanded"></tr>
<!-- Extra row to show detail content column -->
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="candidate-detail-row"></tr>
</table>
</div>
<div class="row">
<div class="column">
<button class="export_btn">Export</button>
</div>
</div>
</div>
<app-footer></app-footer>

桌子。任何人请查看我的代码,如果我做错了什么或遗漏了什么,请帮助我。组件负载表

import { Component, OnInit, ViewChild, ChangeDetectorRef,ElementRef } from '@angular/core';
import {animate, state, style, transition, trigger} from '@angular/animations';
import { LoginService } from '../login.service';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Candidate } from '.././Models/candidate.model';
@Component({
selector: 'app-candidates',
templateUrl: './candidates.component.html',
styleUrls: ['./candidates.component.scss'],
animations: [
trigger('detailExpand', [
state('collapsed, void', style({ height: '0px',visibility: 'hidden'  })),
state('expanded', style({ height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
transition('expanded <=> void', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
]),
],
})
export class CandidatesComponent implements OnInit {

columnsToDisplay: string[] = ['arrow','reference', 'name', 'date', 'grade', 'location', 'status', 'action'];
dataSource = new MatTableDataSource<Candidate>();
expandedElement: Candidate | null;

constructor(private loginService: LoginService, private cdr: ChangeDetectorRef,private eleRef: ElementRef) { }
ngOnInit(): void {   
this.loginService.getCandidates().subscribe(results => {
console.log("inisde candidate ts ===>", results);
if (!results) { return };
this.dataSource.data = results;
});
console.log("this after table displayed expanele on init",this.expandedElement);
}
}
.table-bg1{
top: 57px;
left: 0px;
width: 1366px;
height: 268px;
background: url('../../assets/images/Diversity-Img.png') #000000 0% 0% no-repeat padding-box;
//opacity: 0.36;
}
.cand_heading{
top: 152px;
left: 165px;
width: 230px;
height: 61px;
text-align: center;
font: Bold 50px/61px Calibri;
letter-spacing: 0px;
color: #FFFEFE;
//opacity: 1;
}
.table-bg2{
top: 325px;
left: 0px;
width: 1366px;
height: 702px;
background: url('../../assets/images/shutterstock_709202158.png') #000000 0% 0% no-repeat padding-box;
// opacity: 0.36;
}
.table_layout{
top: 484px;
left: 30px;
width: 1296px;
height: 393px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border-radius: 47px 47px 38px 38px;
opacity: 1;
margin: 21px 40px 89px 30px;
}
.table_header{
top: 484px;
left: 30px;
width: 1296px;
height: 62px;
background: transparent linear-gradient(180deg, #2B74F3 0%, #163A7A 100%) 0% 0% no-repeat padding-box;
border-radius: 38px 38px 0px 0px;
opacity: 1;
}
.column {
float: left;
width: 286px;
padding: 5px;
}
/* Clearfix (clear floats) */
.row::after {
content: "";
clear: both;
display: block;
}

thead{
border-radius: 47px 47px;
}

.approve_link{
top: 558px;
left: 1104px;
width: 70px;
height: 20px;
text-align: left;
font: Regular 14px/20px Source Sans Pro;
letter-spacing: 0px;
color: #2D81B7;
opacity: 1;
}
.buddy_tag_link{
top: 559px;
left: 1189px;
width: 101px;
height: 20px;
text-align: left;
font: Regular 14px/20px Source Sans Pro;
letter-spacing: 0px;
color: #2D81B7;
opacity: 1;
}
.catg_dd{
top: 389px;
left: 111px;
width: 315px;
height: 42px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border: 1px solid #707070;
border-radius: 21px;
opacity: 1;
margin: 64px 43px 0px 81px;
}
.ref_id_input{
top: 389px;
left: 469px;
width: 315px;
height: 42px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border: 1px solid #707070;
border-radius: 21px;
opacity: 1;
margin: 64px 43px 0px 0px;
}
.records_dd{
top: 389px;
left: 827px;
width: 173px;
height: 42px;
background: #FFFFFF 0% 0% no-repeat padding-box;
border: 1px solid #707070;
border-radius: 21px;
opacity: 1;
margin: 64px 43px 0px 0px;
}
.search{
top: 389px;
left: 1043px;
width: 173px;
height: 42px;
background: transparent linear-gradient(180deg, #21BF36 0%, #11601B 100%) 0% 0% no-repeat padding-box;
border-radius: 21px;
opacity: 1;
margin: 64px 0px 0px 0px;
}
::ng-deep .mat-select-content{
width:2000px;
background-color: red;
font-size: 10px;   
}
.export_btn{
top: 962px;
left: 53px;
width: 173px;
height: 42px;
color: white;
background: transparent linear-gradient(180deg, #21BF36 0%, #11601B 100%) 0% 0% no-repeat padding-box;
border-radius: 21px;
margin: 0px 0px 23px 53px;
opacity: 1;
}
.ic_add_circle{
top: 680px;
left: 53px;
width: 20px;
height: 20px;
background: #FFFFFF 0% 0% no-repeat padding-box;
opacity: 1;
}
//expansion properties
// .example-detail-row {
//   height: 0;
// }
// .example-element-detail {
//   overflow: hidden;
//   display: flex;
// }
// .example-element-description {
//   padding: 16px;
// }
.element-row {
position: relative;
}
.element-row:not(.expanded):hover {
background: #f5f5f5;
}
.element-row.expanded {
border-bottom-color: transparent;
}
i:hover {
cursor: pointer;
}
//tttttttttttttttttttttttttttttttttttttttttttttttttttttt

mat-row.example-detail-row {
height: 0;
}
// mat-row.example-element-row:not(.example-expanded-row):hover {
//   background: rgb(46, 235, 8);
// }
mat-row.example-element-row:not(.example-expanded-row):active {
background: grey;
}
.example-element-row mat-cell {
border-bottom-width: 0;
}
// .example-element-detail {
//   overflow: hidden;
//   display: flex;
// }
mat-icon {
cursor: pointer;
}
.expandIcon{
left: 53px;
width: 20px;
height: 20px;
background:#149AEF  0% 0% no-repeat padding-box;
opacity: 1;
border-radius: 10px;
}
<app-header></app-header>
<div class="table-bg1">
<span class="cand_heading">Candidates</span>
</div>
<div class="table-bg2">
<div class="row">
<mat-table class="table_layout" [dataSource]="dataSource" multiTemplateDataRows>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="arrow">
<mat-header-cell *matHeaderCellDef mat-sort-header></mat-header-cell>
<mat-cell *matCellDef="let element">
<mat-icon class="expandIcon"
(click)="expandedElement = expandedElement === element ? null : element">
{{expandedElement === element ? '-' : '+'}}</mat-icon>
</mat-cell>
</ng-container>
<ng-container matColumnDef="reference">
<mat-header-cell *matHeaderCellDef>Reference</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.referenceId}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.firstName}}
{{element.middleName}} {{element.lastName}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Date</mat-header-cell>
<mat-cell *matCellDef="let  element"> {{element.startDate |date: 'dd/MM/yyyy'}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="grade">
<mat-header-cell *matHeaderCellDef>Grade</mat-header-cell>
<mat-cell *matCellDef="let  element"> {{element.grade}} </mat-cell>
</ng-container>
<ng-container matColumnDef="location">
<mat-header-cell *matHeaderCellDef>Location</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.location}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef>Status</mat-header-cell>
<mat-cell *matCellDef="let  element"> {{element.status}} </mat-cell>
</ng-container>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<a href="" class="approve_link">Approve</a>
<a href="" class="buddy_tag_link">Buddy Tagging</a>
</mat-cell>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
<div class="example-element-detail"
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'"
[style.height]="element == expandedElement ? 'unset' : '0 !important'">
<div class="row" style="margin-left: 150px;">
<div class="column">
<span> Email ID: {{element.emailId}}</span>
</div>
<div class="column">
<span> Employee ID: {{element.empId}}</span>
</div>
<div class="column">
<span> Start Date:{{element.startDate |date: 'dd/MM/yyyy'}}</span>
</div>
</div>
<div class="row" style="margin-left: 150px;">
<div class="column">
<span> Phone: {{element.phone}}</span>
</div>
<div class="column">
<p>Reporting Address: {{element.reportingAddress}}</p>
</div>
<div class="column">
<span>Confirmation Date:{{element.confirmDate |date: 'dd/MM/yyyy'}}</span>
</div>
</div>
</div>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columnsToDisplay" class="table_header"></mat-header-row>
<mat-row *matRowDef="let row; columns: columnsToDisplay;" class="example-element-row"
[class.example-expanded-row]="expandedElement === element">
</mat-row>
<mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></mat-row>
</mat-table>
</div>
<div class="row">
<div class="column">
<button class="export_btn">Export</button>
</div>
</div>
</div>
<app-footer></app-footer>

enter code here

我无法通过复制成功运行您的代码,如果您可以放入stackblitz,我可以再次检查,同时您可以在这里查看类似的功能示例

根据上面的代码,创建材料表的方法是使用display:flex样式,而不是本地HTML表
参考https://material.angular.io/components/table/overview#tables-带显示器柔性

但上述文件也表明:

请注意,这种方法意味着您不能包含某些本机表功能,如colspan/rowspan,也不能让列根据其内容自行调整大小。

您可能还面临问题,因为在这种替代方法中,很少有功能不能正常工作。

因此,尝试使表成为本地HTML类型。

下面是一个例子:示例

最新更新