What does Angular FormControl value actually hold and why is it different from the nativeElement value?

1.1k Views Asked by At

Update: logging blur and keyup events shows that the mask never makes it into the FormControl value. Why is that? Even calling the setValue() method on the control itself strips out the mask. Like:

<mat-form-field>
  <mat-label>MSRP Pricing</mat-label>
  <input
    type="text"
    #cost
    matInput
    mask="separator.2"
    thousandSeparator=","
    prefix="$ "
    [formControl]="msrpCtrl"
    (blur)="setVal(msrpCtrl, cost.value)"
    (keyup)="log('keyup', msrpCtrl.value)">
  <mat-error *ngIf="msrpCtrl.hasError('required')">
    MSRP Price is required
  </mat-error>
</mat-form-field>
setVal(control: FormControl, val){
    console.log('set val as' + val);
    control.setValue(val);
  }

This still strips out the mask. Any ideas here?

Original Post:

I am using Angular 8.0.0, Angular forms 8.0.0, Angular Material 8.2.3 and ngx-mask 8.1.5

I have been building a dynamic form and using masks to help guide the users with entering in proper data.

For whatever reason though, FormControl values strip out masks. Example case - MSRP Cost.

So I have a simple input like the following:

<mat-form-field>
  <mat-label>MSRP Pricing</mat-label>
  <input
    type="text"
    #cost
    matInput
    mask="separator.2"
    thousandSeparator=","
    prefix="$ "
    [formControl]="msrpCtrl">
  <mat-error *ngIf="msrpCtrl.hasError('required')">
    MSRP Price is required
  </mat-error>
</mat-form-field>

As the user types, it will throw a comma in for each thousand separator, only let them specify 2 decimal points, and keeps a dollar sign and a space before the first number. Simple enough, and it works.

The problem arises when it comes time to actually send the data elsewhere. If the user enters in numbers into that field and what the mask shows is

$ 130,000.56

what the formControl value actually holds is 130000.56

I want it to actually hold what the input value has which is $ 130,000.56

The only way I can figure how to do this is by referencing the DOM input element directly in my TS file, and getting the value this way:

@ViewChild('cost', {static: false}) cost: ElementRef;
.
.
.
console.log(this.cost.nativeElement.value);
// Or send the value on

This is definitely not ideal, especially doing this for 40+ more inputs. Is there a reason why the mask is stripped out of the FormControl value in the first place? And if there isn't, is there a better approach to capturing the value that the mask shows?

1

There are 1 best solutions below

1
On BEST ANSWER

I had this same issue with wanting to retain dashes in a phone number mask. Using Angular 8.2.12 and ngx-mask 8.2.0 I solved it by setting the dropSpecialCharacters option to false

<input type="text" formControlName="phone" mask="000-000-0000" [dropSpecialCharacters]="false" />

link to documentation