[angular] 여러 양식 필드에 의존하는 Angular2 유효성 검사기

내 필드가 유효한지 결정하기 위해 여러 값을 사용할 수있는 유효성 검사기를 만들 수 있습니까?

예를 들어 고객이 선호하는 연락 방법이 이메일 인 경우 이메일 필드가 필요합니다.

감사.


예제 코드로 업데이트 됨 …


    import {Component, View} from 'angular2/angular2';
    import {FormBuilder, Validators, formDirectives, ControlGroup} from 'angular2/forms';

    @Component({
        selector: 'customer-basic',
        viewInjector: [FormBuilder]
    })
    @View({
        templateUrl: 'app/components/customerBasic/customerBasic.html',
        directives: [formDirectives]
    })
    export class CustomerBasic {
        customerForm: ControlGroup;

        constructor(builder: FormBuilder) {
            this.customerForm = builder.group({
                firstname: [''],
                lastname: [''],
                validateZip: ['yes'],
                zipcode: ['', this.zipCodeValidator]
                // I only want to validate using the function below if the validateZip control is set to 'yes'
            });
        }

        zipCodeValidator(control) {
            if (!control.value.match(/\d\d\d\d\d(-\d\d\d\d)?/)) {
                return { invalidZipCode: true };
            }
        }

    }



답변

다른 사람들이 게시 한 방법에 대해 반복하기 위해 이것이 FormGroup여러 그룹을 포함하지 않는 유효성 검사기를 만드는 방법 입니다.

이 예에서는 passwordconfirmPassword필드 의 키 이름을 제공하기 만하면 됩니다.

// Example use of FormBuilder, FormGroups, and FormControls
this.registrationForm = fb.group({
  dob: ['', Validators.required],
  email: ['', Validators.compose([Validators.required,  emailValidator])],
  password: ['', Validators.required],
  confirmPassword: ['', Validators.required],
  firstName: ['', Validators.required],
  lastName: ['', Validators.required]
}, {validator: matchingPasswords('password', 'confirmPassword')})

위해서는 Validators매개 변수를 적용하려면, 그들은을 반환해야 function와 함께 중 하나 FormGroup또는 FormControl매개 변수로. 이 경우 FormGroup.

function matchingPasswords(passwordKey: string, confirmPasswordKey: string) {
  return (group: FormGroup): {[key: string]: any} => {
    let password = group.controls[passwordKey];
    let confirmPassword = group.controls[confirmPasswordKey];

    if (password.value !== confirmPassword.value) {
      return {
        mismatchedPasswords: true
      };
    }
  }
}

기술적으로는 두 값의 키를 알고 있으면 유효성을 검사 할 수 있었지만 Validators 반환 할 오류와 동일한 . 반환 된 오류의 키 이름을 나타내는 세 번째 매개 변수를 사용하도록 함수를 수정할 수 있습니다.

2016 년 12 월 6 일 업데이트 됨 (v2.2.4)

전체 예 : https://embed.plnkr.co/ukwCXm/


답변

Dave의 대답 은 매우, 매우 도움이되었습니다. 그러나 약간의 수정이 일부 사람들에게 도움이 될 수 있습니다.

Control필드 에 오류를 추가해야하는 경우 양식 및 유효성 검사기의 실제 구성을 유지할 수 있습니다.

// Example use of FormBuilder, ControlGroups, and Controls
this.registrationForm= fb.group({
  dob: ['', Validators.required],
  email: ['', Validators.compose([Validators.required,  emailValidator])],
  password: ['', Validators.required],
  confirmPassword: ['', Validators.required],
  firstName: ['', Validators.required],
  lastName: ['', Validators.required]
}, {validator: matchingPasswords('password', 'confirmPassword')})

에 오류를 설정하는 대신 ControlGroup실제 필드에서 다음과 같이 설정하십시오.

function matchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
  return (group: ControlGroup) => {
    let passwordInput = group.controls[passwordKey];
    let passwordConfirmationInput = group.controls[passwordConfirmationKey];
    if (passwordInput.value !== passwordConfirmationInput.value) {
      return passwordConfirmationInput.setErrors({notEquivalent: true})
    }
  }
}


답변

여러 양식 필드에 대한 유효성 검사기를 구현할 때 각 양식 컨트롤이 업데이트 될 때 유효성 검사기가 다시 평가되는지 확인해야합니다. 대부분의 예제는 이러한 시나리오에 대한 솔루션을 제공하지 않지만 데이터 일관성과 올바른 동작을 위해 매우 중요합니다.

이를 고려한 Angular 2 용 사용자 지정 유효성 검사기 구현을 참조하십시오 : https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 .

내가 사용하고 otherControl.valueChanges.subscribe()다른 컨트롤의 변화를 수신하고 thisControl.updateValueAndValidity()다른 제어가 변경 될 때 검증의 또 다른 라운드를 트리거 할 수 있습니다.


나중에 참조 할 수 있도록 아래 코드를 복사하고 있습니다.

match-other-validator.ts

import {FormControl} from '@angular/forms';


export function matchOtherValidator (otherControlName: string) {

  let thisControl: FormControl;
  let otherControl: FormControl;

  return function matchOtherValidate (control: FormControl) {

    if (!control.parent) {
      return null;
    }

    // Initializing the validator.
    if (!thisControl) {
      thisControl = control;
      otherControl = control.parent.get(otherControlName) as FormControl;
      if (!otherControl) {
        throw new Error('matchOtherValidator(): other control is not found in parent group');
      }
      otherControl.valueChanges.subscribe(() => {
        thisControl.updateValueAndValidity();
      });
    }

    if (!otherControl) {
      return null;
    }

    if (otherControl.value !== thisControl.value) {
      return {
        matchOther: true
      };
    }

    return null;

  }

}

용법

반응 형과 함께 사용하는 방법은 다음과 같습니다.

private constructForm () {
  this.form = this.formBuilder.group({
    email: ['', [
      Validators.required,
      Validators.email
    ]],
    password: ['', Validators.required],
    repeatPassword: ['', [
      Validators.required,
      matchOtherValidator('password')
    ]]
  });
}

더 많은 최신 유효성 검사기는 moebius-mlm / ng-validators 에서 찾을 수 있습니다 .


답변

Angular 2 RC.5를 사용하고 있지만 Dave의 유용한 답변을 기반으로 ControlGroup을 찾을 수 없습니다. FormGroup이 대신 작동한다는 것을 알았습니다. 그래서 저는 Dave의 코드에 대해 약간의 업데이트를했고 다른 사람들과 공유 할 것이라고 생각했습니다.

구성 요소 파일에서 FormGroup에 대한 가져 오기를 추가합니다.

import {FormGroup} from "@angular/forms";

양식 컨트롤에 직접 액세스해야하는 경우 입력을 정의합니다.

oldPassword = new FormControl("", Validators.required);
newPassword = new FormControl("", Validators.required);
newPasswordAgain = new FormControl("", Validators.required);

생성자에서 양식을 인스턴스화하십시오.

this.form = fb.group({
  "oldPassword": this.oldPassword,
  "newPassword": this.newPassword,
  "newPasswordAgain": this.newPasswordAgain
}, {validator: this.matchingPasswords('newPassword', 'newPasswordAgain')});

클래스에 matchingPasswords 함수를 추가합니다.

matchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
  return (group: FormGroup) => {
    let passwordInput = group.controls[passwordKey];
    let passwordConfirmationInput = group.controls[passwordConfirmationKey];
    if (passwordInput.value !== passwordConfirmationInput.value) {
      return passwordConfirmationInput.setErrors({notEquivalent: true})
    }
  }
}

RC.5를 사용하는 사람들에게 도움이되기를 바랍니다. 아직 RC.6에서 테스트하지 않았습니다.


답변

각도 소스를 많이 파고 있지만 더 나은 방법을 찾았습니다.

constructor(...) {
    this.formGroup = builder.group({
        first_name:        ['', Validators.required],
        matching_password: builder.group({
            password: ['', Validators.required],
            confirm:  ['', Validators.required]
        }, this.matchPassword)
    });

    // expose easy access to passworGroup to html
    this.passwordGroup = this.formGroup.controls.matching_password;
}

matchPassword(group): any {
    let password = group.controls.password;
    let confirm = group.controls.confirm;

    // Don't kick in until user touches both fields   
    if (password.pristine || confirm.pristine) {
      return null;
    }

    // Mark group as touched so we can add invalid class easily
    group.markAsTouched();

    if (password.value === confirm.value) {
      return null;
    }

    return {
      isValid: false
    };
}

비밀번호 그룹의 HTML 부분

<div ng-control-group="matching_password" [class.invalid]="passwordGroup.touched && !passwordGroup.valid">
    <div *ng-if="passwordGroup.touched && !passwordGroup.valid">Passwords must match.</div>
    <div class="form-field">
        <label>Password</label>
        <input type="password" ng-control="password" placeholder="Your password" />
    </div>
    <div class="form-field">
        <label>Password Confirmation</label>
        <input type="password" ng-control="confirm" placeholder="Password Confirmation" />
    </div>
</div>


답변

정확히 정확하지 않기 때문에 matthewdaniel의 대답을 확장합니다. 다음은 유효성 검사기를 .NET Framework에 올바르게 할당하는 방법을 보여주는 예제 코드입니다 ControlGroup.

