Formatting Numbers to Words with Commas Using Angular Pipes
Tags: webdev, javascript, angular, typescript
Published: 2023-07-02 16:11:28

**Introduction:**
In Angular applications, we often encounter scenarios where we need to format numbers as words. Additionally, adding commas to large numbers enhances readability. In this blog post, we will explore how to create an Angular pipe that converts numbers to words and adds commas at the appropriate places.

**Step 1: Creating the Angular Pipe**
To get started, let's create an Angular pipe called _**numberToWords**_. This pipe will be responsible for transforming the input number into its corresponding words with commas.
```
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'numberToWords'
})
export class NumberToWordsPipe implements PipeTransform {
  transform(value: any): string {
    if (value && this.isInteger(value)) {
      return this.numToWordsWithCommas(value);
    }
    return value;
  }

  // Helper methods for number to words conversion and comma insertion
  // ...
}
```
In the code snippet above, we define the _**NumberToWordsPipe **_class and implement the _**PipeTransform**_ interface. This interface requires us to define a transform method, which is the main transformation logic for the pipe.

The transform method takes the input value and checks if it exists and is an integer using the _**isInteger**_ method. If the value is valid, it calls the _**numToWordsWithCommas**_ method to convert the number to words with commas. If the value is not valid, it simply returns the original value.

**Step 2: Implementing the Number to Words Conversion**
To convert a given number into its corresponding words, we need to define helper methods within the _"NumberToWordsPipe"_ class.

First, we implement the **_numToWords_** method, which takes a number and converts it into its corresponding words. The conversion logic involves breaking the number into chunks of three digits and converting each chunk to words using arrays of predefined words. Let's look at the code:

```
private numToWords(n: number): string {
    if (n === 0) {
      return 'zero';
    }
// Define arrays of words for numbers less than twenty, tens, and scales
    let lessThanTwenty = ['','one','two','three','four',   'five','six','seven','eight','nine','ten','eleven','twelve', 'thirteen','fourteen','fifteen','sixteen','seventeen', 'eighteen','nineteen'];

    let tens = ['','','twenty','thirty','forty','fifty','sixty',
      'seventy','eighty','ninety'];

    let scales = ['','thousand','million','billion',    'trillion'];

  // Define helper method convertChunk to convert individual chunks to words

    let convertChunk = (num: number): string => {
      let chunkResult = '';

      let hundreds = Math.floor(num / 100);
      num %= 100;

      if (hundreds !== 0) {
        chunkResult += `${lessThanTwenty[hundreds]} hundred`;
      }

      if (num === 0) {
        return chunkResult;
      }

      if (chunkResult !== '') {
        chunkResult += ' and ';
      }

      if (num < 20) {
        chunkResult += lessThanTwenty[num];
      } else {
        let tensDigit = Math.floor(num / 10);
        let onesDigit = num % 10;
        chunkResult += `${tens[tensDigit]}${onesDigit !== 0 ? '-' + lessThanTwenty[onesDigit] : ''}`;
      }

      return chunkResult;
    };
  // Define helper method convertGroup to convert the entire number
    let convertGroup = (num: number, scale: string): string => {
      let groupResult = '';
      let chunkCount = 0;

      while (num > 0) {
        let chunk = num % 1000;
        if (chunk !== 0) {
          let chunkWords = convertChunk(chunk);
          if (chunkCount > 0) {
            groupResult = `${chunkWords} ${scales[chunkCount]} ${groupResult}`;
          } else {
            groupResult = `${chunkWords} ${groupResult}`;
          }
        }
        num = Math.floor(num / 1000);
        chunkCount++;
      }

      return groupResult.trim();
    };

    return convertGroup(n, '');
  }
```

In the _**numToWords**_ method, we define arrays **_lessThanTwenty_**, **_tens_**, and **_scales_** that hold the words for numbers less than twenty, tens, and scales (thousand, million, billion, etc.) respectively. These arrays provide the foundation for converting the number to words.

Next, we define the convertChunk method. This method takes a three-digit chunk of the number and converts it into words. The logic involves breaking the chunk into its hundreds, tens, and ones places, and then combining the corresponding words from the arrays defined earlier.

To convert the entire number, we implement the **_convertGroup_** method. This method takes the original number and divides it into chunks of three digits. It iterates over each chunk, converts it to words using **_convertChunk_**, and appends the corresponding scale (thousand, million, billion, etc.) to each chunk. Finally, it returns the converted number as a string.

**Step 3: Adding Commas to the Result**
To enhance the readability of large numbers, we can add commas at the appropriate places. Let's implement the **_addCommas_** method within the **_NumberToWordsPipe_** class:

```
private addCommas(str: string): string {
    let parts = str.split(' ');
    for (let i = 0; i < parts.length; i++) {
      if (parts[i] === 'and') {
        continue;
      }
      parts[i] = parts[i].replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');

      if (parts[i] === 'thousand' || parts[i] === 'million' || parts[i] === 'billion' || parts[i] === 'trillion') {
        parts[i] = parts[i]+','
      }
    }
    return parts.join(' ');
  }
```
In the _**addCommas**_ method, we split the converted string into an array of individual words using the space delimiter. We iterate over each word and use a regular expression to find any sequence of three digits (excluding the last group) and replace it with the same digits followed by a comma.

We also provide special handling for words like 'thousand','million', 'billion',etc to ensure that a comma is added after them. This step is necessary because they act as  scale in the number-to-words conversion.

Finally, we join the modified array of words back into a string and return it.

**Step 4: Combining the Conversion and Comma Insertion**
To obtain the final result of converting a number to words with commas, we combine the number-to-words conversion and comma insertion logic. We do this in the **_numToWordsWithCommas_** method:
```
private numToWordsWithCommas(n: number): string {
  let result = this.numToWords(n);
  result = this.addCommas(result);

  return result;
}
```
In the _**numToWordsWithCommas**_ method, we first call the _**numToWords**_ method to convert the input number to words. We then pass the resulting string to the _**addCommas**_ method to add commas at the appropriate places. Finally, we return the modified string as the final result.

**Conclusion:**
In this blog post, we have learned how to create an Angular pipe that converts numbers to words and adds commas at the right places. By utilizing the _**NumberToWordsPipe**_ in your Angular applications, you can easily format numbers to enhance readability and provide a better user experience.

Feel free to modify and customize the code as per your specific requirements and use it in your Angular projects. This pipe can be especially useful in applications where numbers need to be displayed in a human-readable format, such as financial or data reporting systems.

You can find the complete code and examples in the accompanying GitHub repository https://github.com/yeanca/custom_pipe

I hope this blog post has been informative and helpful. If you have any questions or feedback, please leave a comment below.

Happy coding