10

Cant seem to figure this out. I have tried many different variations. This is on an Angular project.

I want a percent number to always be shown with two decimal places even if the user only types a whole number.

I cant switch the data type around as a lot of other code has been written around it being a number.

The problem is that TypeScript does not allow var and I am having trouble getting to add the extra zeros or round said number to two decimals. It always seems to strip them.

Declaration:

 percent: number;

Some things I have tried.

1:
this.percent = Math.round(this.percent * 1e2) / 1e2;

2:
this.percent = this.percent.toFixed(2); // Throws error cant assign string to num because to fixed returns string

3:
const percentString = this.percent.toString() + '.00';
this.percent = parseFloat(percentString) // Strips 00 (Tried this to just add zeros to whole number as test [will be making it more dynamic])

4:
this.percent = Math.round(this.percent * 100) / 100;

5: (This whole function from another SOF)

  addZeroes(num) {
// Convert input string to a number and store as a variable.
    let value = Number(num).toString();
// Split the input string into two arrays containing integers/decimals
    const res = num.split('.');
// If there is no decimal point or only one decimal place found.
    if (res.length === 1 || res[1].length < 3) {
// Set the number to two decimal places
      value = parseFloat(value).toFixed(2);
    }
// Return updated or original number.
    return value;
  }

and then

this.percent = parseFloat(this.addZeroes(this.percent));

6:
this.percent = parseFloat(this.percent).toFixed(2); // Error inside parseFloat: TS2345: Argument of type 'number' is not assignable to parameter of type 'string'

7:
this.percent = parseFloat(this.percent.toString()).toFixed(2); // Throws error on this.percent assignment: TS2322: Type 'string' is not assignable to type 'number'

8:
this.percent = Number(this.percent).toFixed(2); // Error on assignment: TS2322: Type 'string' is not assignable to type 'number'.

HTML:

  <mat-form-field>
    <input
      matInput
      [numbers]="'.'"
      type="text"
      maxlength="5"
      [placeholder]="'Percent'"
      [(ngModel)]="percent"
      (change)="updateDollarAmountNew()"
      numbers
      name="percent">
  </mat-form-field>

I have also tried piping on front end but have problems with that as well.

[(ngModel)]="p.percent | number : '1.2-2'" // Error: ng: The pipe '' could not be found

[(ngModel)]="{{percent | number : '1.2-2'}}" // Error: unexpected token '}}'

[(ngModel)]={{percent | number : '1.2-2'}} // Error: Attribute number is not allowed here

[(ngModel)]={{percent | number : 2}} // Error: : expected

// And so on...

Thanks for your tips and help!

2
  • try [(ngModel)]="percent | number : '1.2-2'". Since you are passing a value into an input (in this case percent into ngModel), you don't need the {{}} Commented Mar 15, 2019 at 16:47
  • I can reference this from here Commented Oct 25, 2022 at 11:49

2 Answers 2

18

You've done all the work, but just haven't put the right bits together. Parsing the float works, and toFixed(2) was correctly returning a string with 2 decimal places, you just need to use them together:

parseFloat(input).toFixed(2)

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for answering. See update about errors received.
Try just using Number() rather than parseFloat(). It sounds like you've got your types confused somewhere, as your compiler thinks it's a number, but your browser thinks it's a string
Shoot nope. Added html and declaration details.
This answer is advocating an anti-pattern approach. Wherever possible you should always try to implement presentation using the HTML template - thats what it is for - and seperation of concerns is important :) medium.freecodecamp.org/…
11

Treating it as a number and formatting in the view is the correct approach.

However, you're mixing up binding & formatting, for example: [(ngModel)]="{{percent | number : '1.2-2'}}" is (very roughly!) equivalent to saying in english: bind my model to the string interpolation of...my model.

Try:

<div>{{percent | number : '1.2-2'}}</div>

There are good examples of number pipe usage in the docs: https://angular.io/api/common/DecimalPipe#example

2 Comments

Well that is a step forward! That does work but I do need this format to be bound to the input as shown in the HTML above. Can you think of a good way to do this?
@DavidLaGrange To achieve that with an input field you'll need to write yourself a directive. Here's one that achieves a similar effect - you'll need to adjust it to suit your use case: stackblitz.com/edit/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.