Telerik blogs

Learn how to use the orderBy pipe to manipulate data in templates to display them in the format we want.

Angular is a component-based framework that lets us create interactive web frontends for users by composing components together. In addition to components, we can create pipes that let us manipulate data in templates to display them in the format we want.

In this article, we’ll look at how to add an orderBy pipe into our app and use it in our template.

Pipe Basics

We can create our own pipes to transform data in our templates before displaying them.

To create the files for the pipe and register the pipe in our Angular app module, we use the ng g command that comes with Angular CLI.

In this example, we will create a pipe that converts strings to lowercase before displaying them.

To start, we run:

ng generate pipe lowerCase

to create the lowerCase pipe.

This will create the files and register them in the Angular app module so we can make changes to the pipe file and use it right away.

In app.module.ts, we should see something like:

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { LowerCasePipe } from "./lower-case.pipe";

@NgModule({
  declarations: [AppComponent, LowerCasePipe],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

If we see LowerCasePipe in declarations, that means we can use it in our template in components that are registered in AppModule.

We should have the lower-case.pipe.ts file in the app folder after running the command. In it, we write:

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "lowerCase",
})
export class LowerCasePipe implements PipeTransform {
  transform(value: string, ...args: unknown[]): unknown {
    return value.toLowerCase();
  }
}

We added the transform method into the LowerCasePipe class. It implements the PipeTransform TypeScript interface, which requires the transform method to be included.

The transform method takes the value, which is the value passed from the template to the pipe. We set its type to a string since we expect a string argument to be passed in.

It returns the result that we want to render in the template. In this case, we want to display the string in all lowercase. Therefore, we return the lowercase version of value by calling toLowerCase.

Then in app.component.html, we can use the lowerCase pipe we just created.

In app.component.html, we write:

<p>{{ "HELLO WORLD" | lowerCase }}</p>

to render the "HELLO WORLD" string in all lowercase by applying the lowerCase we just created.

We use the name property value in the object we called the Pipe decorator with as the pipe name in the template.

Create a Pipe to Sort Items That Are Displayed in Templates

Pipes can be applied to values other than strings. We can apply pipes to any kind of value.

One kind of thing we commonly do is to order by items in an array before we display them. To do this, we can create a pipe. Pipes can take arguments, so we can sort array items in the way we want before we display the items.

To create a pipe that can sort arrays before we display the items, we use the JavaScript array sort method. The sort method takes a function that compares the two items being iterated through as the arguments. sort makes a copy of the array it called, sorts the copied array, and then returns the sorted copied array.

We can call these two parameters a and b.

For instance, we write:

const sorted = array.sort((a, b) => {
  //...
});

to call sort on the array array with a function that takes items a and b and compares them.

a and b are items in the array array that we are comparing.

If we compare the a and b items and return a number bigger than 0 in the sort callback, then we sort a after b.

If we compare them and return a number less than 0 in the sort callback, then we sort a before b.

And if we return 0 in the sort callback, then we keep the original order of a and b.

For instance, if we write:

const array = [1, 5, 4, 2, 3];
const sorted = array.sort((a, b) => {
  return a - b;
});
console.log(sorted);

Then sorted is [1, 2, 3, 4, 5] since we order a before b if a is less than b.

And if we write:

const array = [1, 5, 4, 2, 3];
const sorted = array.sort((a, b) => {
  return b - a;
});
console.log(sorted);

Then sorted is [5, 4, 3, 2, 1] since we order b before a if b is bigger than a.

And if we write:

const array = [1, 5, 4, 2, 3];
const sorted = array.sort((a, b) => {
  return 0;
});
console.log(sorted);

Then sorted is [1, 5, 4, 2, 3] since we keep the same order as the array.

With this information, we can make a pipe that orders the values we want.

To start, we create the orderBy pipe by running:

ng generate pipe orderBy

Then in app.module.ts, we see something like:

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { OrderByPipe } from "./order-by.pipe";

@NgModule({
  declarations: [AppComponent, OrderByPipe],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

The OrderByPipe is in the array we set as the value of the declarations property, so it’s registered in the AppModule.

The order-by.pipe.ts file should be created. And we can modify that to sort the values we want before displaying them.

Next, we create the Person interface since we want our pipe to sort these objects. To create the person.ts file, we run:

ng generate interface Person

In it, we write:

export interface Person {
  name: string;
  age: number;
}

to add the name and age properties into our TypeScript interface.

Now we can work on our pipe.

In order-by.pipe.ts, we write:

import { Pipe, PipeTransform } from "@angular/core";
import { Person } from "./person";

@Pipe({
  name: "orderBy",
})
export class OrderByPipe implements PipeTransform {
  transform(value: Person[], order: "asc" | "desc" = "asc"): Person[] {
    return value.sort((a, b) => {
      if (order === "asc") {
        return a.age - b.age;
      } else if (order === "desc") {
        return b.age - a.age;
      }
      return 0;
    });
  }
}

to add the transform method.

It takes the value parameter, which is an array of Person objects. Person is the interface we created earlier.

order is an argument for the pipe that lets us specify whether to sort by asc (ascending order) or desc (descending order). In it, we call value.sort with a callback that checks the order direction.

If it’s asc, then we sort by age in ascending order. If it’s desc, then we sort by age in descending order.

Otherwise, we return the array with the same items as value in the same order.

We set the type of value to Person[] so only an array of Person objects is accepted.

order has type "asc" | "desc" with the default value being "asc" so only "asc" or "desc" can be values of order.

And the return type of the transform method is Person[] since sort returns an array with the objects in value sorted. We need the types to avoid TypeScript type errors.

Next, we can add some Person objects in AppComponent and display them in a sorted manner. To do this, we write:

import { Component } from "@angular/core";
import { Person } from "./person";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  persons: Person[] = [
    { name: "Joe", age: 50 },
    { name: "Jane", age: 10 },
    { name: "Mary", age: 30 },
    { name: "Alex", age: 23 },
    { name: "Steve", age: 68 },
    { name: "Paul", age: 91 },
  ];
  orderBy: "asc" | "desc" = "asc";
}

in app.component.ts.

We have an array of Person objects set as the value of the persons instance variable.

Also, we have the orderBy instance variable initially set to "asc".

Then in app.component.html, we write:

<button (click)="orderBy = orderBy === 'asc' ? 'desc' : 'asc'">
  Toggle Sort
</button>
<ul>
  <li *ngFor="let p of persons | orderBy: orderBy">
    {{ p.name }} - {{ p.age }}
  </li>
</ul>

to add a button that lets us toggle the value of orderBy between "asc" and "desc".

And then we render the items in persons after they’re sorted by the orderBy pipe we just created.

The orderBy after the colon is the orderBy instance variable in AppComponent which we set as the argument of the orderBy pipe.

As a result, we should see the items displayed in the list initially sorted by their age values in ascending order. Then when we click Toggle Sort, we see the sort order reversed so the age values are sorted in descending order.

Conclusion

In addition to components, we can create pipes in Angular that let us manipulate data in templates to display them in the format we want.

We can create our own pipe that sorts values in the order we want before we display them by using the array sort method. The sort method makes a copy of the array, sorts it and then returns the sorted array so the original array isn’t affected.


About the Author

John Au-Yeung

John Au-Yeung is a frontend developer with 6+ years of experience. He is an avid blogger (visit his site at https://thewebdev.info/) and the author of Vue.js 3 By Example.

Related Posts

Comments

Comments are disabled in preview mode.