Home > Back-end >  Keeping input field formatted in Angular form... values desynchronisation
Keeping input field formatted in Angular form... values desynchronisation

Time:08-10

Description I have a form with an input field that should hold a 1 to 4 characters code. It should only contain letters and ideally only uppercase letters.

I wrote the function keepCodeFormatted() in order to correct the input as the user types. But where I'm getting lost is that the value seems to be in different places and not all are updated the same. What am I doing wrong?

For examples, see outputs 1,2,3 in the html part. Typically output 1 contains what I want and outputs 2 and 3 contains something from a step before, or something wrong (numbers).

Examples

I enter a lowercase 'd'

  • Output 1: D
  • Output 2: d
  • Output 3: d

Then I enter a number '3'

  • Output 1: D
  • Output 2: D3
  • Output 3: D3

Then I enter an uppercase 'T' (there everything turn as expected

  • Output 1: DT
  • Output 2: DT
  • Output 3: DT

Then I enter a '<' symbol

  • Output 1: DT
  • Output 2: DT<
  • Output 3: DT<

Resulting issues With

  • Output 1: DT
  • Output 2: DT<
  • Output 3: DT<

Remember that user only sees Output 1 -> input seems valid but button is not clickable and user is not aware that input is actually in an invalid state. (same with number instead of symbols)

With Output 1: DTM Output 2: DTm Output 3: DTm Form can be submitted, but submitted value with be DTm instead of DTM. (Remember that uppercase is preferred) Hence the .toUpperCase() somewhere in the onSubmit method ... but this should not be required.

Tried I tried updating this.myFormGroup.value.code but this give not improvement. I tried updating this.myFormGroup.controls['code'] but this is read-only. I tried this.myFormGroup.controls['code'].updateValueAndValidity(); but this doesn't really do anything in this situation. I tried to work with keydown , but this made things worse (in example by preventing [enter] key from submitting.

myForm(html)

<form #myForm="ngForm" [formGroup]="myFormGroup" (ngSubmit)="onSubmit()">
    <div >
        <input #code  type="text" maxlength="4" size="4" formControlName="code" (keyup)="code.value = keepCodeFormatted(code.value)" />
        <button [disabled]="myFormGroup.invalid"  type="submit" id="button-whatever">Submit</button>
    </div>
</form>
<p>Output 1:{{code.value}}</p>
<p>Output 2:{{myFormGroup .value.code}}</p>
<p>Output 3:{{myFormGroup .controls['code'].value}}</p>

component-with-my-form.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, Validators } from '@angular/forms';
import { ServiceThatUsesCode } from '../../service-that-uses-code.service';

@Component({
  selector : 'component-with-my-form',
    templateUrl: './component-with-my-form.component.html',
  styles : ['button[disabled] {color:grey;border-color:grey}']})
export class ComponentWithMyForm implements OnInit {
    myFormGroup = this.formBuilder.group({
        code: new FormControl('', [
            Validators.required,
            Validators.maxLength(5),
            Validators.pattern(/^[A-Za-z] $/) //I'd be tempted to remove ^and  $ and a-z but I'm very bad at regular expressions...
        ]),
    });

    constructor(private serviceThatUsesCode: ServiceThatUsesCode, private formBuilder: FormBuilder) { }

    ngOnInit(): void {}

    onSubmit(): void {
        let code: string | null | undefined = this.myFormGroup.value.code;
        if (code) {
            this.serviceThatUsesCode.useCode(code.toUpperCase());
            this.myFormGroup.reset();
        }
    }

    keepCodeFormatted(code: string) {
        let formattedValue: string = code.replace(/[^A-Za-z]/g, '').toUpperCase();
        this.myFormGroup.value.code = formattedValue;
        //this.myFormGroup.controls['code'] = formattedValue; // Can't because left is read only
        this.myFormGroup.controls['code'].updateValueAndValidity();
        return formattedValue;
    }
}

CodePudding user response:

If found here: How do you automatically set text box to Uppercase? that there is a way to do this in basic JavaScript/HTML.

So I replaced

<input #code  type="text" maxlength="4" size="4" formControlName="code" (keyup)="code.value = keepCodeFormatted(code.value)" />

With

<input #code  type="text" maxlength="4" size="4" formControlName="code" oninput="this.value = this.value.replace(/[^A-Za-z]/g, '').toUpperCase()" />

Or maybe

<input #code  type="text" maxlength="4" size="4" formControlName="code" oninput="this.value = this.value.toUpperCase().replace(/[^A-Z]/g, '')" />
  • Related