Building Reusable Components in Angular 2: A Step-by-Step Guide

I have implemented a feature in my component where a table can be sorted by clicking on the <th></th> tags. When a user clicks on a th tag, the data is sorted either in ascending (ASC) or descending (DESC) order.

In my component, I have set up the click event and defined the variables as follows:

public sort_by = "name";
public sort_order = "asc";

sortTableBy(sort_by:string){
    if(sort_by === this.sort_by){
        this.sort_order = (this.sort_order === 'asc' ? 'desc' : 'asc');
    }else{
        this.sort_order = "asc";
        this.sort_by = sort_by;
    }
    this.updateData();
}

Below is the template HTML code:

<th>
    <div (click)="sortTableBy('name')">
        <span>User Name</span>
        <i *ngIf="sort_by == 'name' && sort_order == 'desc'" class="fa fa-sort-up"></i>
        <i *ngIf="sort_by == 'name' && sort_order == 'asc'" class="fa fa-sort-down"></i>
    </div>
</th>

Since I plan to use this table sorting functionality multiple times, I would like to abstract it into a reusable component that looks something like this:

<th>
    <sortable sortBy="name" value="User Name"></sortable>
</th>

I am not sure how to create such a component and establish communication between components. Any help would be appreciated!

Answer №1

If you want to implement a sortable header component, you can create a new component called "header-sortable" and use it in the parent component like this:

  <header-sortable [name]="'User Name'" [prop]="'name'" 
     [sortBy]="sortBy" (sort)="onSort($event)"></header-sortable>

Below is an example of how the header-sortable component could be structured:

@Component({
  selector:'header-sortable',
  template: 
  `
   <th (click)="sortTableBy()" style="cursor:pointer;">
    <div>
        <span>{{name}}</span>
        <i *ngIf="sortBy == prop && sort_order == 'desc'" class="fa fa-sort-up"></i>
        <i *ngIf="sortBy == prop && sort_order == 'asc'" class="fa fa-sort-down"></i>
    </div>
</th>
`
})
export class HeaderSortable {
  @Input() sortBy: string;
  @Input() name: string;
  @Input() prop: string;
  @Output() sort = new EventEmitter<any>();

  sortTableBy() {
    let dir;
    if( this.sortBy == this.prop) {
       dir = this.sortBy === 'desc' ? 'asc' : 'desc';
    }
    else {
      dir  = 'desc';
    }
    this.sort.emit({prop, dir})
  }
}

Answer №2

To make the table headers clickable for sorting, you can move the click method to the <th> element like this:

<th (click)="sortTableBy('name')" style="cursor:pointer;">
    <div>
        <span>User Name</span>
        <i *ngIf="sort_by == 'name' && sort_order == 'desc'" class="fa fa-sort-up"></i>
        <i *ngIf="sort_by == 'name' && sort_order == 'asc'" class="fa fa-sort-down"></i>
    </div>
</th>

Note: The added style makes it clear that the user can click on the header.

Additionally, 5 other <th> tags will also have the same click method with different input parameters:

<th (click)="sortTableBy('age')">
<th (click)="sortTableBy('gender')">
...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be causing the "ERROR TypeError: Cannot read property 'length' of undefined" message to occur with a defined array in my code?

Even though I defined and initialized my array twice, I am encountering a runtime error: "ERROR TypeError: Cannot read property 'length' of undefined." I have double-checked the definition of the array in my code, but Angular seems to be playing ...

Experimenting with TypeScript Single File Component to test vue3's computed properties

Currently, I am in the process of creating a test using vitest to validate a computed property within a vue3 component that is implemented with script setup. Let's consider a straightforward component: // simple.vue <script lang="ts" set ...

Troubleshooting Problem with Angular Material 2's Mat-Paginator [Length] Bug

Utilizing the mat-paginator component for a table, I am facing an issue where I am unable to dynamically set the length of the paginator based on the total number of results retrieved from an API call. Despite trying various methods like setting it in the ...

How to Add RouterModule to an Angular 10 Library without Ivy

I am developing a custom Angular 10 Library to be shared on a private NPM repository. I followed the instructions from Angular.io and used ng new my-workspace --create-application=false and ng generate library my-library with Angular CLI. In one of the co ...

