<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kapil Kumar</title>
    <description>The latest articles on DEV Community by Kapil Kumar (@kapilkumar0037).</description>
    <link>https://dev.to/kapilkumar0037</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1862745%2F4a93d6ed-3830-4589-a17d-f4f0515caeb0.png</url>
      <title>DEV Community: Kapil Kumar</title>
      <link>https://dev.to/kapilkumar0037</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kapilkumar0037"/>
    <language>en</language>
    <item>
      <title>Building a Reusable Table Component in Angular</title>
      <dc:creator>Kapil Kumar</dc:creator>
      <pubDate>Sat, 10 May 2025 13:05:19 +0000</pubDate>
      <link>https://dev.to/kapilkumar0037/building-a-reusable-table-component-in-angular-2c7a</link>
      <guid>https://dev.to/kapilkumar0037/building-a-reusable-table-component-in-angular-2c7a</guid>
      <description>&lt;p&gt;In this article, we'll create a flexible and reusable table component in Angular that supports dynamic columns, data binding, and custom actions. Table will support sorting, filtering and can be extended to support other features. Let's break it down step by step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What will we do in this article?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic Table Structure without Actions&lt;/li&gt;
&lt;li&gt;Extend component to support actions&lt;/li&gt;
&lt;li&gt;Enable component to enable/disable actions based on table data row&lt;/li&gt;
&lt;li&gt;Extend component to support sorting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we begin, ensure you have an Angular project set up. If not, follow these commands to create a new Angular project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @angular/cli
ng new my-app
cd my-app
ng serve --open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once your Angular application is set up, you’re ready to proceed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1. Basic Table Structure without Actions
&lt;/h2&gt;

&lt;p&gt;Let's start with creating a basic table structure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. First, define the interfaces&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface IColumnDef&amp;lt;T&amp;gt; {
    headerText: string;     // Column header text
    field?: keyof T;       // Property name from data object
}

