Abhinay kumar Mishra
Abhinay kumar Mishra

Reputation: 11

How to reuse Angular material table in Angular 17?

I have created a child component and use Angular Material. I am showing dynamic data which is passed to parent component. I am unable to action icon and name so that I can pass event in parent component from child, this project also standalone using

enter image description here

Here is my code which are trying

Parent component:

ngOnInit() {
    this.columns = [
      {
        title: "Country",
        name: "countryName"
      },      
      {
        title: "State",
        name: "state"
      },      
      {
        title: "City",
        name: "cityName"
      },     
      {
        title: "Created By",
        name: "createdBy"
      },
      {
        title: "Created Date",
        name: "createdAt"
      },
      {
        title: "Action",
        name: 'actions',
        buttons: [
          {
            type: "",
            icon: "edit",
            class: "tbl-fav-edit",
            title: ActionButtonType.Edit,
            click: this.btnEditClick,
          },
          {
            type: "",
            icon: "trash-2",
            class: "tbl-fav-delete",
            title: ActionButtonType.Delete,
            click: 'this.btnDeleteClick',
          }
        ]
      }
    ]
    this.getAllCity();
  }

 @if (flg) {
      <app-dynamic-mat-table  [workList]="workList" [columns]="columns"></app-dynamic-mat-table>
                      }

Child component:

import { Component, Input,  OnInit,ViewChild } from '@angular/core';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatIconModule } from '@angular/material/icon';
import { DatePipe } from '@angular/common';
import { FeatherIconsComponent } from '../feather-icons/feather-icons.component';
@Component({
  selector: 'app-dynamic-mat-table',
  standalone: true,
  imports: [MatTableModule,MatPaginatorModule,MatPaginator,MatIconModule,DatePipe,FeatherIconsComponent, DatePipe,],
  templateUrl: './dynamic-mat-table.component.html',
  styleUrl: './dynamic-mat-table.component.scss'
})

export class DynamicMatTableComponent implements OnInit{  
  hide = true; 
  @ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
  @Input() workList:any=[];
  @Input() columns:any=[];
  dataSource:any;  
  displayedColumns=[];  
  displayedColumnss=[];  

  constructor(){
  }

  ngOnInit(): void {
    console.log(this.columns);
    this.dataSource = new MatTableDataSource<any>(this.workList);
    this.displayedColumns = this.columns.map((column: any) => column.name);   
    this.displayedColumnss = this.columns.map((column: any) => column);   
    this.dataSource.paginator = this.paginator;
    console.log(this.displayedColumns);
    console.log(this.displayedColumnss);
  }

  getColumnTitle(columnName: []) {    
    console.log(columnName);
    console.log(this.columns);
    
    const columnTitle = this.columns.find((column: any) => column.name === columnName);
    return columnTitle ? columnTitle.title : '';
}
  <div class="responsive_table">
                    <table mat-table [dataSource]="dataSource" matSort class="mat-cell advance-table">
                        @for (column of displayedColumns; track column) {                           
                                <ng-container [matColumnDef]="column">
                                    <th mat-header-cell *matHeaderCellDef mat-sort-header> {{ getColumnTitle(column) }} </th>
                                    <td mat-cell *matCellDef="let element"> 
                                        @if(column==='createdAt'){
                                            {{ element[column] | date: 'dd-MM-yyyy' }} 
                                          }@else{
                                            {{ element[column] }} 
                                          }
                                        @if(column==='actions'){
                                            {{element[column]}}
                                           @for(actionButton of element.buttons; track actionButton){
                                            <span>{{actionButton}}sww</span>
                                           }                                           
                                        <td><app-feather-icons [icon]="'edit'" [class]="'tbl-fav-edit'" ></app-feather-icons></td>
                                        <td> <app-feather-icons [icon]="'trash-2'" [class]="'tbl-fav-delete'"></app-feather-icons></td>
                                          }
                                    </td>                                  
                                </ng-container>                               
                        }                       
                        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
                        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
                    </table>                   
                    <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
                  </div>

Here edit and delete icon are showing static, but I need to show this icon come from parent so that we can use dynamically and when we click edit icon need to print records also in parent component

Upvotes: 0

Views: 589

Answers (2)

rayss
rayss

Reputation: 657

Hi I'm having issue on this using Angular17 using material-dynamic-table. it seems the package only support upto Angular 16 at the moment. Is there way to work this in Angular 17?

Error: node_modules/material-dynamic-table/lib/dynamic-table.component.d.ts:2:52 - error TS2307: Cannot find module '@angular/material/legacy-paginator' or its corresponding type declarations.

2 import { MatLegacyPaginator as MatPaginator } from '@angular/material/legacy-paginator';

Upvotes: 0

UnknownX
UnknownX

Reputation: 1

you need to pass the click event handlers from the parent component to the child component !Then, the child component can use these handlers to trigger actions in the parent component... -> In the parent component, define click event handlers for the action buttons (btnEditClick and btnDeleteClick).. -> Pass these event handlers to the child component as part of the columns input, -> In the child component, modify the template to use the passed event handlers for the action buttons. ->When the action buttons are clicked in the child component, trigger the corresponding event handler passed from the parent component ! \modified code\

#Parent Component

export class ParentComponent {
  // Define click event handlers
  btnEditClick(item: any) {
    console.log('Edit clicked:', item);
  }

  btnDeleteClick(item: any) {
    console.log('Delete clicked:', item);
  }

  // Your existing code for column definition
}

-------------------------------------------------------------| #Child Component Template

<!-- Inside the table -->
<td mat-cell *matCellDef="let element">
  <span *ngIf="column.name !== 'actions'">{{ element[column.name] }}</span>
  <span *ngIf="column.name === 'actions'">
    <button mat-icon-button (click)="column.click(element)">
      <mat-icon>{{ column.icon }}</mat-icon>
    </button>
  </span>
</td>

-------------------------------------------------------------| With this setup, when the action buttons are clicked in the child component... they trigger the corresponding event handlers(btnEditClick or btnDeleteClick)passed from the parent component. --->You'll also need to update your columns definition in the parent component to include the click property <--- :

this.columns = [
  // Other column definitions...
  {
    title: "Action",
    name: 'actions',
    buttons: [
      {
        type: "",
        icon: "edit",
        class: "tbl-fav-edit",
        title: ActionButtonType.Edit,
        click: this.btnEditClick.bind(this), // Bind the event handler
      },
      {
        type: "",
        icon: "trash-2",
        class: "tbl-fav-delete",
        title: ActionButtonType.Delete,
        click: this.btnDeleteClick.bind(this), // Bind the event handler
      }
    ]
  }
];

-------------------------------------------------------------| !{Make sure to bind the event handlers (btnEditClick and btnDeleteClick) to the parent component instance using...bind(this),so they maintain the correct context when passed to the child component}! you're welcome<3

Upvotes: 0

Related Questions