위의 튜토리얼은 https://angular.io/tutorial 을 참고하였습니다.
1) Edit the hero
input 태그를 통해서 유저가 히어로의 이름을 수정할 수 있도록 하고 싶습니다.
- hero의 이름을 보여주는 기능
- 유저가 타이핑한 프로퍼티를 업데이트하는 기능
두 가지를 동시에 수행해야 합니다.
즉, 기존에는 component class
에서 화면(screen)으로의 일방적인 렌더링을 수행했다면,
이번 기능을 위해서는 화면의 input 태그에 기록된 값이 component class 에 반영되어야 하므로,
화면과 component class가 양방향으로 연결되어야 하는데, 이것을 Two way binding이라고 합니다.
1-1. Two-way binding
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name">
</label>
</div>
[(ngModel)]
: two-way binding을 하는 문법
input 태그의 값을 변경시키면, 바인딩하고 있는 hero.name의 값도 변경됩니다.
1-2. The missing FormsModule
그런데 [(ngModel)]
을 적은 다음에 이런 에러가 발생할 수도 있습니다.
Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'.
브라우저 내부에서 ngModel을 인식할 수 없다는 뜻인데요.
왜냐하면 ngModel
은 built-in directive 는 아니기 때문입니다.
(인풋 태그에서 기본적으로 지정한 attribute가 아니라는 뜻)
이녀석은 FormsModule
의 소속이므로 사전동의(?)를 받아야 정상적으로 사용할 수 있습니다.
도대체 FormsModule는 뭘까요? 일단 그 이전에 AppModule에 대해서 알아봅시다.
2-3. AppModule
Angular는 앱이 필요한 라이브러리들이나 파일들을 지속적으로 체크합니다.
그것들을 metadata라고 부르는데요.
위에서 보았던 @Component 데코레이터를 통해서도 메타데이터를 표현했었는데요. @NgModule 데코레이터는 앱이 요청한 라이브러리 정보들을 표현합니다.
그 중에서도 가장 중요한 라이브러리 정보들은 보통 앱의 top-level AppModule class에서
선언하는 경우가 많습니다.
root level의 AppModule class에서 라이브러리의 일부인 FormsModule을 임포트해봅시다.
2-4. Import FormsModule
// app.module.ts
import {FormsModule} from '@angular/forms';
@angular/forms 라이브러리에서 FormsModule 심볼을 임포트합니다.
imports : [
BrowerModule,
FormsModule
]
그 이후에는 FormsModule을 @NgModule 의 메타데이터를 표현하는 imports라는 배열에 추가해줍시다.
imports 배열은 앱이 필요한 external module들을 의미합니다.
2-5. Declare HerosComponent
사실 우리가 자연스럽게 사용하는 컴포넌트들도 일종의 모듈입니다.
그렇기 때문에, 컴포넌트를 사용하기 위해서는 불러와야 하는데, 컴포넌트는 위의 FormsModule과는 달리 외부 모듈은 아니므로,
따로 구분해서 @NgModule의 declarations에 넣어줘야 합니다.
// app.module.ts
import { HeroesComponent } from './heroes/heroes.component';
역시 선언도 declarations 배열을 통해서 되어 있습니다.
// app.module.ts
@NgModule({
declarations: [
AppComponent,
HeroesComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
그런데, 일일이 app-heroes 라는 컴포넌트를 선언하지 않았는데도 정상적으로 작동되었던 이유는, Angular CLI가 똑똑해서 컴포넌트를 생성할 때 자동으로 임포트를 해주기 때문입니다.