3

I am trying to create input field for percentage. And I am using PercentPipe to display percentage. However I am getting error when I input some number

<input required type="number" min="0" max="100"
   [ngModel]="viewModel.value | percent:'1.2'" id="limitPercentage"
   (ngModelChange)="viewModel.value=$event"
   [formControl]="viewModel.control"
   name="limitPercentage" class="form-control"
   (showErrorMessage)="showErrorMessage($event)"
/>

Error in console:

 ERROR Error: InvalidPipeArgument: '0% is not a number' for pipe 'PercentPipe'
  • 1
    You can't use pipes like that. Here's a good thread about why you're getting that error along with some workarounds: https://stackoverflow.com/a/39643180/9901630 – nll_ptr Sep 18 '19 at 13:28

2 Answers2

2

I found that using the percentpipe was no good for inputs.

I am storing the VAT(Tax rate) rate as a float in my db, but I wanted to show this as a percentage on the product edit form. I suspect it would be confusing otherwise.

So the percentpipe isn't a great fit as it transforms numbers into text strings. Now I guess I could have transformed the number back on save, but I wanted to use the number spinner in the input and to handle the validation.

So this is what I ended up with...

1) in the form I have a input

    <mat-form-field class="col-12 col-sm-6 col-md-2" >
      <mat-label>VAT rate </mat-label>
      <input type="number" matInput formControlName="prodVatRate" 
             min="0" max="100" pattern ="^0?[0-9]?[0-9]$|^(100)$">
          <span matPrefix>%&nbsp;</span>
        </mat-form-field>

2) in the component I have a couple of simple functions to handle the transform.

toPercent(floatingNumber: number): number  {
   return floatingNumber * 100;
}

toDecimal(integerNumber: number): number {
    return integerNumber / 100;
}

they are so simple you might want to add them inline.

3) I'm using reactive forms so at page load I "patchValue" the form with the http response...

this.productForm.patchValue({
  prodVatRate: this.toPercent(this.product.prodVatRate),
  ... more data inserted here
});

4) and finally in my form save / submit, I transform the data back to a float.

    const p = { ...this.product, ...this.productForm.value };

    // change the Vat rate back to a floating point number
    p.prodVatRate = this.toDecimal(p.prodVatRate);

I hope it helps you out.

Darren Street
  • 1,652
  • 17
  • 21
  • If not in loading phase to patch value, you can add `(focusout)` method. It means that move the step 3 into `(focusout)` method. – Bigeyes Aug 03 '21 at 13:03
-1

Do it with a method in your component.

First import and add the pipe in the constructor, also create a transform method.

import { PercentPipe } from '@angular/common';

class YourComponent {

  constructor(private percentPipe: PercentPipe) {}

  toPercent(value) {
    return this.percentPipe.transform(value, '1.2');
  }
}

You will need to add the provider in the provider list in your module if not, you will recieve an exeption

providers: [PercentPipe,...]
Diego Bascans
  • 1,083
  • 1
  • 6
  • 14