How to Create Expand/Collapse Function for Each Row of Table - Angular6

Expand/Collapse table rows - Angular 11 Material

You can use MatExpensionPanel, you've got an example here https://material.angular.io/components/expansion/examples.

Expand/collapse table rows in Angular

For keeping the table row expanded until you click on the row to collapse, you just need boolean flag on each element array. I would suggest to create property under your array as false and set it to toggle on click of row. Also, as @brandon mentioned in comment, your html is invalid. So I modified it a bit.

HTML:

<table class="table">
<tr class="header-row">
<th class="header">Province</th>
</tr>
<tr
class="table-row-not-expanded"
*ngFor="let covenant of covenants; let i = index"
>
<td class="cell" (click)="covenant.isExpanded = !covenant.isExpanded">
<div>{{ covenant.provinceID }}</div>

<div *ngIf="covenant.isExpanded" class="expanded-panel">
<div class="table-container">
<table class="table">
<tr class="header-row">
<th class="header">header 1</th>
<th class="header">header 2</th>
<th class="header">header 3</th>
</tr>
<tr class="table-row">
<td class="cell">1</td>
<td class="cell">2</td>
<td class="cell">3</td>
</tr>
</table>
</div>
</div>
</td>
</tr>
</table>

TS:

import { Component, OnInit, VERSION } from '@angular/core';

@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
name = 'Angular ' + VERSION.major;

covenants: any = [
{ provinceID: 1 },
{ provinceID: 2 },
{ provinceID: 3 },
{ provinceID: 4 },
{ provinceID: 5 },
];

openCoverages = false;
indexSelectedCoverage = 1;

ngOnInit() {
this.covenants.forEach((_covenants) => {
_covenants.isExpanded = false;
});
}
selectItemCoverages(index: number) {
//this.openCoverages = this.openCoverages && this.indexSelectedCoverage === index ? false : true;
//this.indexSelectedCoverage = index;
}
}

Play here

Expand and collapse row on button click which is in a td in mat table row

you need add to your search.component.css

tr.example-detail-row {
height: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
}
.example-element-row td {
border-bottom-width: 0;
}

And remove the (click) in row

//this
<tr mat-row *matRowDef="let search; columns: displayedColumns;"
class="example-element-row"
[class.example-expanded-row]="expandedElement === search"
(click)="expandedElement = expandedElement === search ? null : search">
`enter code here`
</tr>

become as

<tr mat-row *matRowDef="let search; columns: displayedColumns;" 
class="example-element-row"
[class.example-expanded-row]="expandedElement === search">
</tr>

See this fool stackblitz

Angular material table collapse/expand complete table so only header is visible

Solution:

When tapping collapse, I assign an empty array to the data source of that table. when clicking expands I reassign the original array to the data source of that table. This way my header&footer cells which contain totals for the table are still visible but the inner cells are not.

Something like the code below should allow this behavior:

collapse(index: number) {
if (this.contracts[index].tabledatasource.data.length == 0) {
this.contracts[index].tabledatasource = new MatTableDataSource(this.stockArray[index]);
} else {
this.contracts[index].tabledatasource = new MatTableDataSource([]);
}


}

Expandable table rows in angular 4 with angular material

As mentioned here by Andrew Seguin this is already feasible out of the box: using the when predicate.

See this example: https://stackblitz.com/edit/angular-material-expandable-table-rows (thx to Lakston)

demo

Inside of the mat-table tag you have to use the mat-row component with a matRipple directive. When you click on a row the row element will be assigned to the expandedElement variable:

<mat-row *matRowDef="let row; columns: displayedColumns;"
matRipple
class="element-row"
[class.expanded]="expandedElement == row"
(click)="expandedElement = row">
</mat-row>

But now we have to add our expanded row, that is hidden by default and will be shown if the user clicks on the row above:

<mat-row *matRowDef="let row; columns: ['expandedDetail']; when: isExpansionDetailRow"
[@detailExpand]="row.element == expandedElement ? 'expanded' : 'collapsed'"
style="overflow: hidden">
</mat-row>

Important is here the already mentioned when predicate. This calls a isExpansionDetailRow function that is defined in the component itself and checks if the row has a detailRow property:

isExpansionDetailRow = (row: any) => row.hasOwnProperty('detailRow');

Since RC0 the first param is the index:

isExpansionDetailRow = (i: number, row: any) => row.hasOwnProperty('detailRow');

If you want to have an expanded view for every row, you have to add an "ExpansionDetailRow" identified by the detailRow property for every row like this:

connect(): Observable<Element[]> {
const rows = [];
data.forEach(element => rows.push(element, { detailRow: true, element }));
return Observable.of(rows);
}

If you would log the rows variable to the console output, it will look like this:

console output

EDIT: COMPLETE EXAMPLE USING DIRECTIVE

Mat Table expandable rows (sorting, pagination and filtering)

Hide/show a table row when clicking on a link in Angular2

The problem you are facing here is that you are associating a toggle to an element inside a for loop without actually creating different references. This means that all the generated table rows will point to the same reference so when you click one link it will affect multiple.

Since you are already getting the index on the ngFor loop you should associate that index to the toggle references. The result would become something like this

toggle_1[total.projectGroup]
toggle_2[total.projectGroup]

This way the reference for the action would be kept on each row of the table.

But to simplify what it seems to be your goal you could just have

(click) = “toggle[i] = !toggle[i]”

And then where you have the hidden checking the toggle I would also replace

[hidden]="!toggle[total.projectGroup]"

With

[hidden]="!toggle[i]”

I believe you just need the template flags. Unless you need some more complex behaviour I don't think you need the component function at all

I have also noticed that you have the second ngFor loop without an index. This will cause issues because when you set the indProjects property it will have the same value for all the rows. So you need to pass the index to your expand(total.projectGroup, i) function and in the template when doing the loop you will need to read from

<tr *ngFor="let pjt of indProjects[i]" class="table-condensed">

This way you will for sure have unique list per row

How to expand and collapse table row on click

In your (click) event you are only setting expandedElement so it will always get selected. You need to instead toggle the value so the row can be deselected as well.

Change your (click) function to the following

<mat-row *matRowDef="let row; columns: displayedColumns;"
matRipple
class="element-row"
[class.expanded]="expandedElement == row"
(click)="expandedElement = expandedElement === row ? null : row">
</mat-row>


Related Topics



Leave a reply



Submit