export interface IUser {    // Sample data interface
    name: string;
    email: string;
    role: string;
    status: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create column definitions in constants file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { IColumnDef, IUser } from '../models/general.models';

export const COLUMN_DEFINITIONS: IColumnDef&amp;lt;IUser&amp;gt;[] = [
    { headerText: 'Name', field: 'name' },
    { headerText: 'Email', field: 'email' },
    { headerText: 'Role', field: 'role' }
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we have defined field property in IColumnDef as keyOf T, it will give an error while defining column definitions in case field property is not from data object, in this case it's IUser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create and use the Table Component
&lt;/h2&gt;

&lt;p&gt;Generate a new table component:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ng generate component components/table&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Define the Component Class (table.component.ts):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, input, output } from '@angular/core';

@Component({
  selector: 'app-table',
  standalone: true,
  imports: [],
  templateUrl: './table.component.html',
  styleUrl: './table.component.scss'
})
export class TableComponent&amp;lt;T&amp;gt; {
  // Input signals for columns and data
  columns = input&amp;lt;IColumnDef&amp;lt;T&amp;gt;[]&amp;gt;([]);
  tableData = input&amp;lt;T[]&amp;gt;([]);

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Define basic table component HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table class="table"&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
                &amp;lt;th scope="col"&amp;gt;{{col.headerText}}&amp;lt;/th&amp;gt;
            }
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
        @if(tableData().length &amp;gt;= 0){
            @for(data of tableData(); track data){
                &amp;lt;tr&amp;gt;
                    @for(col of columns(); track col){
                        @if(col.field){
                            &amp;lt;td&amp;gt;{{data[col.field]}}&amp;lt;/td&amp;gt;
                        }
                    }
                &amp;lt;/tr&amp;gt;
            }
        }
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the table component, Ex. using in app.component.ts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add app-table to HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;app-table [columns]="columns" [tableData]="tableData"&amp;gt;&amp;lt;/app-table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Define columns and Data in .ts file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; columns= COLUMN_DEFINITIONS;
  tableData:IUser[] = [
    {name: 'Kapil', email:'kapilkumar0037@gmail.com', role:'admin', status:'active'},
    {name: 'Kapil1', email:'kapilkumar0038@gmail.com', role:'admin', status:'active'},

];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. basic table is ready with 3 columns.&lt;/p&gt;

&lt;p&gt;Now display status column as well in the table, to do that we just need to add one more column in column definitions and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { IColumnDef, IUser } from '../models/general.models';

export const COLUMN_DEFINITIONS: IColumnDef&amp;lt;IUser&amp;gt;[] = [
    { headerText: 'Name', field: 'name' },
    { headerText: 'Email', field: 'email' },
    { headerText: 'Role', field: 'role' },
    { headerText: 'Status', field: 'status' }
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As status is already there in data, it will be displayed in the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvg06w7ky3q60ltumvkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvg06w7ky3q60ltumvkf.png" alt="Basic table" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Step: Add actions to the table
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Update IColumnDef interface&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface IColumnDef&amp;lt;T&amp;gt; {
    headerText: string;
    field?: keyof T;
    columnType?: string;
    actions?: IActions&amp;lt;T&amp;gt;[];
}

export interface IActions&amp;lt;T&amp;gt; {
    label: string;
    icon: string;
    tooltip: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Update COLUMNN Definitions constants&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { IColumnDef, IUser } from "../models/general.models";

export const COLUMN_DEFINITIONS: IColumnDef&amp;lt;IUser&amp;gt;[] = [
    {
        headerText: "Name",
        field: "name",
        sortable: true
    },
    {
        headerText: "Email",
        field: "email"
    },
    {
        headerText: "Role",
        field: "role"
    },
    {
        headerText: "Status",
        field: "status"
    },
    {
        headerText: "Action",
        columnType: "action",
        actions: [
            {
                label: "Edit",
                icon: "pi pi-pencil",
                tooltip: "Edit",
            },
            {
                label: "Delete",
                icon: "pi pi-trash",
                tooltip: "Delete",
            }
        ]
    },
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Update table component .ts file to handle action click&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; actionClickEmit = output&amp;lt;{action: IActions&amp;lt;T&amp;gt;, rowData: T}&amp;gt;();

  actionClick(action: IActions&amp;lt;T&amp;gt;, rowData: T) {
    this.actionClickEmit.emit({action, rowData});
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Update table component .html file to display actions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table class="table"&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
            &amp;lt;th scope="col"&amp;gt;{{col.headerText}}&amp;lt;/th&amp;gt;
            }
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
        @if(tableData().length &amp;gt;= 0){
        @for(data of tableData(); track data){
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
            @if(col.field){
            &amp;lt;td&amp;gt;{{data[col.field]}}&amp;lt;/td&amp;gt;
            } @else if(col.columnType == 'action'){
            &amp;lt;td&amp;gt;
                @for(action of col.actions; track action){
                &amp;lt;button type="button" class="btn btn-primary me-2"
                    (click)="actionClick(action, data)"&amp;gt;{{action.label}}&amp;lt;/button&amp;gt;
                }
            &amp;lt;/td&amp;gt;
            }
            }
        &amp;lt;/tr&amp;gt;
        }
        }


    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it, Edit and Delete actions added to the table, and it will emit the output events on click&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr8zbfv132cbjhrq77rl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr8zbfv132cbjhrq77rl.png" alt="Table with actions" width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable/Disable actions based on table data
&lt;/h2&gt;

&lt;p&gt;Ex. The Requirement is to disable Edit if status is not active and disable the delete button if role is admin&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit the IActions interface to have a disabled functions
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface IActions&amp;lt;T&amp;gt; {
    label: string;
    icon: string;
    tooltip: string;
    disabled?: (data: T) =&amp;gt; boolean;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Add the button disabling logic to Column definitions in the constants file&lt;/strong&gt;&lt;br&gt;
Updated actions in column definitions&lt;br&gt;
 &lt;strong&gt;disabled: (data: IUser) =&amp;gt; data.status=== "inactive"&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;disabled: (data: IUser) =&amp;gt; data.role === "admin"&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const COLUMN_DEFINITIONS: IColumnDef&amp;lt;IUser&amp;gt;[] = [
    {
        headerText: "Name",
        field: "name",
        sortable: true
    },
    {
        headerText: "Email",
        field: "email"
    },
    {
        headerText: "Role",
        field: "role"
    },
    {
        headerText: "Status",
        field: "status"
    },
    {
        headerText: "Action",
        columnType: "action",
        actions: [
            {
                label: "Edit",
                icon: "pi pi-pencil",
                tooltip: "Edit",
                disabled: (data: IUser) =&amp;gt; data.status=== "inactive"
            },
            {
                label: "Delete",
                icon: "pi pi-trash",
                tooltip: "Delete",
                disabled: (data: IUser) =&amp;gt; data.role === "admin"
            }
        ]
    },
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Update the table component HTML to call the disabled function&lt;/strong&gt;&lt;br&gt;
disable login added to button&lt;br&gt;
[disabled]="action?.disabled(data)"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table class="table"&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
            &amp;lt;th scope="col"&amp;gt;{{col.headerText}}&amp;lt;/th&amp;gt;
            }
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
        @if(tableData().length &amp;gt;= 0){
        @for(data of tableData(); track data){
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
            @if(col.field){
            &amp;lt;td&amp;gt;{{data[col.field]}}&amp;lt;/td&amp;gt;
            } @else if(col.columnType == 'action'){
            &amp;lt;td&amp;gt;
                @for(action of col.actions; track action){
                &amp;lt;button [disabled]="action?.disabled(data)" type="button" class="btn btn-primary me-2"
                    (click)="actionClick(action, data)"&amp;gt;{{action.label}}&amp;lt;/button&amp;gt;
                }
            &amp;lt;/td&amp;gt;
            }
            }
        &amp;lt;/tr&amp;gt;
        }
        }
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update user data in app component to have one inactive record
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  tableData:IUser[] = [
    {name: 'Kapil', email:'kapilkumar0037@gmail.com', role:'user', status:'inactive'},
    {name: 'Kapil1', email:'kapilkumar0038@gmail.com', role:'admin', status:'active'},

];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwibqs0nb0g3i77d03bfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwibqs0nb0g3i77d03bfl.png" alt="Table with disabled actions" width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting the table
&lt;/h2&gt;

&lt;p&gt;Now it's time to add the sorting logic, table component should allow sorting for one or more columns depends on configuration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Add sortable properties to our IColumnDef interface&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface IColumnDef&amp;lt;T&amp;gt; {
    headerText: string;
    field?: keyof T;    
    columnType?: string;
    actions?: IActions&amp;lt;T&amp;gt;[];
    sortable?: boolean;
    sortDirection?: 'asc' | 'desc' | '';
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Update column definitions and define sortable columns&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const COLUMN_DEFINITIONS: IColumnDef&amp;lt;IUser&amp;gt;[] = [
    {
        headerText: "Name",
        field: "name",
        sortable: true,
        sortDirection: "asc"
    },
    {
        headerText: "Email",
        field: "email"
    },
    {
        headerText: "Role",
        field: "role",
        sortable: true,
        sortDirection: ""
    },
    {
        headerText: "Status",
        field: "status"
    },
    {
        headerText: "Action",
        columnType: "action",
        actions: [
            {
                label: "Edit",
                icon: "pi pi-pencil",
                tooltip: "Edit",
                disabled: (data: IUser) =&amp;gt; data.status=== "inactive"
            },
            {
                label: "Delete",
                icon: "pi pi-trash",
                tooltip: "Delete",
                disabled: (data: IUser) =&amp;gt; data.role === "admin"
            }
        ]
    },
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;3. Add sorting logic to table component *&lt;/em&gt;&lt;br&gt;
As we using signal input, we can not update the same input after sorting. So adding a new signal to keep sorted data&lt;br&gt;
Our component with sorting will be having below code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, computed, effect, input, output, signal } from '@angular/core';
import { IActions, IColumnDef } from '../../models/general.models';

@Component({
  selector: 'app-table',
  standalone: true,
  imports: [],
  templateUrl: './table.component.html',
  styleUrl: './table.component.scss'
})
export class TableComponent&amp;lt;T&amp;gt; {
  columns = input&amp;lt;IColumnDef&amp;lt;T&amp;gt;[]&amp;gt;([]);
  tableData = input&amp;lt;T[]&amp;gt;([]);
  actionClickEmit = output&amp;lt;{action: IActions&amp;lt;T&amp;gt;, rowData: T}&amp;gt;();

  actionClick(action: IActions&amp;lt;T&amp;gt;, rowData: T) {
    this.actionClickEmit.emit({action, rowData});
  }

  // Internal signals
  sortedData = signal&amp;lt;T[]&amp;gt;([]);

  constructor() {
    // Initialize sortedData when tableData changes
    effect(() =&amp;gt; {
      this.sortedData.set(this.tableData());
    }, { allowSignalWrites: true });
  }

  sort(column: IColumnDef&amp;lt;T&amp;gt;) {
    if (!column.sortable || !column.field) return;

    // Reset other columns
    this.columns().forEach(col =&amp;gt; {
      if (col !== column &amp;amp;&amp;amp; col.sortDirection !== undefined) col.sortDirection = '';
    });

    // Toggle sort direction
    column.sortDirection = column.sortDirection === 'asc' ? 'desc' : 'asc';

    // Sort data
    const sorted = [...this.sortedData()].sort((a, b) =&amp;gt; {
      const aVal = a[column.field!];
      const bVal = b[column.field!];
      return column.sortDirection === 'asc' ? 
             aVal &amp;gt; bVal ? 1 : -1 :
             aVal &amp;lt; bVal ? 1 : -1;
    });

    this.sortedData.set(sorted);
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update table component .html file to handle sorting
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table class="table"&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
            &amp;lt;th scope="col"  (click)="sort(col)"&amp;gt;
                {{col.headerText}}
                @if(col.sortDirection === 'asc'){↑}
                @if(col.sortDirection === 'desc'){↓}
                @if(col.sortDirection === ''){↓↑}
            &amp;lt;/th&amp;gt;
            }
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
        @if(sortedData().length &amp;gt;= 0){
        @for(data of sortedData(); track data){
        &amp;lt;tr&amp;gt;
            @for(col of columns(); track col){
            @if(col.field){
            &amp;lt;td&amp;gt;{{data[col.field]}}&amp;lt;/td&amp;gt;
            } @else if(col.columnType == 'action'){
            &amp;lt;td&amp;gt;
                @for(action of col.actions; track action){
                &amp;lt;button [disabled]="action?.disabled(data)" type="button" class="btn btn-primary me-2"
                    (click)="actionClick(action, data)"&amp;gt;{{action.label}}&amp;lt;/button&amp;gt;
                }
            &amp;lt;/td&amp;gt;
            }
            }
        &amp;lt;/tr&amp;gt;
        }
        }
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it, sorting will work for all the columns now. currently in column definitions it is defined for Name and Role. if we need it for status column as well need to update column definition for status column as below and it will work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
        headerText: "Status",
        field: "status",
        sortable: true,
        sortDirection: ""
    },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xa26n7m5rw1pfyyjwuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xa26n7m5rw1pfyyjwuj.png" alt="table with sorting" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generic Typing: The table component uses generics () to ensure type safety for different data structures&lt;/li&gt;
&lt;li&gt;Dynamic Columns: Columns are configured through the columns input property&lt;/li&gt;
&lt;li&gt;Action Buttons: Supports custom action buttons with disable conditions&lt;/li&gt;
&lt;li&gt;Signal-based Inputs/Outputs: Uses Angular's new signals for reactive data handling&lt;/li&gt;
&lt;li&gt;Sorting based on configuration&lt;/li&gt;
&lt;li&gt;Flexible Structure: Easy to extend with additional features like sorting, filtering, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Github for complete code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/kapilkumar0037/ngx-table-control" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Enhancements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Implement filtering&lt;/li&gt;
&lt;li&gt;Add pagination&lt;/li&gt;
&lt;li&gt;Support for custom cell templates&lt;/li&gt;
&lt;li&gt;Add loading state&lt;/li&gt;
&lt;li&gt;Responsive design&lt;/li&gt;
&lt;li&gt;Custom styling options&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This reusable table component provides a solid foundation for displaying tabular data in Angular applications. It's type-safe, flexible, and can be easily extended with additional features as needed.&lt;/p&gt;

&lt;p&gt;Remember to add appropriate styling and consider adding features like filtering, and pagination based on your specific needs.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
