Home > Back-end >  Using NumeralJS, how can I determine the format based on whether a number is thousands or millions
Using NumeralJS, how can I determine the format based on whether a number is thousands or millions

Time:06-25

My header pretty much sums it up, in my application Im formatting a value only when the value is greater than 6 digits. When the value is thousands, e.g. 210,500, I want to display it as 210.5k, if the value is in the millions, e.g. 2,120,000, I want to display it as 2.12m. Currently the format string ('0,0.[00]a') will display both of these numbers to both decimal place(s), but I'd like that to be determined based on the whether or not the value is thousands or millions

Is the best way to figure this out to loop through the value until a decimal is reached and then determine the formatting based on that number? I have tried using the Custom Format object but am having a hard time understanding what's happening under the hood.

This value is displayed on a card and has to be formatted when there are 6 or more digits in the number. Formatting should be 1 decimal place for values in the thousands, and 2 decimal places shown for values in the millions (or greater)

Desired inputs and outputs:

210500 --> 210.5k
2120000 --> 2.12m
67500.89 --> 6.7k
6750000 --> 6.75m
16.75 --> 16.75
67530.85 --> 67.5k 
675 --> 675
6700.05 --> 6700
2522.25 --> 2522
function formatValue(value: string | number, shorthandFormat: boolean = true, shorthandLength: number = 6) {
    if (value === undefined || value === null) return '?';

    let valueString = value.toString();

    if (valueString.trim() === '') return '';

    if (shorthandFormat) {
        if (!shorthandLength || shorthandLength < 0) {
            shorthandLength = 6;
        }

        if (valueString.length <= shorthandLength) {
            shorthandFormat = false;
        }
    }

    let numeralValue = numeral(value)

    let formatter = shorthandFormat ? '0,0.[0]a' : '0,0.[00]';

    let formattedValue = numeralValue.format(formatter);
    
    return formattedValue;
}

Runnable snippet:

function formatValue(value, shorthandFormat = true, shorthandLength = 6) {
  if (value === undefined || value === null) return '?';

  let valueString = value.toString();

  if (valueString.trim() === '') return '';

  if (shorthandFormat) {
    if (!shorthandLength || shorthandLength < 0) {
      shorthandLength = 6;
    }

    if (valueString.length <= shorthandLength) {
      shorthandFormat = false;
    }
  }

  let numeralValue = numeral(value)

  let formatter = shorthandFormat ? '0,0.[0]a' : '0,0.[00]';

  let formattedValue = numeralValue.format(formatter);

  return formattedValue;
}

// 210,500, I want to display it as 210.5k, if the value is in the millions, e.g. 2,120,000, I want to display it as 2.12m
console.log(formatValue(210500))
console.log(formatValue(2120000))
console.log(formatValue(675000))
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>

CodePudding user response:

Here is code example from a number shorthand formatter I built awhile ago that does exactly what you want.

function numberIntoString({
  value,
  decimals,
}) {
  value = value.toString().replace(/[^0-9.]/g, "");
  let si = [
    { value: 1e3, symbol: "K" },
    { value: 1e6, symbol: "M" },
    { value: 1e9, symbol: "B" },
    { value: 1e12, symbol: "T" },
  ];
  let i;
  for (i = si.length - 1; i > 0; i--) {
    if (value >= si[i].value) {
      break;
    }
  }
  return (
    (value / si[i].value)
      .toFixed(decimals)
      .replace(/\.0 $|(\.[0-9]*[1-9])0 $/, "$1")   si[i].symbol
  );
}

CodePudding user response:

In this case you will need to use a different format string depending on the size of the original number. It looks like you have the following cases:

  • If the number is under 1000, return the same number in long format but with at most two decimal places.
  • If the number is between 1000-10,000, return the same number in long format with no decimal places.
  • If the number is between 10,000-1,000,000, return the same number in shorthand format, with at most one decimal place.
  • If the number is larger than 1,000,000, return the same number in shorthand format, with at most two decimal places.

For each of these cases you will need a different format string. You can do that by comparing the number to each threshold and setting the format string depending on its size.


function formatValue(value, shorthandFormat = true, shorthandLength = 5) {
  if (value === undefined || value === null) return '?';

  let valueString = value.toString();
  if (valueString.trim() === '') return '';

  let numeralValue = numeral(value)

  // Note the format changes depending on how large the value is.
  let formatter = "0[.][00]" // Default formatter: returns the same number with at most, two decimals.
  if (value > 1000) formatter = "0" // Over 1000: remove any decimal part.
  if (value > 10000) formatter = "0.[0]a" // Over 10000: use shorthand with at most, one decimal.
  if (value > 1000000) formatter = "0.[00]a" // Over 1000000: use shorthand with at most, two decimals.

  let formattedValue = numeralValue.format(formatter);

  return formattedValue;
}

const tests = [
  // Small numbers contain at most, two decimals.
  [0, "0"],
  [1, "1"],
  [1.1, "1.1"],
  [1.11, "1.11"],
  [1.115, "1.12"],
  [11.1, "11.1"],
  [11.11, "11.11"],
  [16.75, "16.75"],
  [675, "675"],
  [675.5, "675.5"],
  [675.55, "675.55"],
  
  // Numbers between one-thousand and ten-thousand may not contain decimals.
  [6700.05, "6700"],
  [2522.25, "2522"],
  [6000, "6000"],
 
  // Numbers between ten-thousand and one-million should use shorthand, with at most one decimal.
  [67500.89, "67.5k"],
  [67530.85, "67.5k"],
  [210500, "210.5k"],
  [210000, "210k"],
  
  // Numbers greater than one-million should use shortand, with at most two decimals.
  [2120000, "2.12m"],
  [6750000, "6.75m"],  
  [2000000, "2m"],
  [2100000, "2.1m"],
  [2010000, "2.01m"],
  [2001000, "2m"],
]

tests.forEach(([input, output]) => console.log(`${formatValue(input) === output ? "PASS" : "FAIL"}: ${input} --> ${formatValue(input)}. Expected: ${output}`));
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>

Note: The test for number 67500.89 was changed to expect 67.5k as the result, since 6.7k seemed to be a typo.

  • Related