심화 가이드
폼

템플릿 기반 폼 만들기

이 튜토리얼에서는 템플릿 기반 폼을 만드는 방법을 알아봅니다. 폼에 있는 컨트롤 엘리먼트는 입력값의 유효성을 검사하는 데이터 프로퍼티와 바인딩됩니다. 입력값의 유효성을 검사하면 데이터 무결성을 유지할 수 있으며, 검사 결과에 따라 스타일을 적용해서 사용자 경험을 개선할 수 있습니다.

템플릿 기반 폼은 양방향 데이터 바인딩을 사용합니다. 템플릿에서 값이 변경되면 컴포넌트의 데이터 모델에 반영되고, 데이터 모델에서 값이 변경되면 템플릿에 반영됩니다.

템플릿 기반 폼과 반응형 폼

Angular는 사용자 입력을 처리하는 폼을 두 가지 방식으로 지원합니다. 템플릿 기반 폼은 Angular 템플릿에 폼 전용 디렉티브를 사용합니다. 반응형 폼은 모델을 중심으로 폼을 구성합니다.

템플릿 기반 폼은 작거나 간단한 폼을 만들 때 좋습니다. 반응형 폼은 확장하기 쉬워서 복잡한 폼에 적합합니다. 두 방식을 비교하려면 폼 종류 선택하기 문서를 참고하세요.

Angular 템플릿으로 로그인 폼, 연락처 입력 폼, 업무용 폼 등 거의 모든 종류의 폼을 만들 수 있습니다. 컨트롤을 원하는 대로 배치하고 객체 모델의 데이터와 바인딩하면 됩니다. 유효성 검사 규칙을 지정하고 오류를 표시할 수 있으며, 특정 컨트롤의 입력을 조건에 따라 허용하거나 기본으로 제공되는 시각적 피드백을 표시하는 등 다양한 기능을 사용할 수 있습니다.

목표

이 튜토리얼에서는 다음 내용을 알아봅니다.

  • 컴포넌트와 템플릿으로 Angular 폼 만들기
  • ngModel을 사용해서 입력 컨트롤의 값을 읽고 쓰는 양방향 데이터 바인딩 구성하기
  • 컨트롤 상태를 추적하는 CSS 클래스로 시각적 피드백 제공하기
  • 사용자에게 유효성 검사 오류를 표시하고, 폼 상태에 따라 컨트롤 입력을 허용하기
  • 템플릿 참조 변수로 HTML 엘리먼트 사이에서 정보 공유하기

템플릿 기반 폼 구성하기

템플릿 기반 폼은 FormsModule에 정의된 디렉티브를 사용합니다.

디렉티브 설명
NgModel 폼 엘리먼트에서 변경된 값과 데이터 모델에서 변경된 값을 동기화합니다. 이를 활용해서 사용자 입력의 유효성을 검사하고 오류를 처리할 수 있습니다.
NgForm 최상위 FormGroup 인스턴스를 생성하고 <form> 엘리먼트에 바인딩해서 폼 전체의 값과 유효성 상태를 추적합니다. FormsModule을 로드하면 모든 <form> 태그에 이 디렉티브가 기본으로 적용되므로, 별도의 셀렉터를 추가할 필요가 없습니다.
NgModelGroup FormGroup 인스턴스를 생성하고 DOM 엘리먼트에 바인딩합니다.

진행 순서

이 튜토리얼에서는 다음 순서로 예제 폼을 데이터와 바인딩하고 사용자 입력을 처리합니다.

  1. 기본 폼을 만듭니다.
    • 예제 데이터 모델을 정의합니다.
    • FormsModule 등 필요한 구성 요소를 추가합니다.
  2. ngModel 디렉티브와 양방향 데이터 바인딩 문법으로 폼 컨트롤을 데이터 프로퍼티에 바인딩합니다.
    • ngModel이 CSS 클래스로 컨트롤 상태를 표시하는 방식을 확인합니다.
    • ngModel이 컨트롤에 접근할 수 있도록 이름을 지정합니다.
  3. ngModel로 입력값의 유효성과 컨트롤 상태를 추적합니다.
    • 커스텀 CSS를 추가해서 상태에 따른 시각적 피드백을 제공합니다.
    • 유효성 검사 오류 메시지를 표시하거나 숨깁니다.
  4. 표준 HTML 버튼의 클릭 이벤트에 반응해서 모델 데이터를 추가합니다.
  5. 폼의 ngSubmit 출력 프로퍼티로 폼 제출을 처리합니다.
    • 폼이 유효해질 때까지 Submit 버튼을 비활성화합니다.
    • 폼을 제출하면 입력이 끝난 폼 대신 다른 내용을 페이지에 표시합니다.

