Angular(v8), ReactiveForm, boolean 이외를 사용할 때의 체크 박스 폼을 구축하는 방법

소개



ReactiveForm의 체크 박스로 boolean 이외의 value를 취급할 때의 폼의 구축 방법을 정리했습니다.
ReactiveForm 자체에 대해서는 설명하지 않으므로 자세한 내용은 공식 문서을 참조하십시오.

이런 과제가 있었다고


  • ReactiveForm에서 체크 박스를 사용하고 싶지만 값은 boolean을 다루고 싶지 않습니다.
  • 폼의 외형은 아래의 그림과 같습니다만, 사용자에 의해 입력된 폼의 값을 취급할 때는 개 → Dog, 고양이 → Cat, 쥐 → Rat와 같이 각 체크 박스에 묶인 다른 값을 사용하고 싶습니다.

  • 이 경우 어떻게 할 것인가.

    해결책은 두



    ① 폼 모델을 템플릿 파일에 바인딩하지 않고 change 이벤트 을 이용하여 폼 모델을 갱신시킨다.

    ② 폼 모델을 템플릿 파일에 바인딩시켜 폼의 값을 취득할 때 boolean에서 원하는 값으로 변환시킨다.

    ①과 ② 실제 코드를 아래에 올리고 싶습니다.

    ①의 코드



    (form1.component.ts)
    import { Component } from '@angular/core';
    import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
    
    interface Option {
      label: string;
      value: string;
    }
    
    @Component({
      selector: 'app-form1',
      templateUrl: './form1.component.html'
    })
    export class Form1Component {
      readonly animalsOption: Option[] = [
        { label: 'イヌ', value: 'Dog' },
        { label: 'ネコ', value: 'Cat' },
        { label: 'ネズミ', value: 'Rabbit' }
      ];
      ngForm: FormGroup = this.fb.group({
        animals: this.fb.array([])
      });
      showValue: string[] = [''];
    
      get animals(): FormArray {
        return this.ngForm.get('animals') as FormArray;
      }
    
      constructor(private fb: FormBuilder) {}
    
      onSubmit() {
        console.log(this.ngForm);
        this.showValue = this.animals.value;
      }
    
      onChange(value: string) {
        const array = this.animals.getRawValue();
        array.includes(value)
          ? this.animals.removeAt(array.indexOf(value))
          : this.animals.push(this.fb.control(value));
      }
    }
    

    (form1.html)
    <form [formGroup]="ngForm" (ngSubmit)="onSubmit()">
      <div>
        <label *ngFor="let option of animalsOption">
          <input type="checkbox" (change)="onChange(option.value)" />
          {{ option.label }}
        </label>
      </div>
      <button class="button" type="submit">
        Show Value!
      </button>
      <h4>form1 value -> {{ showValue }}</h4>
    </form>
    

    양식 모델을 템플릿 파일에 바인딩하지 않으므로,
    FormArrayremoveAt()push() 메서드를 사용하여 확인란의 상태에 따라 FormControl을 추가하고 삭제를 동적으로 수행합니다.

    ②의 코드



    (form2.component)
    import { Component } from '@angular/core';
    import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
    
    interface Option {
      label: string;
      value: string;
    }
    
    @Component({
      selector: 'app-form2',
      templateUrl: './form2.component.html'
    })
    export class Form2Component {
      readonly animalsOption: Option[] = [
        { label: 'イヌ', value: 'Dog' },
        { label: 'ネコ', value: 'Cat' },
        { label: 'ネズミ', value: 'Rabbit' }
      ];
      ngForm: FormGroup = this.fb.group({
        animals: this.fb.array(this.animalsOption.map(() => this.fb.control(false)))
      });
      showValue: string[] = [''];
    
      get animals(): FormArray {
        return this.ngForm.get('animals') as FormArray;
      }
    
      constructor(private fb: FormBuilder) {}
    
      onSubmit() {
        console.log(this.ngForm);
        this.showValue = this.convertFormValue(this.animals, this.animalsOption);
      }
    
      private convertFormValue(formArray: FormArray, option: Option[]): string[] {
        const values: boolean[] = formArray.value;
        return values
          .map((val, index) => {
            return val ? option[index].value : undefined;
          })
          .filter(v => v);
      }
    }
    
    

    (form2.html)
    <form [formGroup]="ngForm" (ngSubmit)="onSubmit()">
      <div>
        <span formArrayName="animals">
          <label *ngFor="let _ of ngForm.controls.animals.controls; let i = index">
            <input type="checkbox" [formControlName]="i" />
            {{ animalsOption[i].label }}
          </label>
        </span>
      </div>
      <button class="button" type="submit">
        Show Value!
      </button>
      <h4>form2 value -> {{ showValue }}</h4>
    </form>
    

    FormArray 의 값(boolean[])으로 정의한 변환시키고 싶은 배열(animalsOption)을 참조시켜 원하는 값으로 변환시키고 있습니다.

    각각의 소감


  • ①은 템플릿 파일과 폼 모델이 느슨하게 결합된 상태이므로, 체크 조작 이외로 폼의 값을 변경하는 경우(예를 들면 폼의 리셋 조작( reset())에 어려움) 를 사용하고 있기 때문에 가독성이 높다고 느꼈다.
  • ②는 템플릿 파일과 폼 모델이 밀접한 상태이므로 ①과 같은 괴로움이 나오지 않는다. 다만, FormArray의 값을 변환하는 곳이 약간, 써서 기분이 나쁘다. (개선안구합니다)

  • 결론



    코드 베타를 붙이면 이해하기 어려울 것입니다.
    stackblitz에서 위의 양식을 구현했으므로 자세한 동작을 확인하십시오.

    좋은 웹페이지 즐겨찾기