简体   繁体   中英

Angular 2: Add validators to ngModelGroup

I am using a ngModelGroup directive to group several form inputs together.

In the docs ( https://angular.io/docs/ts/latest/api/forms/index/NgModelGroup-directive.html ) I read that there is a validators: any[] property.

Does this mean I can add a custom validator function which validates only that ngModelGroup ? If so, how do I use it?

That would be awesome because I would like to check if at least one of the checkboxes in the ngModelGroup is checked. I can't use required because that would mean all checkboxes are required. I can't find anything about this in the documentation or am I looking in the wrong place?

This is entirely possible with a ngModelGroup and a custom directive for validation. Key to understanding why this works is that ngModelGroup

Creates and binds a FormGroup instance to a DOM element.

First, we'll build out our directive which is pretty boilerplate with nothing special going on:

@Directive({
  selector: '[hasRequiredCheckboxInGroup]',
  providers: [{provide: NG_VALIDATORS, useExisting: HasRequiredCheckBoxInGroup, multi: true}]
})
export class HasRequiredCheckBoxInGroup implements Validator, OnChanges {
  private valFn = Validators.nullValidator;

  constructor() {
    this.valFn = validateRequiredCheckboxInGroup();
  }

  validate(control: AbstractControl): {[key: string]: any} {
    return this.valFn(control);
  }
}

Our validation function is where we take our key knowledge that ngModelGroup creates a FormGroup and apply it:

function validateRequiredCheckboxInGroup() : ValidatorFn {
      return (group) => { //take the group we declare in the template as a parameter
        let isValid = false; //default to invalid for this case
        if(group) {
          for(let ctrl in group.controls) {
            if(group.controls[ctrl].value && typeof group.controls[ctrl].value === 'boolean') { // including a radio button set might blow this up, but hey, let's be careful with the directives
              isValid = group.controls[ctrl].value;
            }
          }
        }

        if(isValid) {
          return null;
        } else {
          return { checkboxRequired: true };
        }
      }
    }

And finally, having included and declared in our Module the directive, we return to the template (needs to be in a form):

<form #f="ngForm">
      <div ngModelGroup="checkboxes" #chks="ngModelGroup" hasRequiredCheckboxInGroup>
          <input type="checkbox" name="chk1" [(ngModel)]="checks['1']"/>
          <input type="checkbox" name="chk2" [(ngModel)]="checks['2']"/>
      </div>
      <div>
      {{chks.valid}}
      </div>
</form>

And here's a plunker with all this available to play with: http://plnkr.co/edit/AXWGn5XwRo60fkqGBU3V?p=preview

Thanks all for helping me out! I've accepted Silentsod's answer because it was most helpful.

My final solution was simply building the form using FormBuilder .

In my component, create the form and add the validator function to it:

ngOnInit(): void {
    // Validator function:
    let validateMemberList = (group: FormGroup) => {
        let checked = Object.keys(group.controls).reduce((count, key: string) => {
            return count + (group.controls[key].value ? 1 : 0);
        }, 0);

        return checked === 0 ? {'minchecked': 1} : null;
    };

    this.jobForm = this.formBuilder.group({
        jobTitle: ['', Validators.required],
        // more inputs...
        members: this.formBuilder.group({}, {
            // The 2nd argument is an object with a validator property:
            validator: validateMemberList
        }),
        supportMembers: this.formBuilder.group({}, {
            validator: validateMemberList
        })
    });

Then in my template:

<form [formGroup]="jobForm">
    <ul formGroupName="members">
        <li *ngFor="let user of teamMembers.members">
            <label class="e-label">
                <input class="e-input" type="checkbox" [formControlName]="user.$key">
                <user-badge [user]="user"></user-badge>
            </label>
        </li>
    </ul>
...

This validates the form allowing me to display errors and disable the submit button.

Thanks all for the help!

Looks like each control in your ModelGroup should have is own validator. once this is done you might have access to each one through the validators array. so add the required attribute to the inputs that are required

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM