Angular2 Forms
Web Application에 빠질 수 없는 요소가 form입니다. Angular Form요소들을 쉽게 제어할 수 있는 여러 기능들을 제공합니다. 이번에는 Angular가 제공하는 Form 기능의 중 가장 기본적인 내용들을 공유해 보려고 합니다.
이 페이지는 다음의 기능들을 다루고 있습니다.
- 컴포넌트와 템플릿에 Angular form 만들기.
- 인풋 값의 읽기와 쓰기를 위한 two-way 바인딩을 만드는 ngModel 사용하기.
- 상태와 변경을 추적하고, form 컨트롤 유효성 검사하기.
- 컨트롤 상태를 추적하는 CSS 클래스들을 이용해서 view에 표현하기.
- 사용자에게 유효성 검사 에러를 보여주고, 사용/비사용 컨트롤 하기.
- template 참조 변수를 이용하여 HTML 테그 간에 정보 공유하기.
템플릿 기반의 form.
이 페이지에서는 form에 특화된 directives와 명시된 기술을 가지고, Angular template 문법으로 템플릿을 작성하여 form을 만듭니다.
또 다른 방법으로, reactive 접근법(또는 model-driven)을 이용해서 form을 만들 수 있습니다. 하지만, 이 글에서는 template기반의 form에 집중합니다. template-driven 방식은 간단한 form에 대한 검증을 구현하는데 용이합니다.
Angular 템플릿을 사용하면 대부분의 form을 만들 수 있습니다. 로그인, 문의하기, 그외 많은 사업적인 form들을.. Angular를 쓰면 레이아웃을 만들고, 데이터를 바인딩 하고, 특정 유효성 검사를 적용하고, 검사 에러를 보여주고, 활성/비활성을 조절하고, view에 피드백을 보여줄 수 있습니다.
Angular는 반복적인 작업 프로세스를 쉽게 핸들링 할 수 있게 도와줍니다.
여기서 실시간 예제를 보실 수 있으니 함께 테스트하시면 더욱 좋습니다. 실시간 예제를 열어보시면 아래 이미지와 같은 화면을 볼 수 있습니다.