I am having trouble getting the bs-stepper to function properly within my Angular project

I am currently facing issues with the bs-stepper module in my Angular code. It is not functioning as expected and is throwing errors. Here is a snippet of my code: export class FileUploadProcessComponent implements OnInit { import Stepper from 'b ...

Angular attribute directive encountered an error during production build, where it was expected to receive 1 argument but instead received

I have been working on a large-scale application that has been developed by multiple teams over an extended period. A frontend developer from another location included a significant amount of repetitive imperative code, utilizing jQuery for DOM manipulati ...

Executing a designated assessment in Protractor

Is there a way to run a specific test scenario in my Angular app? I recently added a new feature in Protractor, created the necessary page and steps, but I already have other features implemented. I am wondering if it is possible to solely test the new f ...

Using TypeScript controllers to inject $scope

Currently, I am in the process of creating my initial typescript controller and encountering a slight challenge in comprehending how to utilize $scope effectively in order to reference elements within various code blocks. Below is the relevant snippet of c ...

ts-node: The colon symbol was not expected in this context

As I work on developing a backend server for my application, I made the decision to switch from using babel-node as the executor to utilizing ts-node. The command defined in my package.json file is: "server": "cd server && ts-node --project tsconf ...

Fetching a collection from Cloud Firestore using Angular and Firebase

I'm looking to figure out how to retrieve lists from cloud firestore. Here is how I upload a list : export interface Data { name: string; address: string; address2: string; pscode: string; ccode: string; name2: string; } constructor(pri ...

Find the distinct values from an array of objects containing varying elements using Typescript

My array contains dynamic elements within objects: [ { "Value1": [ "name", "surname", "age" ], "Value2": [ "name" ...

Challenges with deploying Angular applications and dealing with undefined properties within Angular code

Currently, I have successfully added new products to the database with all the desired properties. However, I am facing errors that are preventing me from deploying the application for production. Fixing these errors causes further issues where I cannot ad ...

When you use npm uninstall, it deletes the package from package.json, but it does not remove it from the node_modules directory

After attempting to uninstall a package using npm uninstall (package_name) -s The package was successfully removed from package.json but remained in the node_modules folder. How can I effectively remove these unused packages from the node_modules folder? ...

The 'Promise<void>' type cannot be assigned to the 'Promise<xxx>' type

Attempting the following transaction in TypeScript resulted in a compile error. The error message stated: Type 'Promise<void>' is not assignable to type 'Promise<transactionArgument>'. However, the function returns a value o ...

How can I assign a specific class to certain elements within an *ngFor loop in Angular?

I have a situation where I am utilizing the *ngFor directive to display table data with the help of *ngFor="let record of records". In this scenario, I am looking to assign a custom CSS class to the 'record' based on specific conditions; for exam ...

SolidJS directives utilizing use:___ result in TypeScript errors when used in JSX

As I work on converting the forms example from JS to TS, I came across a typescript error related to directives in HTML: https://i.sstatic.net/Hl8Pv.png It appears that validate and formSubmit are being recognized as unused variables by typescript, result ...

ng serve generates an error related to node_modules appearing to be empty

Recently, I embarked on my Angular 4 learning journey and took the following steps: Firstly, I installed Node.js (version 8). Then, I executed the command npm install -g @angular/cli Using the CLI, I created a new project called: ng new my-first-app Ho ...

Encountering a Windows 11 issue: npm ERR! errno -4058 with ENOENT bash code

Encountered a troublesome NPM issue suddenly, after taking a brief break from working on my project. Facing the following error with core-js. npm ERR! code ENOENT npm ERR! syscall spawn bash npm ERR! path C:\Users\User1\Documents\projec ...

There was an issue encountered while trying to execute npm install, resulting in the error message: "This is a glitch

I am diving into the world of Angular and Node for the first time. I'm currently attempting to run a project that combines Angular with Neo4j, but encountering some issues along the way. When I initially tried to launch the project as is, after openin ...

What advantages does Angular's Dependency Injection offer for a basic object setup?

The Angular documentation provides an example of injecting a value (configuration object) using @inject in the constructor for scenarios where a class is not being injected. https://angular.io/guide/dependency-injection#non-class-dependencies I managed t ...