4

I have a situation where I need to format the user input and then validate it.

I am using a reactive form and created my custom validation as seen below (relevant parts):

HTML:

<input type="text" formControlName="invoiceNumber" (blur)="formatInvoiceNumber()" class="form-control">
<div *ngIf="this.form.controls['invoiceNumber'].invalid && this.form.controls['invoiceNumber'].touched">Invalid Text</div>

Controller:

this.form = this.formBuilder.group({
            'invoiceNumber': ['', validateInvoiceNumber()],
        });

    formatRoNumber() {
            var invoiceNumber = this.form.controls['invoiceNumber'].value;
            //format invoice number
        }

Validator:

export function validateInvoiceNumber(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } => {
        let invoiceNumber = control.value,
            isValid = true;

        //validate invoice number
        return isValid ? null : { validInvoiceNumber: { valid: false } }
    };
}

I am running into timing issues. The formatting of input happens after validation.

How can I tell Angular to apply the formatting and then validate?

Thibs
  • 8,058
  • 13
  • 54
  • 85
  • 1
    Looks like you are formatting on blur ... so when the user leaves the field. By default, validation occurs as the user types. So you want it to validate when the user leaves the field instead? Then consider not using the built in validation (not specifying it in the FormBuilder) and instead just calling it directly. If you want it to occur after the formatting, you could call it from formatInvoiceNumber(). – DeborahK Apr 18 '17 at 21:17
  • @DeborahK, I see. I was hoping there was a way to make this work with FormBuilder...or run the formatting some other way. thank-you – Thibs Apr 18 '17 at 21:23
  • If you want to format as they type, you could add a watch on valueChanges and format/validation then. – DeborahK Apr 18 '17 at 22:14
  • You could also decide to validate on blur using the technique shown here: http://stackoverflow.com/questions/33866824/angular2-control-validation-on-blur – DeborahK Apr 18 '17 at 22:17
  • @DeborahK, could you please show how to call validation directly on an input element as you explain in your first comment? – Thibs Apr 20 '17 at 18:28
  • If you call the logic for the validation directly, then you have to manually handle the validation ... such as adding/removing from the errors collection for the field. So this is more code than you may want to tackle for this issue. Could you reiterate what you are trying to achieve? Why do you need to format before validating? – DeborahK Apr 20 '17 at 18:36
  • I need to pad the user input with leading zeros and then validate. This does not have to happen as the user types and is ok on blur. Either or. Caleb's example didn't really work and was calling my validator twice as much.. Thank-you – Thibs Apr 20 '17 at 18:41
  • If you can put together a plunker of the minimum set of code required to achieve what you need, I could take a look. – DeborahK Apr 20 '17 at 18:45

3 Answers3

1

You can do this with formbuilder if you also use ngModel in order to format. I've accomplished it like so

<ion-input
formControlName="fullName"
type="text"
[ngModel]="fullName | pipeHere"
(ngModelChange)="fullName=$event">
</ion-input>

this.customerFields = this.fb.group({
  fullName: ['', Validators.compose([ Validators.required, Validators.minLength(11) ])]
});

the (ngModelChange) will be what fires your pipe into action while the validation fires as usual. If you write a custom pipe, you can allow for additional validation as well.

Caleb Swank
  • 619
  • 5
  • 17
0

Caleb's way is not working for me for some reason, and the validator is being called twice as much.

If it helps anyone, I ended up doing it this way. There must be a better way, seems odd to setValidators, apply them, then remove them for next updates...but this works.

Thank-you Caleb and Deborah for you help.

Control:

<input type="text" formControlName="invoiceNumber" (blur)="updateAndValidateInvoiceNumber()" class="form-control">

Controller:

updateAndValidateInvoiceNumber(): void {
     let control: AbstractControl = this.form.controls['invoiceNumber'];
     let newVal = this.invoiceFormatterPipe.transform(control.value);

     control.patchValue(newVal);
     control.setValidators(validateInvoiceNumber());
     control.updateValueAndValidity();
     control.clearValidators();
 }
Thibs
  • 8,058
  • 13
  • 54
  • 85
0

In your formgroup, add the below pattern for that formControl:

-variable_name: ['', [Validators.pattern(/^[.\d]{1,15}$/)]]
xiawi
  • 1,772
  • 4
  • 19
  • 21