1

My Objective: To display an expandable dynamic table without using any external table-library.

What I did: Currently, I'm looping inside a <div> to display a table (It works!). Now, I also want to add a button in front of every table-row, which when clicked will display some additional information related to that particular row. For that purpose I'm using ng-bootstrap's Collapse.

Issue I'm facing: As every row is expandable and the number of row is dynamic, I'm unable to figure out how can I build an expandable table row without initializing some variable within .ts file first. Also, I want all the rows to be closed at the beginning. As of now, all the expansion button have same id and refer to same boolean variable. Hence, whenever I try to expand one row, every row gets expanded.

Here's my code in HTML:

<div style="display: table-row" *ngFor="let row of rows">
    <button type="button" class="btn" (click)="'isCollapsed'+row.id = !'isCollapsed'+row.id" [attr.aria-expanded]="false"
        aria-controls="'collapse'+row.id">
        E
    </button>
    <div id="'collapse'+row.id" [ngbCollapse]="'isCollapsed'+row.id">
        <div class="card">
            <div class="card-body">
                Some dynamic table content
            </div>
        </div>
    </div>
    <div style="display: table-cell;">
        <input type="checkbox" [checked]="chk" [id]="row.id" [name]="row.id">
    </div>
    <div style="display: table-cell;"> {{row.id}} </div>
    <div style="display: table-cell;"> {{row.name}} </div>
    <div style="display: table-cell;"> {{row.address}} </div>
    <div style="display: table-cell;"> {{row.package}} </div>
    <div style="display: table-cell;"> {{row.notes}} </div>
    <div style="display: table-cell;"> {{row.price}} </div>
    <div style="display: table-cell;"> {{row.status}} </div>
</div>

1 Answer 1

2

You can create an array with rowsControls that will store information about collapse. In your component, try something like this:

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

@Component({
  selector: 'ngbd-collapse-basic',
  templateUrl: './collapse-basic.html'
})
export class NgbdCollapseBasic implements OnInit {
  rowsControls = [];
  rows = [{
    id: 0,
    name: 'First row'
  }, {
    id: 1,
    name: 'Second row'
  }, {
    id: 2,
    name: 'Third row'
  }]

  ngOnInit() {
    this.rows.forEach(row => {
      this.rowsControls.push({
        isCollapsed: true
      })
    });
  }
}

And then template bind to each row isCollapse property like following:

<div *ngFor="let row of rows; let index = index">
  <p>
    <button 
      type="button" 
      class="btn btn-outline-primary" 
      (click)="rowsControls[index].isCollapsed = !rowsControls[index].isCollapsed"
      [attr.aria-controls]="'collapse_' + row.id"
    >
      Toggle
    </button>
  </p>
  <div 
    id="collapse_{{ row.id }}" 
    [ngbCollapse]="rowsControls[index].isCollapsed"
  >
    <div class="card">
      <div class="card-body">
        Some dynamic content of {{ row.name }}
      </div>
    </div>
  </div>
</div>

You can check the demo here: https://angular-dkxc1t.stackblitz.io

Sign up to request clarification or add additional context in comments.

2 Comments

One more thing, is writing "'collapse_' + row.id" vs "collapse_{{ row.id }}" effectively same?
You can read more about interpolation and property binding here: dotnetcurry.com/angularjs/1424/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.