반응형

qpp.module.ts 에서 imports에 - ReactiveFormsModule추가하기

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

 

이미지 처럼 3개의 필드가 있는 모양을 TypeScript를 이용하여 만들것입니다.


FormGroup 생성하기.

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  genders = ['male', 'female'];
  signupForm: FormGroup;

  ngOnInit() {
    // initialize 
    this.signupForm = new FormGroup({
      'username': new FormControl(null),
      'email': new FormControl(null),
      'gender': new FormControl('male')
    });
  }
}

FormGroup에 각 항목 마다 key-value pair로 값을 지정해 줍니다.

key = 항목 명

value = FormControl객체


HTML Input과 바인딩(syncronize)하기

<form>
  <div class="form-group">
    <label for="username">Username</label>
    <input
      type="text"
      id="username"
      class="form-control">
    </div>
    <div class="form-group">
    <label for="email">email</label>
    <input
      type="text"
      id="email"
      class="form-control">
    </div>
    <div class="radio" *ngFor="let gender of genders">
    <label>
      <input
        type="radio"
        [value]="gender">{{ gender }}
    </label>
  </div>
  <button class="btn btn-primary" type="submit">Submit</button>
</form>

 

HTML에 directive를 오버라이드 합니다. - <form>태그에 formGroup 연결

<form [formGroup]="signupForm">

위에서 선언한 signForm을 formGorup속성으로 넣어줍니다.

 

각 항목마다 formControlName을 사용하여, Angular에게 내가 사용하는 typeScript의 input 이름을 알려줍니다.

<input
  type="text"
  id="username"
  class="form-control"
  formControlName="username">

물론 속성 값으로   [formControlName]="'username'" 를 사용해도 됩니다. string을 전달해야 하기 떄문에 ""안에 ''를 넣어야 합니다.

 

브라우저로 들어가 제대로 매칭이 되었는지 확인해 봅니다.

그림과 같이 ng-untouched와 같은 클래스가 있습니다.

개발 도구를 이용하면 ng로 시작하는 클래스가 있음으로, type스크립트가 작동한다는 것을 알 수 있습니다.


Validation 추가하기 - formControl 생성시 2번째 argu.에 추가합니다.

this.signupForm = new FormGroup({ //first: default Value, second: validation
      'username': new FormControl(null, Validators.required),
      'email': new FormControl(null, [Validators.required, Validators.email]),
      'gender': new FormControl('male')
    });

[]를 이용하여 복수의 validation을 추가합니다.

 

HTML에 안내 문 추가 하기

<span 
  *ngIf="!signupForm.get('username').valid && signupForm.get('username').touched"
  >Please enter a valid username!</span>

signupForm 객체에 들어가 valid, touched와 같은 validation 값에 접근할 수 있습니다.

 

구릅핑 하기 - Form Group

ts파일에 userData로 그릅핑 하겠습니다. - nested Group

'userData': new FormGroup({
  'username': new FormControl(null, Validators.required),
  'email': new FormControl(null, [Validators.required, Validators.email])
}),      

html도 같이 변경해 주어야 합니다.

<div formGroupName="userData">
	... <!-- username과 email <input> -->
</div>

validation도 역시 다르게 접근해야 합니다.

<span *ngIf="!signupForm.get('userData.username').valid && signupForm.get('userData.username').touched">...</span>

폼 컨트롤 어레이 추가하기 - FormArray

 

사용자가 원하는 만큼 text항목을 추가합니다. 

취미 리스트나 todo list에 사용할 수 있습니다.

 

ts에서 formGroup에 FormArray를 추가합니다.

this.signupForm = new FormGroup({
  'userData': new FormGroup({
    'username': new FormControl(null, Validators.required),
    'email': new FormControl(null, [Validators.required, Validators.email])
  }),      
  'gender': new FormControl('male'),
  'hobbies': new FormArray([])
});

hobbies라는 FormArray를 빈 상태로 추가합니다. - 취미가 없는 사람이 있을 수 있기 때문입니다.

