티스토리 뷰

728x90

1. 이번 포스트는 지난 포스트의 사용자 정의 검증로직을 좀 더 범용적으로 사용할 수 있도록 변경한다.

  1-1 지난 포스트의 연속이므로 이전 포스트를 읽는 게 좋다.

 

2. 범용로직을 작성한다.

  2-0 검증로직의 분리를 위해  class를 하나 생성하였다.

 

  2-1 이 class에 여러개의 검증로직을 정의하여 특정한 form에 종속되지 않도록 작성하다. 

    2-1-1 독립성을 유지하기 위해서는 클래스는 독립성이 보장되어야 하므로 static 메소드를 사용해야 한다.

      2-1-1-1 검증로직을 그대로 복사하여 붙여 넣었다.

 

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

export class PasswordValidators {
  static isMatch(form: AbstractControl) {
    const { password, passwordConfirmation } = form.value;
    if (password !== passwordConfirmation) {
      return { notMatched: true };
    } else {
      return null;
    }
  }
}

 

    2-1-2 이제 호출하는 부분을 아래의 코드를 2단계로 변형할 수 있다.

      2-1-2-1 검증로직은 결과 객체를 반환하므로 그것을 적절하게 반환해 주면 된다.

      2-1-2-2 중요한 것은 validator에 설정하는 검증로직은 callback함수기 때문에 함수 정의만 넘겨주면 된다.

        2-1-2-2-1 원할 때 프로그램에서 적절하게 callback을 호출하기 때문에 개발자가 신경 쓸 필요가 없다.

 

  // 처음의 form
  constructor(private formBuilder: FormBuilder) {
    this.passwordFormGroup = this.formBuilder.group(
      {
        password: [
          '',
          [
            Validators.required,
            Validators.minLength(3),
            Validators.maxLength(20),
          ],
        ],
        passwordConfirmation: [
          '',
          [
            Validators.required,
            Validators.minLength(3),
            Validators.maxLength(20),
          ],
        ],
      },
      {
        validators: (form: AbstractControl) => {
          const { password, passwordConfirmation } = form.value;
          if (password !== passwordConfirmation) {
            return { notMatched: true };
          } else {
            return null;
          }
        },
      }
    );
  }
  
  // 1단계 
  
      {
        validators: (form: AbstractControl) => {
          return PasswordValidators.isMatch(form)
        },
      }
      
  // 2단계
  
      {
        validators: PasswordValidators.isMatch,
      }

 

    2-1-3 결과 화면

      2-1-3-1 3가지 경우 모두 적절하게 동작한다.

 

 

  2-2 이제 한 걸음 더 나아가 다른 form에서도 이 검증함 수를 사용할 수 있도록 인자값까지 넘겨주도록 변경한다.
    2-2-1 어떤 form은 control이름을 pass, passconfirm 으로 정의할 수도 있고, pass, passConfirm으로 할 수도 있다.

    2-2-2 이런 모든 경우를 고려해서 이름을 매핑하는 하고 변형된 함수로 반환하는 코드를 작성한다.

      2-2-2-1 아래처럼 우선 control의 이름을 넘겨주어야 한다.

 

import { Component, OnInit } from '@angular/core';
import {
  FormGroup,
  FormBuilder,
  Validators,
} from '@angular/forms';
import { PasswordValidators } from '../password-validators';

@Component({
  selector: 'app-passwordconfirm',
  templateUrl: './passwordconfirm.component.html',
  styleUrls: ['./passwordconfirm.component.css'],
})
export class PasswordconfirmComponent implements OnInit {
  ngOnInit(): void {}

  passwordFormGroup: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.passwordFormGroup = this.formBuilder.group(
      {
        password: [
          '',
          [
            Validators.required,
            Validators.minLength(3),
            Validators.maxLength(20),
          ],
        ],
        passwordConfirmation: [
          '',
          [
            Validators.required,
            Validators.minLength(3),
            Validators.maxLength(20),
          ],
        ],
      },
      {
        validators: PasswordValidators.isMatch('password', 'passwordConfirmation'),
      }
    );
  }
}

 

    2-2-3 이제 검증함수를 변경한다.

      2-2-3-0 함수를 반환하는 함수를 작성하였다. 어차피 결론은 콜백 검증함수를 제공하는 문제다.

      2-2-3-1 컨트롤의 이름을 인자로 받아 formGroup 컨트롤에서 이름으로 객체의 속성을 가지고 와서 검증한다.

      2-2-3-2 이렇게 하면 어떤 컨트롤 이름을 사용해도 이 함수를 재사용 가능하다.

 

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

export class PasswordValidators {
  static isMatch(param1: string, param2: string) {
    return (form: AbstractControl) => {
      const password1 = form.value[param1];
      const password2 = form.value[param2];

      if (password1 !== password2) {
        return { notMatched: true };
      } else {
        return null;
      }
    };
  }
}

 

    2-2-4 결과화면 - 결과는 동일하다. 참고로 아래 각 컨트롤의 에러상황을 보기 위해 추가한 부분이 있다.

 

728x90
댓글