Search code examples
angularangular-validation

load reactive-form error validation message only on focus or on non valid data loading


working on angular 5 form validation. All is working fine except error message are displaying movement page load which is fine only if loaded data doesn't complaints with validation but not for untouched tabs, i.e. empty textbox.

I want to show error message only when user start typing except if loaded data not valid. surprisingly, minLength and maxLength behaving as I want, not sure about others

template

<div *ngIf="form.controls[question.key].invalid && (form.controls[question.key].invalid || form.controls[question.key].touched)" class="alert alert-danger">

    <div *ngIf="form.controls[question.key].hasError('required')">
      Name is required.
    </div>

    <div *ngIf="form.controls[question.key].hasError('email')">
      Email Format is Incorrect.
    </div>

    <div *ngIf="form.controls[question.key].hasError('minlength')">
      Minimum Length Required.
    </div>

    <div *ngIf="form.controls[question.key].hasError('maxlength')">
      Maximum Length Required.
    </div>

    <div *ngIf="form.controls[question.key].hasError('postCode')">
        PostCode Incorrect.
    </div>

</div>

validation service class

@Injectable()
export class QuestionControlService {

    private validations: ValidatorFn[] = [];

    constructor() {
    }

    toFormGroup(questions: QuestionBase<any>[]) {
        let group: any = {};

        questions.forEach(question => {

            this.validations = [];

            debugger;

            for (var key in question.validations) {
                this.mapValidation(question.validations[key].title, question.validations[key].value);
            }
            group[question.key] = new FormControl(question.value || '', this.validations);

        });

        return new FormGroup(group);
    }


    mapValidation(validationTitle: string, validationValue: string) {
        if (validationTitle != null) {

            if (validationTitle == "minLength") {
                this.validations.push(Validators.minLength(parseInt(validationValue)));
            } else if (validationTitle == "maxLength") {
                this.validations.push(Validators.maxLength(parseInt(validationValue)));
            } else if (validationTitle == "required" && validationValue == "true") {
                this.validations.push(Validators.required)
            } else if (validationTitle == "emailType" && validationValue == "true") {
                this.validations.push(Validators.email);
            } else if (validationTitle == "postCodeType" && validationValue == "true") {
                this.validations.push(postCodeValidator);
            }
        }
    }
}

//Custom Validation
//-----------------

function postCodeValidator(control: FormControl) {
    let givenPostCode = control.value;

    let UKPostCodePattern = /^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))\s?[0-9][A-Za-z]{2})$/;

    var isUKPostCodeValid = UKPostCodePattern.test(givenPostCode);

    if (!isUKPostCodeValid) {
        return {
            postCode: {
                required: "UK Valid PostCode",
                provided: givenPostCode
            }
        }
    }
    return null;
}

Solution

  • This makes your error messages to wait untill interaction is done with input

    form.controls[question.key].touched
    

    You have to either exclude condition or add another one that will take fact that data has been loaded into consideration.

    it can be like this

    form.controls[question.key].touched || isDataLoaded
    

    so errors will appear if form is invalid AND (input has been touched OR data has been loaded from somewhere)

    You can also use directive to make input field initially touched,thus validation will apply. You will have to modify it for conditional execution i guess.

    https://stackblitz.com/edit/angular-urqles-xbvkpn?file=app/input-overview-example.html