Search code examples
angulartypescriptangular-directive

How to replace dot with comma on input?


I'm trying to use Directive in my Angular App, inside an input box the user must be able to insert only values with three decimal.

The decimal are separated with comma but there could be a case where the user will use dot as separator and in this case i have to replace the dot with the comma on input.

I was trying the following way to archieve it:

@Directive({
  selector: '[appQuantity]',
})
export class QuantityDirective {
  @Input()
  public plu: Plu;

  constructor(private ref: ElementRef) {}

  @HostListener('input', ['$event'])
  public onInput(event: any): void {
    const val = this.ref.nativeElement.value;

    this.ref.nativeElement.value = this.ref.nativeElement.value.replace(/\./g, ','); // here i should replace dot with comma but it's not working
    if (this.plu.um === 'PZ'){ // controls if input is empty i'm setting 1
      if (!val || val <= 0){
        this.ref.nativeElement.value = 1;
      }
    }
    this.plu.qta = parseFloat(this.ref.nativeElement.value); // setting the object quantity to inserted value
  }
}

But it just return NaN value on parseFloat and just set the input to 1...


Solution

  • As per the docs for parseFloat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat

    Return value
    A floating point number parsed from the given string.
    
    Or NaN when the first non-whitespace character cannot be converted to a number.
    

    Parsefloat expects a string 000.00 but because you are replacing the . with a , you are getting NaN.

    I would recommending parsing the number first then converting to your output and only setting once you are happy with the value rather than resetting the same value a few times.

    @Directive({
      selector: '[appQuantity]',
    })
    export class QuantityDirective {
      @Input()
      public plu: Plu;
    
      constructor(private ref: ElementRef) {}
    
      @HostListener('input', ['$event'])
      public onInput(event: any): void {
        // Use `let` instead of rewriting the value constantly (weird side effects on ui if you keep setting the value)
        let val = this.ref.nativeElement.value;
    
        // Convert `,` to `.` to allow for valid parsing
        val = parseFloat( val.replace(/,/g, '.'))
        if (this.plu.um === 'PZ'){ // controls if input is empty i'm setting 1
        // Now that `val` is a number, `<= 0` is valid because it should not be used on strings
          if (!val || val <= 0){
            val = 1;
          }
        }
    
        // Format as needed
        const correctFormat = val.toString().replace(/\./g, ',')
        // Set now
        this.ref.nativeElement.value = correctFormat
        this.plu.qta= correctFormat; // setting the object quantity to inserted value
      }
    }
    
    Just a tip

    If you are concerned about number formats, you could use toLocaleString and other built in number formatters that can handle stuff like currency and language.