Require one from two fields using Angular 2

后端 未结 4 1738
感情败类
感情败类 2020-12-29 09:02

I\'m trying to create a contact form. The form looks like this:

相关标签:
4条回答
  • 2020-12-29 09:45

    Slightly refactored Florian's answer for the lazy as it was making ts-sonar angry (cognitive-complexity rule):

    const isFieldEmpty = (fieldName: string, fg: FormGroup) => {
        const field = fg.get(fieldName).value;
        if (typeof field === 'number') { return field && field >= 0 ? true : false; }
        if (typeof field === 'string') { return field && field.length > 0 ? true : false; }
    };
    
    export function atLeastOne(...fields: string[]) {
      return (fg: FormGroup): ValidationErrors | null => {
        return fields.some(fieldName => isFieldEmpty(fieldName, fg))
          ? null
          : ({ atLeastOne: 'At least one field has to be provided.' } as ValidationErrors);
      };
    }
    
    0 讨论(0)
  • 2020-12-29 09:54

    Yes, a custom validator is the way to go.

    Make your form group like this:

    this.contact = this.formBuilder.group({
      name: ['', Validators.required],
      email: ['', Validators.required],
      phone: ['', Validators.required],
      message: ['', Validators.required]
    }, {validator: this.customValidationFunction})
    

    Then have the customValidationFunction check for validation. Made up validation just for example:

    customValidationFunction(formGroup): any {
       let nameField = formGroup.controls['name'].value; //access any of your form fields like this
       return (nameField.length < 5) ? { nameLengthFive: true } : null;
    }
    

    Change each input like this (changing your p tags to divs. Substitute the control name for each and change syntax for the hidden span tag validation where appropriate):

    <div [ngClass]="{'has-error':!contact.controls['name'].valid && contact.controls['name'].touched}">
        <label>Name</label>
        <input class="input" type="text" [formControl]="contact.controls['name']">
        <span [hidden]="!contact.hasError('nameLengthFive')" class="error">Enter your name</span>
    </div>
    
    0 讨论(0)
  • 2020-12-29 10:06

    I created a custom validator directive:

    import {
        FormGroup,
        ValidationErrors,
        ValidatorFn,
        Validators,
      } from '@angular/forms';
    
      export const atLeastOne = (validator: ValidatorFn, controls:string[] = null) => (
        group: FormGroup,
      ): ValidationErrors | null => {
        if(!controls){
          controls = Object.keys(group.controls)
        }
    
        const hasAtLeastOne = group && group.controls && controls
          .some(k => !validator(group.controls[k]));
    
        return hasAtLeastOne ? null : {
          atLeastOne: true,
        };
      };
    

    To use it, you just do this:

    this.form = this.formBuilder.group({
                name: ['', Validators.required],
                email:[''],
                telefone:[''],
                message:['', Validators.required],
            }, { validator: atLeastOne(Validators.required, ['email','telefone']) });
    

    So email or telefone would be required here. If you leave it empty then any control with a value is fine and you can use it with any type of validator, not just Validators.required.

    This is reusable in any form.

    0 讨论(0)
  • 2020-12-29 10:09

    I have updated my validator snippet to support string and number types

    I was inspired by Todd Skelton. This is a very simple Validator that does just what you ask for and nothing else:

    /**
     * Validates if at least one of the provided fields has a value.
     * Fields can only be of type number or string.
     * @param fields name of the form fields that should be checked
     */
    export function atLeastOne(...fields: string[]) {
      return (fg: FormGroup): ValidationErrors | null => {
        return fields.some(fieldName => {
          const field = fg.get(fieldName).value;
          if (typeof field === 'number') return field && field >= 0 ? true : false;
          if (typeof field === 'string') return field && field.length > 0 ? true : false;
        })
          ? null
          : ({ atLeastOne: 'At least one field has to be provided.' } as ValidationErrors);
      };
    }

    And here is how I use it:

      ngOnInit(): void {
        this.form = this.formBuilder.group(
          {
            field: [this.field],
            anotherField: [this.anotherField],
          },
          { validator: atLeastOne('field','anotherField') },
        );
      }

    0 讨论(0)
提交回复
热议问题