a blog for those who code

Thursday, 26 December 2019

Custom Pipes For Everyday Use in Angular


In my previous post Why Pipes are Useful in Angular and How to Create Custom Pipes, we have discussed about how Pipes are useful in Angular and how easy is to create a custom Pipes in Angular.

Just to get a refresher, Pipes are being used whenever we want to perform some logic to transform the data inside our templates. We use a pipe in the Angular template with the | syntax like

{{ myDate | date:'longDate' }}

Understanding Reactive and Template-driven Forms in Angular


In this post, we will be discussing some of the pipes which we can create and use in our application. 

1. Comma Separated Pipe

Say for example, you have a string array and that has to be converted to a comma-separated string every-time you show it to the user. Instead of doing it every-time, what we can do is to create a pipe and that pipe will handle the logic of creating a comma-separated string.

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

@Pipe({
  name: 'commaSeparted'
})
export class CommaSepartedPipe implements PipeTransform {

  transform(val: any): string[] {
    return val.split(',');
  }
}

2. Remove HTML Tag Pipe

Sometimes when we are displaying some text to the user we do not want to show the text with all the HTML tags but we just want to show the contents for that we can use the below pipe :

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

@Pipe({
  name: 'removeHtmlTag'
})
export class RemoveHtmlTagPipe implements PipeTransform {

  transform(val: any): string[] {
    return val.replace(/<[^>]*>/g, '');
  }
}

3. Truncate Text

Sometimes we only want to show a certain number of characters to the user and not the full string. So what we can do is to create a pipe with the parameters like a number of characters, what to be shown after the truncate etc as shown below. In the below pipe if no parameters are given that means I will truncate up to 20 characters and after the truncate, I will show '...'. It can be changed according when you are calling the pipe.

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

@Pipe({
 name: 'truncateText'
})

export class TruncateTextPipe implements PipeTransform {

transform(value: string, args: string[]): string {
    const limit = args.length > 0 ? parseInt(args[0], 10) : 20;
    const trail = args.length > 1 ? args[1] : '...';
    return value.length > limit ? value.substring(0, limit) + trail : value;
   } 
}

Understanding Observable - A key Concept in Angular

4. Time Ago Pipe

This is one of the common scenarios where we want to show how much time has elapsed instead of showing the Date. The code of the time ago pipe is shown as below:


import { Pipe, PipeTransform, NgZone, ChangeDetectorRef, OnDestroy } from '@angular/core';
@Pipe({
    name: 'timeAgo',
    pure: false
})
export class TimeAgoPipe implements PipeTransform, OnDestroy {
    private timer: number;
    constructor(private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone) { }
    transform(value: string) {
        this.removeTimer();
        const d = new Date(value);
        const now = new Date();
        const seconds = Math.round(Math.abs((now.getTime() - d.getTime()) / 1000));
        const timeToUpdate = (Number.isNaN(seconds)) ? 1000 : this.getSecondsUntilUpdate(seconds) * 1000;
        this.timer = this.ngZone.runOutsideAngular(() => {
            if (typeof window !== 'undefined') {
                return window.setTimeout(() => {
                    this.ngZone.run(() => this.changeDetectorRef.markForCheck());
                }, timeToUpdate);
            }
            return null;
        });
        const minutes = Math.round(Math.abs(seconds / 60));
        const hours = Math.round(Math.abs(minutes / 60));
        const days = Math.round(Math.abs(hours / 24));
        const months = Math.round(Math.abs(days / 30.416));
        const years = Math.round(Math.abs(days / 365));
        if (Number.isNaN(seconds)) {
            return '';
        } else if (seconds <= 45) {
            return 'a few seconds ago';
        } else if (seconds <= 90) {
            return 'a minute ago';
        } else if (minutes <= 45) {
            return minutes + ' minutes ago';
        } else if (minutes <= 90) {
            return 'an hour ago';
        } else if (hours <= 22) {
            return hours + ' hours ago';
        } else if (hours <= 36) {
            return 'a day ago';
        } else if (days <= 25) {
            return days + ' days ago';
        } else if (days <= 45) {
            return 'a month ago';
        } else if (days <= 345) {
            return months + ' months ago';
        } else if (days <= 545) {
            return 'a year ago';
        } else { // (days > 545)
            return years + ' years ago';
        }
    }
    ngOnDestroy(): void {
        this.removeTimer();
    }
    private removeTimer() {
        if (this.timer) {
            window.clearTimeout(this.timer);
            this.timer = null;
        }
    }
    private getSecondsUntilUpdate(seconds: number) {
        const min = 60;
        const hr = min * 60;
        const day = hr * 24;
        if (seconds < min) { // less than 1 min, update every 2 secs
            return 2;
        } else if (seconds < hr) { // less than an hour, update every 30 secs
            return 30;
        } else if (seconds < day) { // less then a day, update every 5 mins
            return 300;
        } else { // update every hour
            return 3600;
        }
    }
}

These pipes can be useful for your day to day activity or you can create your own pipe as per your need.

Career Category (English)728x90

No comments:

Post a comment