0

I want to put space between number - for example 600000 -> 600 000.

What I've done :

HTML :

  <h2>{{price.spaces(item.price)}}€</h2>

TS :

 spaces(price){
    let p = new String(price);
    if(p.length == 4){
      p.split("", 4);
       p = p[0] + ' ' + p[1]  + p[2]  + p[3];

     }

    if(p.length == 5){
      p.split("", 5);
       p = p[0] + p[1] + ' ' + p[2]  + p[3] + p[4];
     }

 if(p.length == 6){
  p.split("", 6);
   p = p[0] + p[1] + p[2] + ' ' + p[3] + p[4] + p[5];
 }

 //if(p.length == 7){
  //p.split("", 7);
   //p = p[0] + ' ' + p[1] + p[2] + p[3] + ' ' + p[4] + p[5] + p[6];
 //}
 return p;
  }

Expected behavior :

  1. If length 4 - 1 000
  2. If length 5 - 10 000
  3. If lenght 6 - 100 000
  4. If length 7 - 1 000 000

Result of my function :

It counts length normally - for example if 600000 (6 length) , it does if(p.length == 6) part, and after that it does if(p.length == 7), because before in if(p.length == 6) it became 7 with space.

How to make my function better ?

Devla
  • 326
  • 4
  • 19

2 Answers2

2

One option would be to use a regular expression: identify each position in the string such that 3 digits, or 6 digits, or 9 digits, etc later are followed by the end of the string:

const spaces = price => String(price)
  .replace(
    /(?!^)(?=(?:\d{3})+$)/g,
    ' '
  );

for (let i = 1; i < 1e10; i *= 10) {
  console.log(spaces(i));
}

(?!^)(?=(?:\d{3})+$) means:

  • (?!^) - Negative lookahead for ^ - make sure this position is not the start of the string
  • (?=(?:\d{3})+$) - Positive lookahead for:
    • (?:\d{3})+ - Numeric characters repeated a multiple of 3 times
    • $ - Followed by the end of the string
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

I created a custom Angular pipe to manage and display such numbers with space.

The aim is to have a generic method that is able to transform one Input (a number), and transform it into what I want (a formatted number). Angular pipes are made and great to do that.

Here is a sample, you can inspire yourself from it and only take what you want.

I used an Euclidean division to manage any length of a number.

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

@Pipe({
  name: 'formatNumber'
})
export class FormatNumberPipe implements PipeTransform {

  transform(value: any): string {
    if (value) {
      // Gets the value as a string
      if (typeof value !== 'string') {
        value = value.toString();
      }
      // Delete existing spaces
      while ((value as string).indexOf(' ') !== -1) {
        value = (value as string).replace(' ', '');
      }

      // Manage decimal values
      let integerPart: string = value;
      if (value.indexOf('.') !== -1) {
        integerPart = value.slice(0, value.indexOf('.'));
      }
      if (value.indexOf(',') !== -1) {
        integerPart = value.slice(0, value.indexOf(','));
      }

      let firstSlice = true;
      const arrayResults: Array<string> = [];
      let finalResult = '';

      const divisor = 3;
      const dividend: number = integerPart.length;
      let remainder = dividend % divisor;
      let quotient = (dividend + remainder) / divisor;

      if (dividend >= 3) {
        do {
          if (firstSlice && remainder > 0) {
            // Manage numbers with remainders
            firstSlice = false;
            arrayResults.push(integerPart.slice(0, remainder));
          } else {
            // Slice each part of the number to an array
            firstSlice = false;
            arrayResults.push(integerPart.slice(remainder, remainder + divisor));
            remainder = remainder + divisor;
            quotient--;
          }
          // Continue dividing the number while there are values
        } while (quotient >= 1);

        // Concats the sliced parts to build the final number
        arrayResults.forEach(part => {
          finalResult += `${part} `;
        });
        // Delete any trailing whitespace
        finalResult = finalResult.trim();
        return finalResult;
      } else {
        return value;
      }
    }
    return value;
  }
}

Once the pipe is done, you can use it however you want in your app :

Either in your template directly :

<input [ngModel]="value | formatNumber" (ngModelChange)="value = $event">

Or in your code directly using Dependency Injection of the pipe :

this.sommeFormat.totalValue = this.formatNumber.transform(this.somme.totalValue);

Here is the official documentation about Angular pipes : https://angular.io/guide/pipes

Alex Beugnet
  • 4,003
  • 4
  • 23
  • 40
  • Hi @Alex, i'm trying to use your pipe, when i try to persist data in backend, there is an error that the input is not a valid double, is there a way to solve this – Bilal Dekar Aug 09 '20 at 14:15
  • 1
    Hi, since the output is a string, you might need to transform it back into a double before sending it to the backend. You can do that easily by slicing the spaces and then converting the string into a double somehow. Your backend should work correctly that way. Or you can also manage it differently and only display a transformed value, and then send to your backend the initial non-transformed value instead. – Alex Beugnet Aug 10 '20 at 01:19
  • thank you @Alex , i transformed the input to a double before sending it to persist and it worked – Bilal Dekar Aug 10 '20 at 09:16
  • there is something else when i enter a number with a comma, it is persisted perfectly, but the part after the comma is not displayed in the input – Bilal Dekar Aug 10 '20 at 09:17
  • i can ask a question if you want to. – Bilal Dekar Aug 10 '20 at 09:35
  • 1
    Sounds like an HTML issue, maybe the input size is not correct ? – Alex Beugnet Aug 11 '20 at 21:18
  • i figured it out, there was an issue with comma part, the format is not taking in consideration the after comma part, so i added value.slice(value.indexOf('.') + 1, value.length); to the final result – Bilal Dekar Aug 12 '20 at 11:52