import {Component} from angular2/core
import {FormBuilder, Control, ControlGroup, Validators} from 'angular2/common'

@Component({
  selector: 'my-app',
  template: `
    <form [ngFormModel]="form">
      <label for="name">Name:</label>
      <input id="name" type="text" ngControl="name">
      <br>
      <label for="email">Email:</label>
      <input id="email" type="email" ngControl="email">
      <br>
      <div ngControlGroup="matchingPassword">
        <label for="password">Password:</label>
        <input id="password" type="password" ngControl="password">
        <br>
        <label for="confirmPassword">Confirm Password:</label>
        <input id="confirmPassword" type="password" ngControl="confirmPassword">
      </div>
    </form>
    <p>Valid?: {{form.valid}}</p>
    <pre>{{form.value | json}}</pre>
  `
})
export class App {
  form: ControlGroup
  constructor(fb: FormBuilder) {
    this.form = fb.group({
      name: ['', Validators.required],
      email: ['', Validators.required]
      matchingPassword: fb.group({
        password: ['', Validators.required],
        confirmPassword: ['', Validators.required]
      }, {validator: this.areEqual})
    });
  }

  areEqual(group: ControlGroup) {
    let val;
    let valid = true;

    for (name in group.controls) {
      if (val === undefined) {
        val = group.controls[name].value
      } else {
        if (val !== group.controls[name].value) {
          valid = false;
          break;
        }
      }
    }

    if (valid) {
      return null;
    }

    return {
      areEqual: true
    };
  }
}

다음은 작동하는 예입니다. http://plnkr.co/edit/Zcbg2T3tOxYmhxs7vaAm?p=preview


답변

여기에 전체 또는 하위에 의존하지 않고 ControlGroup각각에 직접 연결되는 또 다른 옵션이 있습니다 Control.

내가 가진 문제는 서로 의존하는 컨트롤이 계층 적으로 함께 있지 않아서 ControlGroup. 또한 내 CSS는 각 컨트롤이 기존 앵귤러 클래스를 활용하여 오류 스타일을 표시할지 여부를 결정하도록 설정되었으며, 컨트롤 별 유효성 검사 대신 그룹 유효성 검사를 처리 할 때 더 복잡했습니다. 유효성 검사가 각 개별 컨트롤이 아닌 컨트롤 그룹에 연결되어 있기 때문에 단일 컨트롤이 유효한지 확인하려는 시도는 불가능했습니다.

제 경우에는 다른 필드가 필요한지 여부를 결정하기 위해 선택 상자의 값을 원했습니다.

이것은 구성 요소에서 Form Builder를 사용하여 작성됩니다. 선택 모델의 경우 요청 개체의 값에 직접 바인딩하는 대신 컨트롤에 대한 “변경시”이벤트를 처리 할 수있는 함수를 가져 오거나 설정하도록 바인딩했습니다. 그런 다음 선택 컨트롤 새 값에 따라 다른 컨트롤에 대한 유효성 검사를 수동으로 설정할 수 있습니다.

다음은 관련 뷰 부분입니다.

<select [ngFormControl]="form.controls.employee" [(ngModel)]="employeeModel">
  <option value="" selected></option>
  <option value="Yes">Yes</option>
  <option value="No">No</option>
</select>
...
<input [ngFormControl]="form.controls.employeeID" type="text" maxlength="255" [(ngModel)]="request.empID" />

관련 구성 요소 부분 :

export class RequestComponent {
  form: ControlGroup;
  request: RequestItem;

  constructor(private fb: FormBuilder) {
      this.form = fb.group({
        employee: new Control("", Validators.required),
        empID: new Control("", Validators.compose([Validators.pattern("[0-9]{7}"]))
      });

  get employeeModel() {
    return this.request.isEmployee;
  }

  set employeeModel(value) {
    this.request.isEmployee = value;
    if (value === "Yes") {
      this.form.controls["empID"].validator = Validators.compose([Validators.pattern("[0-9]{7}"), Validators.required]);
      this.form.controls["empID"].updateValueAndValidity();
    }
    else {
      this.form.controls["empID"].validator = Validators.compose([Validators.pattern("[0-9]{7}")]);
      this.form.controls["empID"].updateValueAndValidity();
    }
  }
}

제 경우에는 항상 패턴 유효성 검사가 컨트롤에 연결되어 있으므로 validator항상 무언가로 설정되어 있지만 validator컨트롤에 연결된 유효성 검사가 없으면을 null로 설정할 수 있다고 생각합니다 .

업데이트 : 모델 변경을 캡처 (ngModelChange)=changeFunctionName($event)하거나 제어 값 변경을 사용하여 구독하는 다른 방법이 있습니다.this.form.controls["employee"].valueChanges.subscribe(data => ...))