Angular form 만들기
아래는 임의 app/hero-form.component.html
컴포넌트의 템플릿 소스입니다.
1 | <div class="container"> |
소스 안에 form 요소가 있고 form 안에는 input, button등의 form을 구성하는 요소들이 있습니다. 별다를게 없다구요? 네 맞습니다. 당연한 이야기 일 수 있지만 angular의 form은 기본 html form으로 부터 출발합니다. 여기에 angular만의 기능들을 하나하나 추가해 봅시다.
Add powers with *ngFor
이번 주제와는 큰 상관없지만, select
요소를 추가 하기 위에 *ngFor
지시자를 추가하겠습니다. button
테그 위에 아래 소스를 추가합니다.
1 | <div class="form-group"> |
위 소스에서 *ngfor
는, component의 powers
배열 길이만큼 순회하면서 option
테그를 생성하고 value
와 text
에 배열의 각 요소를 바인딩합니다.
two-way 바인딩
위 form에 two-way 바인딩을 만들어 봅시다. two-way 바인딩을 위해서는 ngModel
지시자(directive)를 추가해 줍니다.
1 | <input type="text" class="form-control" id="name" required |
자, 이제 인풋 요소에는 Owen Jeon
이라는 이름이 보입니다. 그리고 input
값을 수정할 때마다 TODO: remove this:
에 동일한 텍스트가 실시간 반영되어 나타납니다.
Angular에서 데이타 바인딩의 방향은 기본적으로 컴포넌트(클래스) -> 템플릿 입니다. two-way 바인딩을 사용하면 템플릿에서 컴포넌트로도 데이터를 바인딩 할 수 있습니다.
즉 위 예제에서 input
값이 수정되면 이 데이터가 컴포넌트로 바인딩 되고, 이 데이터가 다시 템플릿에 바인딩 되어 TODO: remove this:
에 나타나게 되는 것입니다.
two-way 바인딩에 대한 더 자세한 내용은 구글 공식문서를 참고하세요.
<input>
태그에 name
속성을 추가하고 "name"
으로 설정한 것은 다른 의미가 있습니다. [(ngModel)]
을 form
태그와 함께 사용하려면 name
속성을 정의해야합니다.
(다시 말해서, form
태그를 쓰지 않는다면 name
속성은 없어도 잘 동작 합니다.)
내부적으로 Angular는
FormControl
인스턴스를 만들고<form>
태그에 Angular가 첨부한NgForm
지시자(directive)를 등록합니다. 각FormControl
은name
속성에 지정한 이름으로 등록됩니다.
1 | ... |
- 각
input
태그에는,label
태그의 for 속성이 input과 매칭시키는 데 사용하는 id 속성이 있습니다. - 각
input
태그에는 angular의 form 이 가진 컨트롤을 form에 등록하는 데 필요한 name 속성이 있습니다.
위쪽 영역(diagnostic)에 model
의 값들이 반영되어 나타납니다.
Track control state and validity with ngModel
form에 ngModel
를 사용하면 2 way 바인딩 이외에도, 사용자가 컨트롤 영역을 손댔는지(touch), 값이 변경되었는지, 값이 유효성 검사를 통과 했는지 등을 확인 할 수 있습니다.
이는 css class 이름으로 나타나게 됩니다.
상태 | true일때 class | false일때 class |
---|---|---|
컨트롤 영역에 손을 댔음. | ng-touched | ng-untouched |
값 변경됨. | ng-dirty | ng-pristine |
유효성 검사 통과. | ng-valid | ng-invalid |
template의 input에 #spy를 추가합니다. 그러면 spy 변수에 input엘리먼트 객체가 담기게되어, 해당 엘리먼트 프로퍼티에 접근 할 수 있습니다. className프로퍼티를 사용해서 CSS class에 접근해 봅시다.
1 | <input type="text" class="form-control" id="name" |
위 그림을 보면 input을 조작함에 따라 CSS class가 어떻게 바뀌는지 알 수 있습니다.
유효성 검증 메시지 보여주기
form의 기능을 향상시키기 위해서, 에러 메세지를 보여주려고 합니다. 에러 메세지는 사용자가 입력에 반응해, 본인이 잘못 입력하는 것을 바로바로 알려 줄 수 있습니다.
이 효과를 만들기 위해, <input>
테그의 기능을 확장하겠습니다.
- ngModel을 참조하는 변수를 만듭니다.
#name="ngModel"
- input의 유효성 검사가 통과하지 못했을때 보여 줄
<div>
를 만듭니다.
1 | <label for="name">Name</label> |
template 내에서 input box를 제어하려면 template 참조 변수가 필요합니다. 여기서 name이라는 변수를 선언하고 “ngModel”값을 부여했습니다.
왜 “ngModel”일까요? directive의
exportAs
속성은 Angular에게 참조 변수를 directive에 연결하는 방법을 알려줍니다.ngModel
directive의 exportAs 속성이 “ngModel”이기 때문에name
을ngModel
로 설정합니다.
위 로직대로 구현하면, input의 input 값이 수정되지 않은 상태거나, 유효성 검사를 통과했다면 error영역을 감춥니다.
Submit the form with ngSubmit
사용자는 form의 인풋 요소들을 입력하고 나면 제출을 할 것입니다. 하단에 있는 제출 버튼은 그 자체로는 특별한 로직이 보이지 않습니다만, type이 submit으로 설정되어 있어서, form의 제출을 트리거 합니다(type="submit"
).
1 | <form (ngSubmit)="onSubmit(ngForm)" #heroForm="ngForm"> |
form 엘리먼트에 몇가지를 추가했습니다. template 참조 변수인 #heroForm
을 정의하고 값을 “ngForm”으로 초기화했습니다. 변수 heroForm
은 이제 양식 전체를 관리하는 NgForm
directive에 대한 참조입니다.onSubmit
함수를 class에서 받아 form의 값들을 사용할 수 있습니다. 또한 valueChanges
프로퍼티를 이용하면 class에서 form 요소들의 값이 변할때마다 값을 observable로 던저줍니다.
이제 우리는 form의 요소들이 모두 validation을 통과했다면 submit버튼을 보여주고, 아니면 가리고 싶습니다.
1 | <button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button> |
이제 사용자가 Name
을 지우면 submit버튼은 사라집니다.
지금까지 template-driven 기반의 form과 관련된 기능들을 살펴보았습니다. 이후에는 model-driven 기반의 form에 대해서 살펴보겠습니다. model-driven은 검증 로직을 class 내에서 구현하여 view와 js코드간의 구분을 보다 명확히 하고, validation기능을 확장 할 수 있다는 장점이 있습니다.