<div formArrayName="hobbies">
  <h4>Youre Hobbies</h4>
    <button 
    class="btn btn-default"
    type="button"
    (click)="onAddHobby()">Add Hobby</button>
      <div 
      class="form-group"
      *ngFor="let hobbyContrl of signupForm.get('hobbies').controls; let i = index">
      <input type="text" class="form-control" [formControlName]="i">
  </div>
</div>

HTML에 formArrayName으로 바인딩 합니다.

onAddHobby라는 매쏘드로 사용자에게 반응합니다.

 

몇개의 취미가 있을지 모르기 때문에 ngFor을 이용하여 FormArray에 값을 추가합니다.

 

<Add Hobby 버튼>을 누를때 마다 onAddHobby()매쏘드가 작동하여 FormControl push합니다.

onAddHobby() {
  const control = new FormControl(null, Validators.required);
  (<FormArray>this.signupForm.get('hobbies')).push(control);
}

 

ngFor에 의하여 <input type="text"> 가 나타납니다.

생성과 동시에 formControlName의 매칭을 추가해야 하기 때문에, [formControlName]="i"를 사용합니다.

[]로 속성으로 만들어야 "i" index를 formControlName으로 줄 수 있기 때문입니다.


Custom Validators

특정 username을 사용하지 못하도록 합니다.

 

변수를 사용하여 지정합니다.

forbiddenUsernames = ['Chris', 'Anna'];

매쏘드를 만듭니다.

forbiddenNames(control: FormControl): {[s: string]: boolean} {
  if(this.forbiddenUsernames.indexOf(control.value) !== -1) return {'nameIsForbidden': true};
  return null;
}

foo(argu): {[s: string]:boolean} {} 

foo(argu)뒤에 오는 :{...}은 반환인자 입니다.

foo(): {} foo() 매쏘드는 구조체를 반환합니다.

key/value pair를 반환합니다.

key는 string이고, value는 boolean 입니다.


Indexable Types

...더보기

위 indexable Types 링크를 누르면 이전에 어떻게 interface를 사용할 수 있는지 나와있습니다.

a[10], ageMap["daniel"] 처럼 "index into"로 타입을 기술 할 수 있습니다.

Indexable(색인가능한) 타입은 객체에 색인할 수 있도록하는 인덱스 특징(index signature 이하 인덱스 특징)을 갖고 있으며, 인덱싱 할 때 객체와 상응하는 리턴 타입이 함께합니다. 아래 예제를 보겠습니다.

interface StringArray {
    [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

위쪽, StringArray 인터페이스는 하나의 인덱스 특징을 갖고 있습니다.
이 인덱스 서명은 StringArray가 number로 인덱싱 되어있음을 나타내고, string을 반환한다고 보여주고 있습니다.


forbiddenUsernames의 index를 돌면서 해당 FormControl의  값을 찾습니다.

존재하지 않으면 -1을 반환하는 indexOf를 이용하기떄문에 !== -1를 이용하여 true, false를 결정합니다.

 

forbiddenNames를 호출할 당시의 this는 우리가 생각하는 this가 아니므로 작동하지 않습니다.

'username': new FormControl(null, [Validators.required, this.forbiddenNames.bind(this)]),

validator를 추가할때 bind(this)를 넘겨주는 꼼수을 사용합니다.


Async Vaildator

HTTP 통신을 통해서 Valid 여부를 확인 할 수 있습니다.

 

서버의 응답을 처리할 때 사용하는 기능입니다. 

  static asyncInvalidProjectName(control: FormControl): Promise<any> | Observable<any> {
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        if (control.value === 'Testproject') {
          resolve({'invalidProjectName': true});
        } else {
          resolve(null);
        }
      }, 2000);
    })
    return promise;
  }

 

setTimeout()를 서버에서 응답으로 가정했습니다.

반응형

'프로그래밍 > Angular' 카테고리의 다른 글

Pipe  (0) 2019.08.15
Form - 복습 및 보충 내용  (0) 2019.08.14
Handling Form - Template Driven  (0) 2019.07.02
Observable & Subject  (0) 2019.06.26
Router 정리  (0) 2019.06.25

+ Recent posts