본문 바로가기

프론트엔드/앵귤러

앵귤러 폼 - 템플릿 드리븐 폼

반응형

 

앵귤러 template-driven form을 설정하는 방법을 보겠습니다.

 

먼저, 폼을 사용하기 위해서는 앵귤러 폼 라이브러리에서 forms 모듈을 가져와야 합니다.

//scr/app/app.module.ts

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

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule // forms module
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

※모듈을 추가를 하지 않으면 아래와 같이 템플릿이나 ts 클래서 파일에서 해당 찾을 수 없습니다.

폼을 사용하고자 하는 템플릿에 아래와 같이 폼을 더합니다.

 

기본폼부터 시작해서 하나씩 추가하며 보겠습니다. 먼저, 템플릿 폼의 기능을 하나도 추가하지 않은 폼은 아래와 같습니다.

<!-- form.component.html -->

<form>
  <div>
    <input type="text">
  </div>

  <div>
    <input type="text">
  </div>

  <div>
    <input type="text">
  </div>

  <button>Submit</button>
</form>

템플릿 폼을 사용하기 위해서는 해당 폼을 forms 모듈과 연결해야 하는데요 연결은 아래와 같이 폼에 템플릿 변수를 생성한 뒤 그 값에 'ngForm'이라는 값을 부여하여 연결합니다.

<!-- form.component.html -->

<form #form="ngForm">
  <div>
    <input type="text">
  </div>

  <div>
    <input type="text">
  </div>

  <div>
    <input type="text">
  </div>

  <button>Submit</button>
</form>

해당 폼에 서밋 이벤트를 더해 템플릿 폼 객체를 확인해 보겠습니다. 아래와 같이 서밋 이벤트를 연결하고 매개변수에 폼의 템플릿 변수명을 추가합니다.

<!-- form.component.html -->

<form #form="ngForm" (submit)="onSubmit(form)">
  <div>
    <input type="text">
  </div>

  <div>
    <input type="text">
  </div>

  <div>
    <input type="text">
  </div>

  <button>Submit</button>
</form>

그리고 해당 템플릿 클래스에 아래와 같이 해당 function을 매개변수와 함께 추가합니다. 매개변수로 들어오는 값의 타입은 'NgForm'으로 forms 모듈에서 옵니다.

/** form.component.ts */

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms'; // forms module

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

  constructor() { }

  ngOnInit(): void {
  }

  onSubmit(form: NgForm) {
    console.log(form)
  }
}

이후 템플릿에서 제출을 클릭하면 아래와 같이 제출된 폼을 확인 가능합니다. 보이는 것처럼 객체 안에는 value, status, errors, touched 등 활용가능한 다양한 속성들이 제공됩니다. controls는 폼에 포함된 각각의 input이라고 생각하면 되는데 지금은 input을 해당 폼의 컨트롤로 연결하는 작업을 하지 않았기 때문에 보시는 것처럼 빈 객체로 표시됩니다.

해당 폼에 컨트롤로 연결하기 위해서는 'name' 속성과 'ngModel' 속성 두 가지 필요한데요. 'name' 속성은 해당 컨트롤의 이름을 지정하여 판별할 수 있게 해 주고 'ngModel' 속성은 폼과 연결하는 기능을 합니다. 둘 중 하나라도 생략되는 컨트롤로 인식되지 않습니다.

<!-- form.component.html -->

<form #form="ngForm" (submit)="onSubmit(form)">
  <div>
    <input type="text" name="name" ngModel>
  </div>

  <div>
    <input type="text" name="phone" ngModel>
  </div>

  <div>
    <input type="text" name="email" ngModel>
  </div>

  <button>Submit</button>
</form>

위와 같이 추가 한 뒤 다시 제출해 보면 아래와 같이 연결된 컨트롤을 확인할 수 있습니다.

그럼 제약조건을 추가해 보겠습니다. template-driven 폼은 템플릿에 제약조건을 설정하는데요. 일반적인 html에서 제공하는 제약조건을 추가하는 것과 비슷합니다. 가장 기본적인 'required' 제약조건을 추가해 보겠습니다.

<!-- form.component.html -->

<form #form="ngForm" (submit)="onSubmit(form)">
  <div>
    <input type="text" name="name" ngModel required>
  </div>

  <div>
    <input type="text" name="phone" ngModel required>
  </div>

  <div>
    <input type="text" name="email" ngModel required>
  </div>

  <button>Submit</button>
</form>

제약조건을 추가 후 제출하게 되면 아래와 같이 'status'가 'INVALID'라고 뜹니다.

이러한 기능을 활용하여 다양한 구현이 가능한데요 그럼 템플릿 폼을 활용하여 제약조건과 에러 메시지를 포함한 간단한 폼을 만들어 보겠습니다.  

 

<!-- form.component.html -->

<form #form="ngForm" (submit)="onSubmit(form)">
  <div>
    <input type="text" name="name" ngModel required #name="ngModel">    
  </div>

  <div>
    <input type="text" name="phone" ngModel required #phone="ngModel">    
  </div>

  <div>
    <input type="text" name="email" ngModel required #email="ngModel">    
  </div>

  <button>Submit</button>
</form>

각 컨트롤의 제약조건에 맞는 에러메시지를 조건과 함께 추가하여 제약조건에 어긋날 때 에러메시지를 표시합니다. 아래에서 'touched'라는 조건을 추가하였는데 이는 에러의 여부만 조건으로 사용하면 최초 필수항목에 값이 없으므로 에러값이 참으로 반환되어 사용자가 입력을 시도하기 전에 메시지가 표시되어 사용자가 불편함을 느낄 수 있기 때문입니다.

<!-- form.component.html -->

<form #form="ngForm" (submit)="onSubmit(form)">
  <div>
    <input type="text" name="name" ngModel required #name="ngModel">
    <div *ngIf="name.touched && name.errors?.['required']">name required</div>    
  </div>

  <div>
    <input type="text" name="phone" ngModel required #phone="ngModel">
    <div *ngIf="phone.touched && phone.errors?.['required']">phone required</div>
  </div>

  <div>
    <input type="text" name="email" ngModel required #email="ngModel">
    <div *ngIf="email.touched && email.errors?.['required']">email required</div>
  </div>

  <button>Submit</button>
</form>

※에러메시지는 아래와 같이 'invalid'를 사용하여 구현도 가능하나 제약조건이 여러 개인 경우 에러메시지를 구분하여 표현하기 힘들기 때문에 위의 방법을 추천합니다.

<!-- form.component.html -->

<form #form="ngForm" (submit)="onSubmit(form)">
  <div>
    <input type="text" name="name" ngModel required #name="ngModel">
    <div *ngIf="name.touched && name.invalid">name required</div>    
  </div>

  <div>
    <input type="text" name="phone" ngModel required #phone="ngModel">
    <div *ngIf="phone.touched && phone.invalid">phone required</div>
  </div>

  <div>
    <input type="text" name="email" ngModel required #email="ngModel">
    <div *ngIf="email.touched && email.invalid">email required</div>
  </div>

  <button>Submit</button>
</form>

이후 클래스 파일에서 아래와 같이 폼의 상태를 확인하고 처리하는 코드를 작성 가능합니다.

/** form.component.ts */

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

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

  constructor() { }

  ngOnInit(): void {
  }

  onSubmit(form: NgForm) {
    if(form.valid) {
      console.log(form)
      // add an action when form is valid
    }
    form.resetForm()
  }
}

이상으로 앵귤러 폼 - Template-driven form에 대해서 알아보았습니다.

 

728x90
반응형