Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

at least one field is required in angular 4 forms

I'm using angular 4 forms and I have some fields. and first_name, last_name and company are really important for me. I want to force the user to fill one of these 3 fields. how can I do it?

here are .ts codes:

this.contactForm = this.fb.group({
        first_name: [null, Validators.compose([Validators.required])],
        last_name: [null, Validators.compose([Validators.required])],
        email: [null, Validators.compose([this.validateEmail])],
        company: [null],
        position: [null],
      });

an html:

 <form [formGroup]="contactForm" fxLayout="column">
            <md-input-container class="data_light">
              <input class="data_font capital" mdInput placeholder="{{'Contacts.FirstName' | translate}}" [formControl]="contactForm.controls['first_name']">
            </md-input-container>
            <small *ngIf="contactForm.controls['first_name'].hasError('required') && contactForm.controls['first_name'].touched" class="mat-text-warn data_light">{{'Contacts.firstNameReq' | translate}}
            </small>
            <md-input-container class="data_light">
              <input class="data_font capital" mdInput placeholder="{{'Contacts.lastName' | translate}}" [formControl]="contactForm.controls['last_name']">
            </md-input-container>
            <small *ngIf="contactForm.controls['last_name'].hasError('required') && contactForm.controls['last_name'].touched" class="mat-text-warn data_light">{{'Contacts.lastNameReq' | translate}}
            </small>
            <md-input-container class="data_light">
              <input class="data_font" mdInput placeholder="{{'Contacts.email' | translate}}" [formControl]="contactForm.controls['email']"
                (blur)="checkContactEmail()">
            </md-input-container>
            <small *ngIf="contactForm.controls['email'].hasError('validateEmail') && contactForm.controls['email'].dirty" class="mat-text-warn data_light">{{'Contacts.emailValid' | translate}}
            </small>
            <small *ngIf="!emailValid" class="mat-text-warn data_light">{{emailMessage}}
            </small>
            <md-input-container class="data_light">
              <input class="data_font capital" mdInput placeholder="{{'Contacts.Company' | translate}}" [formControl]="contactForm.controls['company']">
            </md-input-container>
            <md-input-container class="data_light">
              <input class="data_font capital" mdInput placeholder="{{'Contacts.Position' | translate}}" [formControl]="contactForm.controls['position']">
            </md-input-container>
          </form>
like image 320
fariba.j Avatar asked Apr 26 '18 07:04

fariba.j


People also ask

When one field is filled other fields must be required?

if one field in the form is filled,all other fields must be filled or if none of the fields are filled then no need of checking validations. Iam using a method focus to add validations. once selecting a field,all fields are required validation executing.

How many forms are there in angular?

Angular provides two different approaches to handling user input through forms: reactive and template-driven.

What is form field in angular?

Overview for form-field. <mat-form-field> is a component used to wrap several Angular Material components and apply common Text field styles such as the underline, floating label, and hint messages.


3 Answers

private atLeastOneValidator = () => {
    return (controlGroup) => {
        let controls = controlGroup.controls;
        if ( controls ) {
            let theOne = Object.keys(controls).find(key=> controls[key].value!=='');
            if ( !theOne ) {
                return {
                    atLeastOneRequired : {
                        text : 'At least one should be selected'
                    }
                }
            }
        }
        return null;
    };
};

Above is a reusable validator and you can use it like this :

 this.contactForm.setValidators(this.atLeastOneValidator())

This makes the whole contactForm invalid if none of the fields have a value.

Note that the contactForm's default validation will still work nicely and you don't have to care about the number of fields in your form and everything is dynamically handled

EDIT :

Note that the atLeastOneValidator is checking for the values to not to be empty , but if you wanted to say :

At least one of them fields must be valid, then you can simply adjust the conditions to below

 let theOne = Object.keys(controls).find(key=> controls[key].valid );

You can then use the error in your template like this :

 <small *ngIf="contactForm.hasError('atLeastOneRequired')" class="mat-text-warn data_light">{{contactForm.getError('atLeastOneRequired')}}
        </small>
like image 177
Milad Avatar answered Oct 08 '22 04:10

Milad


Disable your button until required fields are not fileld by user

<button type='submit' [disabled]='!contactForm.valid'> Submit</button>

Then call function to check disable like this

<button type='submit' [disabled]='checkValid()'> Submit</button>
checkValid() {
  if(this.contactForm.get('first_name').valid || this.contactForm.get('last_name').valid || this.contactForm.get('email').valid) {
    return false;
  } else {
    return true;
  }
}
like image 44
Pardeep Jain Avatar answered Oct 08 '22 05:10

Pardeep Jain


I provide a better customized way for some fields only, and not for all fields of the form. Also,

  • Not like this <button [disabled]="checkValid()">,

  • But to use directly <button [disabled]="form.invalid || form.pristine || loading">

Fields can be provided via Array param as following:

export const atLeastOneHasValue = (fields: Array<string>) => {
    return (group: FormGroup) => {
        for (const fieldName of fields) {
            if (group.get(fieldName).value) {
                return null;
            }
        }
        return { paymentMethodRequired: true };
    };
};

// Form group
form = this.formBuilder.group({
   field1: [],
   field2: [],
   field3: [],
   field4: []
}, {
    validators: atLeastOneHasValue(['field2', 'field3'])
});

You then, can check and show error as following in the template, saving button will be disabled thanks to form.invalid boolean:

<mat-error *ngIf="form.hasError('paymentMethodRequired')">
    {{"ERROR_PAYMENT_METHOD_REQUIRED" | translate}}
</mat-error>
like image 29
Davideas Avatar answered Oct 08 '22 06:10

Davideas