폼 만들기

  1. 예제 애플리케이션은 폼에 반영할 데이터 모델을 Actor 클래스로 정의합니다.

    actor.ts

    export class Actor {
      constructor(
        public id: number,
        public name: string,
        public skill: string,
        public studio?: string,
      ) {}
    }
  2. 폼의 레이아웃과 세부 내용은 ActorFormComponent 클래스에 정의합니다.

    actor-form.component.ts (v1)

    import {Component} from '@angular/core';
    
    import {Actor} from '../actor';
    import {FormsModule} from '@angular/forms';
    import {JsonPipe} from '@angular/common';
    
    @Component({
      selector: 'app-actor-form',
      templateUrl: './actor-form.component.html',
      imports: [FormsModule, JsonPipe],
    })
    export class ActorFormComponent {
      skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting'];
    
      model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions');
    
      submitted = false;
    
      onSubmit() {
        this.submitted = true;
      }
    
    }

    컴포넌트의 selector 값이 "app-actor-form"이므로, 부모 템플릿에서 <app-actor-form> 태그로 이 폼을 사용할 수 있습니다.

  3. 아래 코드는 처음 표시되는 폼에 배우 예제를 보여주기 위해 배우 인스턴스를 생성합니다.

    const myActress = new Actor(42, 'Marilyn Monroe', 'Singing');
    console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn"

    이 예제에서는 model과 skills에 가상 데이터를 사용합니다. 실제 애플리케이션에서는 데이터 서비스를 주입해서 실제 데이터를 가져오고 저장하거나, 이 프로퍼티를 입력과 출력으로 공개하면 됩니다.

  4. 컴포넌트에서 FormsModule 모듈을 로드하면 폼 기능이 활성화됩니다.

    @Component({
      selector: 'app-actor-form',
      templateUrl: './actor-form.component.html',
      imports: [FormsModule, JsonPipe],
    })
    export class ActorFormComponent {
  5. 폼은 최상위 컴포넌트 템플릿에 정의된 애플리케이션 레이아웃에 표시됩니다.

    app.component.html

    <app-actor-form />

    초기 템플릿은 폼 그룹 두 개와 제출 버튼이 있는 폼 레이아웃을 정의합니다. 두 폼 그룹은 Actor 데이터 모델의 name, studio 프로퍼티에 각각 대응합니다. 각 그룹에는 레이블과 사용자 입력 필드가 있습니다.

    • Name <input> 컨트롤 엘리먼트에는 HTML5 required 어트리뷰트가 있습니다.
    • Studio <input> 컨트롤 엘리먼트에는 없습니다. studio는 선택 사항이기 때문입니다.

    Submit 버튼에는 스타일을 적용하는 클래스가 몇 개 있습니다. 아직까지 폼 레이아웃은 바인딩이나 디렉티브 없이 HTML5로만 구성되어 있습니다.

  6. 예제 폼은 Twitter Bootstrap의 container, form-group, form-control, btn 스타일 클래스를 사용합니다. 이 스타일을 사용하기 위해 애플리케이션 스타일시트에서 라이브러리를 로드합니다.

    styles.css

    @import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');
  7. 폼에서는 ActorFormComponent 내부의 skills 목록에 미리 정의된 항목 중에서 배우의 특기를 선택해야 합니다. Angular @for 반복문으로 데이터 값을 순회해서 <select> 엘리먼트를 구성합니다.

    actor-form.component.html (특기)

    <div class="form-group">
      <label for="skill">Skill</label>
      <select class="form-control" id="skill" required>
        @for (skill of skills; track $index) {
          <option [value]="skill">{{ skill }}</option>
        }
      </select>
    </div>

지금 애플리케이션을 실행하면 선택 컨트롤에 특기 목록이 표시됩니다. 입력 엘리먼트는 아직 데이터 값이나 이벤트와 바인딩되지 않았기 때문에 비어 있으며, 아무 동작도 하지 않습니다.

입력 컨트롤을 데이터 프로퍼티에 바인딩하기

다음으로 입력 컨트롤을 해당하는 Actor 프로퍼티와 양방향 데이터 바인딩합니다. 그러면 사용자 입력이 데이터 모델에 반영되고, 프로그램에서 데이터를 변경하면 화면에도 반영됩니다.

FormsModule에 선언된 ngModel 디렉티브로 템플릿 기반 폼의 컨트롤을 데이터 모델의 프로퍼티에 바인딩할 수 있습니다. 양방향 데이터 바인딩 문법인 [(ngModel)]로 디렉티브를 적용하면, Angular가 컨트롤의 값과 사용자 상호작용을 추적하고 뷰와 모델을 동기화합니다.

  1. 템플릿 파일 actor-form.component.html을 엽니다.
  2. Name 레이블 옆의 <input> 태그를 찾습니다.
  3. 양방향 데이터 바인딩 문법 [(ngModel)]="..."으로 ngModel 디렉티브를 추가합니다.

actor-form.component.html (일부)

<input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" />
TODO: remove this: {{ model.name }}

참고: 이 예제에서는 각 입력 태그 뒤에 확인용 문자열 바인딩 {{model.name}}을 임시로 추가해서 해당 프로퍼티의 현재 값을 표시합니다. 주석에 적힌 대로 양방향 데이터 바인딩의 동작을 확인한 후에는 이 확인용 코드를 삭제하세요.

폼 전체 상태에 접근하기

컴포넌트에서 FormsModule을 로드하면 Angular가 템플릿의 <form> 태그에 NgForm 디렉티브를 자동으로 생성해서 적용합니다. NgForm의 셀렉터가 <form> 엘리먼트와 일치하는 form이기 때문입니다.

NgForm과 폼 전체 상태에 접근하려면 템플릿 참조 변수를 선언하세요.

  1. 템플릿 파일 actor-form.component.html을 엽니다.

  2. <form> 태그에 템플릿 참조 변수 #actorForm을 추가하고, 아래와 같이 값을 지정합니다.

    actor-form.component.html (일부)

    <form #actorForm="ngForm">

    이제 actorForm 템플릿 변수는 폼 전체를 관리하는 NgForm 디렉티브 인스턴스를 참조합니다.

  3. 애플리케이션을 실행합니다.

  4. Name 입력 필드에 값을 입력합니다.

    글자를 입력하거나 삭제하면 데이터 모델에도 글자가 추가되거나 삭제되는 것을 확인할 수 있습니다.

문자열 바인딩으로 값을 표시하는 확인용 코드를 통해 입력 필드의 값이 모델로 전달되고, 다시 화면에 표시되는 것을 확인할 수 있습니다.

컨트롤 엘리먼트에 이름 지정하기

엘리먼트에 [(ngModel)]을 사용하려면 해당 엘리먼트에 name 어트리뷰트를 정의해야 합니다. Angular는 이 이름으로 부모 <form> 엘리먼트에 적용된 NgForm 디렉티브에 엘리먼트를 등록합니다.

예제에서는 <input> 엘리먼트에 name 어트리뷰트를 추가하고 배우의 이름을 의미하는 "name"으로 지정했습니다. 고유한 값이면 무엇이든 사용할 수 있지만, 의미를 알기 쉬운 이름이 좋습니다.

  1. Studio와 Skill에도 같은 방식으로 [(ngModel)] 바인딩과 name 어트리뷰트를 추가합니다.
  2. 문자열 바인딩으로 값을 표시하던 확인용 메시지는 이제 삭제해도 됩니다.
  3. 배우 모델 전체에 양방향 데이터 바인딩이 동작하는지 확인하기 위해 컴포넌트 템플릿 맨 위에 json 파이프를 사용하는 문자열 바인딩을 추가합니다. 이 파이프는 데이터를 문자열로 직렬화합니다.

수정한 폼 템플릿은 다음과 같습니다.

actor-form.component.html (일부)

{{ model | json }}
<div class="form-group">
  <label for="name">Name</label>
  <input
    type="text"
    class="form-control"
    id="name"
    required
    [(ngModel)]="model.name"
    name="name"
  />
</div>

<div class="form-group">
  <label for="studio">Studio</label>
  <input
    type="text"
    class="form-control"
    id="studio"
    [(ngModel)]="model.studio"
    name="studio"
  />
</div>

<div class="form-group">
  <label for="skill">Skill</label>
  <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill">
    @for (skill of skills; track $index) {
      <option [value]="skill">{{ skill }}</option>
    }
  </select>
</div>

다음 내용을 확인해 보세요.

  • 각 <input> 엘리먼트에는 id 프로퍼티가 있습니다. <label> 엘리먼트의 for 어트리뷰트는 이 값을 사용해서 레이블과 입력 컨트롤을 연결합니다. 이는 표준 HTML 기능입니다.

  • 각 <input> 엘리먼트에는 필수인 name 프로퍼티도 있습니다. Angular는 이 값을 사용해서 컨트롤을 폼에 등록합니다.

동작을 확인한 후에는 {{ model | json }} 문자열 바인딩을 삭제해도 됩니다.

폼 상태 추적하기

Angular는 폼이 제출되면 form 엘리먼트에 ng-submitted 클래스를 적용합니다. 이 클래스를 사용해서 제출한 폼의 스타일을 변경할 수 있습니다.

컨트롤 상태 추적하기

컨트롤에 NgModel 디렉티브를 추가하면 컨트롤 상태를 나타내는 클래스 이름이 추가됩니다. 이 클래스로 상태에 따라 컨트롤의 스타일을 변경할 수 있습니다.

Angular가 컨트롤 상태에 따라 적용하는 클래스 이름은 다음과 같습니다.

상태 참일 때 클래스 거짓일 때 클래스
컨트롤에 접근한 적이 있습니다. ng-touched ng-untouched
컨트롤 값이 변경되었습니다. ng-dirty ng-pristine
컨트롤 값이 유효합니다. ng-valid ng-invalid

Angular는 폼이 제출되면 form 엘리먼트에 ng-submitted 클래스도 적용합니다. 다만 form 엘리먼트 안에 있는 컨트롤에는 이 클래스를 적용하지 않습니다.

이 CSS 클래스로 컨트롤 상태에 맞는 스타일을 정의하면 됩니다.

컨트롤 상태 확인하기

Angular가 클래스를 추가하고 삭제하는 모습을 확인하려면 브라우저 개발자 도구를 열고 배우 이름을 입력하는 <input> 엘리먼트를 검사하세요.

  1. 브라우저 개발자 도구에서 Name 입력 필드에 해당하는 <input> 엘리먼트를 찾습니다. 엘리먼트에 "form-control" 외에도 여러 CSS 클래스가 있는 것을 확인할 수 있습니다.

  2. 처음 표시될 때는 값이 유효하고, 초기화하거나 리셋한 후 값이 변경되지 않았으며, 컨트롤에도 접근한 적이 없다는 것을 클래스가 나타냅니다.

    <input class="form-control ng-untouched ng-pristine ng-valid" />
  3. Name <input> 필드에서 다음 동작을 하면서 어떤 클래스가 적용되는지 확인해 보세요.

    • 아무 동작도 하지 않고 상태만 확인합니다. 클래스는 컨트롤에 접근한 적이 없고(untouched), 값이 변경되지 않았으며(pristine), 유효한 상태(valid)를 나타냅니다.

    • 이름 입력 필드 안쪽을 클릭한 다음 바깥쪽을 클릭합니다. 이제 컨트롤에 접근했으므로 엘리먼트의 ng-untouched 클래스가 ng-touched 클래스로 바뀝니다.

    • 이름 끝에 슬래시를 추가합니다. 이제 컨트롤은 접근한 상태(touched)이면서 값이 변경된 상태(dirty)입니다.

    • 이름을 모두 지웁니다. 값이 유효하지 않게 되므로 ng-valid 클래스가 ng-invalid 클래스로 바뀝니다.

상태에 따른 시각적 피드백 제공하기

ng-valid와 ng-invalid 클래스는 특히 유용합니다. 값이 유효하지 않을 때 이를 시각적으로 명확히 알릴 수 있기 때문입니다. 필수 입력 필드도 표시하는 것이 좋습니다.

입력 필드 왼쪽에 색상 막대를 표시하면 필수 입력 필드와 유효하지 않은 데이터를 함께 나타낼 수 있습니다.

다음 순서로 스타일을 변경해 봅시다.

  1. ng-* CSS 클래스의 스타일을 정의합니다.

  2. 새 forms.css 파일에 클래스 정의를 추가합니다.

  3. 프로젝트에서 index.html과 같은 디렉터리에 새 파일을 추가합니다.

    forms.css

    .ng-valid[required], .ng-valid.required  {
      border-left: 5px solid #42A948; /* green */
    }
    
    .ng-invalid:not(form)  {
      border-left: 5px solid #a94442; /* red */
    }
  4. index.html 파일의 <head> 태그에 새 스타일시트를 추가합니다.

    index.html (스타일)

    <link rel="stylesheet" href="assets/forms.css" />

유효성 검사 오류 메시지 표시하고 숨기기

Name 입력 필드는 필수이므로 값을 지우면 막대가 빨간색으로 바뀝니다. 문제가 있다는 것은 알 수 있지만, 사용자는 무엇이 잘못되었고 어떻게 해결해야 하는지 알 수 없습니다. 컨트롤 상태를 확인하고 상태에 맞는 안내 메시지를 제공해 봅시다.

Skill 선택 필드도 필수이지만, 선택할 수 있는 항목이 유효한 값으로 제한되어 있기 때문에 이런 오류 처리가 필요하지 않습니다.

적절한 시점에 오류 메시지가 표시되도록 다음 순서로 구성합니다.

  1. 입력 필드에 지역 참조 추가하기

    input 태그에 템플릿 참조 변수를 추가하면 템플릿 안에서 입력 필드의 Angular 컨트롤에 접근할 수 있습니다. 예제에서는 #name="ngModel" 변수를 사용합니다.

    템플릿 참조 변수(#name)를 "ngModel"로 지정한 이유는 이 값이 NgModel.exportAs 프로퍼티 값이기 때문입니다. 이 프로퍼티는 참조 변수를 디렉티브에 연결하는 방법을 Angular에 알려줍니다.

  2. 오류 메시지 추가하기

    적절한 오류 메시지가 담긴 <div>를 추가합니다.

  3. 조건에 따라 오류 메시지 표시하기

    name 컨트롤의 프로퍼티를 메시지가 담긴 <div> 엘리먼트의 hidden 프로퍼티에 바인딩해서 오류 메시지를 표시하거나 숨깁니다.

  4. actor-form.component.html (오류 메시지 숨기기)

    <div [hidden]="name.valid || name.pristine" class="alert alert-danger">

  5. name에 조건부 오류 메시지 추가하기

    아래 예제와 같이 name 입력 필드에 조건부 오류 메시지를 추가합니다.

    actor-form.component.html (일부)

    <label for="name">Name</label>
    <input
      type="text"
      class="form-control"
      id="name"
      required
      [(ngModel)]="model.name"
      name="name"
      #name="ngModel"
    />
    <div [hidden]="name.valid || name.pristine" class="alert alert-danger">
      Name is required
    </div>

pristine 상태 이해하기

이 예제에서는 컨트롤이 유효하거나 pristine 상태일 때 메시지를 숨깁니다. pristine은 폼에 값이 표시된 후 사용자가 아직 값을 변경하지 않았다는 의미입니다. pristine 상태를 고려하지 않으면 값이 유효할 때만 메시지를 숨기게 됩니다. 이 경우 새로 생성한 빈 배우 데이터나 유효하지 않은 배우 데이터로 컴포넌트를 열면, 사용자가 아무 동작을 하기 전부터 오류 메시지가 표시됩니다.

사용자가 값을 잘못 변경했을 때만 메시지를 표시하고 싶을 수 있습니다. 컨트롤이 pristine 상태일 때 메시지를 숨기면 이렇게 동작합니다. 다음 단계에서 폼에 새 배우를 추가해 보면 이 방식의 의미를 확인할 수 있습니다.

새 배우 추가하기

이번에는 표준 HTML 버튼의 클릭 이벤트에 반응해서 모델 데이터를 추가하는 방법을 알아봅니다. 폼에서 새 배우를 추가할 수 있도록 클릭 이벤트에 반응하는 New Actor 버튼을 추가하겠습니다.

  1. 템플릿의 폼 맨 아래에 "New Actor" <button> 엘리먼트를 추가합니다.

  2. 컴포넌트 파일에서 배우 데이터 모델에 새 배우를 생성하는 메서드를 추가합니다.

    actor-form.component.ts (새 배우 생성 메서드)

    newActor() {
      this.model = new Actor(42, '', '');
    }
  3. 버튼의 클릭 이벤트를 새 배우를 생성하는 newActor() 메서드에 바인딩합니다.

    actor-form.component.html (새 배우 버튼)

    <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button>
  4. 애플리케이션을 다시 실행하고 New Actor 버튼을 클릭합니다.

    폼이 비워지고, 입력 필드 왼쪽의 필수 입력 막대가 빨간색으로 바뀝니다. name과 skill 프로퍼티가 유효하지 않다는 뜻입니다. 오류 메시지는 숨겨져 있는 것을 확인해 보세요. 아직 아무 값도 변경하지 않았으므로 폼이 pristine 상태이기 때문입니다.

  5. 이름을 입력하고 New Actor 버튼을 다시 클릭합니다.

    이제 입력 필드가 pristine 상태가 아니므로 Name is required 오류 메시지가 표시됩니다. 폼은 New Actor 버튼을 클릭하기 전에 이름을 입력했다는 것을 기억합니다.

  6. 폼 컨트롤을 pristine 상태로 되돌리려면 newActor() 메서드를 실행한 뒤 폼의 reset() 메서드를 실행해서 모든 상태 플래그를 명시적으로 초기화합니다.

    actor-form.component.html (폼 초기화)

    <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">
      New Actor
    </button>

    이제 New Actor 버튼을 클릭하면 폼과 컨트롤의 상태 플래그가 모두 초기화됩니다.

ngSubmit으로 폼 제출하기

사용자는 폼을 모두 입력한 후에 제출할 수 있어야 합니다. 폼 맨 아래의 Submit 버튼은 그 자체로는 아무 동작도 하지 않지만, 타입이 type="submit"이기 때문에 폼 제출 이벤트를 발생시킵니다.

이 이벤트를 처리하려면 다음 순서로 진행합니다.

  1. ngOnSubmit 감지하기

    폼의 ngSubmit 이벤트 프로퍼티를 배우 폼 컴포넌트의 onSubmit() 메서드에 바인딩합니다.

    actor-form.component.html (ngSubmit)

    <form (ngSubmit)="onSubmit()" #actorForm="ngForm">
  2. disabled 프로퍼티 바인딩하기

    템플릿 참조 변수 #actorForm으로 Submit 버튼이 포함된 폼에 접근하고 이벤트 바인딩을 구성합니다.

    폼 전체의 유효성을 나타내는 프로퍼티를 Submit 버튼의 disabled 프로퍼티에 바인딩하겠습니다.

    actor-form.component.html (제출 버튼)

    <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">
      Submit
    </button>
  3. 애플리케이션 실행하기

    아직 별다른 기능은 없지만 버튼이 활성화된 것을 확인할 수 있습니다.

  4. Name 값 지우기

    "required" 규칙을 위반했기 때문에 오류 메시지가 표시됩니다. Submit 버튼도 비활성화된 것을 확인해 보세요.

    버튼의 활성화 상태와 폼의 유효성을 연결하는 별도 코드를 작성할 필요는 없습니다. 폼 기능이 적용된 엘리먼트에 템플릿 참조 변수를 정의하고 버튼 컨트롤에서 이 변수를 참조하면, FormsModule이 자동으로 처리합니다.

폼 제출 처리하기

폼을 제출했다는 것을 보여주려면 데이터 입력 영역을 숨기고 그 자리에 다른 내용을 표시하면 됩니다.

  1. 폼 감싸기

    폼 전체를 <div>로 감싸고 hidden 프로퍼티를 ActorFormComponent.submitted 프로퍼티에 바인딩합니다.

    actor-form.component.html (일부)

    <div [hidden]="submitted">
        <h1>Actor Form</h1>
        <form (ngSubmit)="onSubmit()" #actorForm="ngForm">
    
        <!-- ... all of the form ... -->
      </form>
    </div>

    아래 ActorFormComponent 코드에서 확인할 수 있듯이 폼을 제출하기 전까지는 submitted 프로퍼티가 false이므로, 처음에는 폼이 표시됩니다.

    actor-form.component.ts (submitted)

    submitted = false;
    
    onSubmit() {
      this.submitted = true;
    }

    Submit 버튼을 클릭하면 submitted 플래그가 true로 바뀌고 폼이 사라집니다.

  2. 제출 상태 추가하기

    폼을 제출한 상태에서 다른 내용을 표시하려면 폼을 감싼 새 <div> 아래에 다음 HTML을 추가합니다.

    actor-form.component.html (일부)

    <div [hidden]="!submitted">
      <h2>You submitted the following:</h2>
      <div class="row">
        <div class="col-xs-3">Name</div>
        <div class="col-xs-9">{{ model.name }}</div>
      </div>
      <div class="row">
        <div class="col-xs-3">Studio</div>
        <div class="col-xs-9">{{ model.studio }}</div>
      </div>
      <div class="row">
        <div class="col-xs-3">Skill</div>
        <div class="col-xs-9">{{ model.skill }}</div>
      </div>
      <br />
      <button type="button" class="btn btn-primary" (click)="submitted = false">Edit</button>
    </div>

    이 <div>는 문자열 바인딩으로 배우 데이터를 읽기 전용으로 표시하며, 컴포넌트가 제출 상태일 때만 나타납니다.

    새로 표시되는 영역에는 Edit 버튼도 있습니다. 이 버튼의 클릭 이벤트는 submitted 플래그를 해제하는 표현식에 바인딩됩니다.

  3. Edit 버튼 테스트하기

    Edit 버튼을 클릭하면 화면이 다시 수정할 수 있는 폼으로 바뀝니다.

정리

이 문서에서 살펴본 Angular 폼은 다음 프레임워크 기능을 활용해서 데이터를 수정하고 유효성을 검사합니다.

  • Angular HTML 폼 템플릿
  • @Component 데코레이터가 적용된 폼 컴포넌트 클래스
  • NgForm.ngSubmit 이벤트 프로퍼티에 바인딩해서 폼 제출 처리하기
  • #actorForm, #name과 같은 템플릿 참조 변수
  • 양방향 데이터 바인딩을 위한 [(ngModel)] 문법
  • 유효성 검사와 폼 엘리먼트의 변경사항 추적에 사용하는 name 어트리뷰트
  • 컨트롤이 유효한지, 오류 메시지를 표시해야 하는지 확인하는 입력 컨트롤 참조 변수의 valid 프로퍼티
  • NgForm의 유효성 상태에 바인딩해서 Submit 버튼의 활성화 상태 제어하기
  • 유효하지 않은 컨트롤을 사용자에게 시각적으로 알리는 커스텀 CSS 클래스

완성된 애플리케이션 코드는 다음과 같습니다.