-1

I am working on an angular app. I have few number which I need to display. Those numbers can be like 1234567.87876868. While displaying this number I need to show in format like 12.9k and my code to make number in this form is

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

@Pipe({
    name: 'number'
})
export class numberPipe implements PipeTransform {

    transform(number: number, args?: any): any {
        if (isNaN(number)) return 0; // will only work value is a number
        if (number === null) return 0;
        if (number === 0) return 0;
        let abs = Math.abs(number);
        const rounder = Math.pow(10, 1);
        const isNegative = number < 0; // will also work for Negetive numbers
        let key = '';

        const powers = [
            {key: 'Q', value: Math.pow(10, 15)},
            {key: 'T', value: Math.pow(10, 12)},
            {key: 'B', value: Math.pow(10, 9)},
            {key: 'M', value: Math.pow(10, 5)},
            {key: 'K', value: 1000}
        ];

        for (let i = 0; i < powers.length; i++) {
            let reduced = abs / powers[i].value;
            reduced = Math.round(reduced * rounder) / rounder;
            if (reduced >= 1) {
                abs = reduced;
                key = powers[i].key;
                break;
            }
        }
        return (isNegative ? '-' : '') + abs + key;
    }
}

in html <div>{{ mynumber | number}}<div> Now that problem with this is If number is less that 1000 it shows original number and which shows like this 345.4354564 which does not look good on screen. So I need to use number pipe( number: '1.2-2'). But when I use number pipe with my custom pipe it doesnot work. It says '12.4K is not a number for pipe Decimalpipe'. How can I handle both the scenarios?

R. Richards
  • 24,603
  • 10
  • 64
  • 64
julie
  • 35
  • 6

2 Answers2

0

I had the same problem in the past and the best I found was this solution using Math.log.

@Pipe({
  name: 'number',
})
export class NumberPipe implements PipeTransform {
  transform(input: number, args?: any): string | number | null {
    let exp: number;
    const suffixes = ['K', 'M', 'B', 'T', 'Q', 'E'];

    if (Number.isNaN(input)) {
      return null;
    }

    if (Math.abs(input) < 1000) {
      return input;
    }

    exp = Math.floor(Math.log(input) / Math.log(1000));

    return (input / Math.pow(1000, exp)).toFixed(args) + suffixes[exp - 1];
  }
}

PS: I am sure that I found it somewhere in stack overflow, but I couldn't find the original answer :(

StPaulis
  • 2,844
  • 1
  • 14
  • 24
0

If anyone stumbles upon this: the proposed solution is extremely imperformant.

The bigger the number the longer these Math functions will take to calculate. If you don't believe that, just time them yourself with a simple console like this

  console.time('algo');
  for (let i = 0; i < 100_000_000; i++) {
    shortenWithMath(i);
  }
  console.timeEnd('algo');

it took almost 2.5x as long as simply chaining several boolean checks like this

export const shortenNumber = (val: number) => {
  switch (true) {
    case val > 1_000_000_000_000_000_000_000_000:
      return `${Math.round(
        val / 1_000_000_000_000_000_000_000_000
      )} septillion`;
    case val > 1_000_000_000_000_000_000_000:
      return `${Math.round(val / 1_000_000_000_000_000_000_000)} sextillion`;
    case val > 1_000_000_000_000_000_000:
      return `${Math.round(val / 1_000_000_000_000_000_000)} quintillion`;
    case val > 1_000_000_000_000_000:
      return `${Math.round(val / 1_000_000_000_000_000)} quadrillion`;
    case val > 1_000_000_000_000:
      return `${Math.round(val / 1_000_000_000_000)} trillion`;
    case val > 1_000_000_000:
      return `${Math.round(val / 1_000_000_000)} billion`;
    case val > 1_000_000:
      return `${Math.round(val / 1_000_000)} million`;
    case val > 1_000:
      return `${Math.round(val / 1_000)} thousand`;
    default:
      return val.toString();
  }
};

Not saying that these boolean checks are the best solution, but it sure as hell beats doing Math.floor, Math.log, Math.log, Math.pow together just to determine the numbers exponent.

wohlben
  • 31
  • 2