User123
User123

Reputation: 373

How to make expandable table rows within an ngFor loop [Angular]?

I've nested tables, when a row is clicked I need to display data underneath the table row. However, the data is being displayed at the end of ngRepeat.

HTML:

  <table class="table table-hover table-bordered table-responsive-xl">
  <thead>
    <th> Name </th>
    <th> Place </th>
    <th> Phone </th>
  </thead>

  <tbody>

  <tr *ngFor="let data of data1" (click) ="expand()">
        <td> +{{data.name}} </td>
        <td> {{data.place}} </td>
        <td> {{data.phone}} </td>
  <td> {{data.hobbies}} </td>
  <td> {{data.profession}} </td>
 </tr>

 <ng-container *ngIf="expandContent">
    <tr *ngFor="let data of data2">
        <td> {{data.datades.name}} </td>
        <td> {{data.datades.hobbies}} </td>
        <td> {{data.datades.profession}} </td>
 </tr>
 </ng-container>
 </tbody>
 </table>

Component :

export class AppComponent  {
expandContent = true;
  data1 =[{
 'name' : 'john',
 'place' : 'forest',
 'phone' : '124-896-8963'
  },{
 'name' : 'Jay',
 'place' : 'City',
 'phone' : '124-896-1234'
  }, {
 'name' : 'Joseph',
 'place' : 'sky',
 'phone' : '124-896-9632'
  },
  ]

 data2 =[{
'whoseData' : 'john',
'datades' : {
'name' : 'john',
'hobbies' : 'singing',
'profession' : 'singer'
 }
 },{
'whoseData' : 'Jay',
'datades' : {
'name' : 'jay',
'hobbies' : 'coding',
'profession' : 'coder'
}
}
]

 expand(){
this.expandContent = !this.expandContent
}
 }

When the first row is clicked I would like to display, the data associated with the first row, under it.

Expected result enter image description here

DEMO

Upvotes: 7

Views: 14449

Answers (2)

Martin Parenteau
Martin Parenteau

Reputation: 73771

You would need to make these changes:

  1. Include the main row and the corresponding detail rows in the same ngFor loop iteration
  2. Add an expanded property to the data objects, instead of having the global expandContent
  3. Define a method to filter the details of the clicked row

The template could look as follows:

<ng-container *ngFor="let data of data1">
  <tr (click)="data.expanded = !data.expanded">
    <td> {{ data.expanded ? '&ndash;' : '+'}} {{data.name}} </td>
    <td> {{data.place}} </td>
    <td> {{data.phone}} </td>
    <td> {{data.hobbies}} </td>
    <td> {{data.profession}} </td>
  </tr>
  <ng-container *ngIf="data.expanded">
    <tr *ngFor="let details of findDetails(data)">
      <td> {{details.datades.name}} </td>
      <td> {{details.datades.hobbies}} </td>
      <td> {{details.datades.profession}} </td>
    </tr>
  </ng-container>
</ng-container>

where findDetails is defined as:

findDetails(data) {
  return this.data2.filter(x => x.whoseData === data.name);
}

See this stackblitz for a demo.

Upvotes: 21

developing2020
developing2020

Reputation: 322

Your dropdown data is being displayed at the bottom of the table because your ng-container is in a separate div. Checkout Bootstrap Collapse and look at the Accordion example to see if it will solve your problem: https://getbootstrap.com/docs/4.1/components/collapse/

Upvotes: 0

Related Questions