모듈(Module)
모듈
세부 구현이 숨겨지고 공개 API를 이용해 다른 코드에서 재사용 가능한 코드를 말한다. (예를 들어 리모컨)
ES6에서의 모듈
ES6에서는 모듈 개념 + 변수의 스콥이 모듈로 제한된다. 스코프가 모듈 내로 제한된다는 의미는 각각 파일들이 하나의 모듈이 되는 것이며, 각각 파일에서 정의가 된 변수들은 파일 안에서 스콥이 보장된다. 따라서 각 파일에 있는 기능을 쓰려면 export, import 작업을 해야 한다.
앵귤러에서의 모듈
컴포넌트, 파이프, 서비스 등과 같은 앵귤러 애플리케이션의 주요 부분을 기능 단위로 그룹핑하게 해 준다.
- 모든 앵귤러 애플리케이션은 하나의 Root Module을 가진다. (ex. app.module.ts)
- 여러 Feature Module을 가질 수 있다.
- 재사용할 수 있는 기능을 외부에 배포하기 위해 사용되기도 한다. (ex. 메테리얼 디자인의 MdButtionModule, 부트스트랩의 ModalModule)
컴포넌트(Component)
앵귤러 애플리케이션은 여러 컴포넌트로 구성되어 있으며, 애플리케이션에서 가장 중요한 구성 요소이다. 여러 html 요소들이 한 컴포넌트에 그룹화되어 있다.
- 빌딩 블록(레고)
- HTML 요소들의 그룹
- 뷰(템플릿)와 로직으로 구성되어 있음!
TODO 리스트 예제 만들기
1. 모듈 생성
모듈명이 todo인 모듈을 생성한다. src/app/todo/todo.module.ts 파일이 생성된다.
ng generate module todo
# 또는 약어 사용가능
ng g m todo
이어서 todo 모듈 내부에 todos 컴포넌트를 생성한다. 이때 --module 플래그로 특정 모듈을 직접 지정가능한데 todo.module.ts 파일을 직접 지정했다. 또한 todo 컴포넌트는 다른 데서 사용할 수 있다는 의미로 --export 플래그를 추가한다. ( todo 컴포넌트도 export를 하기 때문에 ES6 모듈이 된다)
ng generate component todo/todos --module todo/todo.module.ts --export
# 또는 약어 사용가능
ng g c todo/todos --module todo/todo.module.ts --export
즉 아래처럼 명령어를 입력하면 총 5개의 파일이 생성된다.
최종적으로 모듈 파일 1개와 컴포넌트 관련 파일 4개가 생성된 것을 확인할 수 있다.
이제 todo 관련 내용으로 변경하기 위해 소스를 변경한다. app.component.ts 파일이 아닌 todos.component.ts 파일 내용으로 보이도록 변경할 것이다.
src/app/app.component.html 파일에서 Todo 셀렉터로 변경한다.
<app-todos></app-todos>
src/app/app.module.ts 파일에서 TodoModule 모듈을 추가한다.
// 생략...
import { TodoModule } from './todo/todo.module'; // Todo 모듈 추가
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
TodoModule // Todo 모듈 추가
],
//...
})
export class AppModule { }
여기까지 진행하면 todo 컴포넌트로 대체되어 보인다.
2. 샘플용 파일 작성
src/app/todo/todos/todos.component.html 파일에서 정적인 html 파일을 작성한다. 이 파일을 기준으로 컴포넌트 분리해 볼 것이다.
<div class="title">
<h1>나의 일정</h1>
<h2>3월 19일</h2>
</div>
<div>
<div>
<input type="checkbox">운동하기
</div>
<div>
<input type="checkbox">공부하기
</div>
</div>
<div>
<input type="text" placeholder="할 일 추가">
</div>
서버 실행 시 정적인 html 파일 내용이 보인다.
3. 템플릿(Template) 이해하기
앵귤러에서 템플릿은 HTML 코드로서 템플릿을 표현한다. Template 표현식과 Template 문장을 가진다.
템플릿에서 가장 많이 이루어지는 게 특정 대상을 바인딩하는 것이다. 바인딩(Binding)은 컴포넌트 클래스의 속성과 데이터를 실제 브라우저 도큐먼트 오브젝트인 DOM의 속성과 이벤트와 연결하는 것이다.
바인딩은 크게 단방향, 양방향으로 분류할 수 있다. (아래 사진 화살표 참고) 바인딩의 대상으로는 속성, 이벤트, ngModel, class, style이 있다.
4. 단방향 바인딩 사용하기 (컴포넌트 -> DOM)
src/app/todo/todos/todos.component.ts 파일에서 단방향 바인딩을 사용하기 위해 todos 배열 객체를 생성한다.
// 생략...
export class TodosComponent {
todos: {
done: boolean,
text: string
}[]
constructor() {
this.todos = [
{ done: false, text: '운동하기' },
{ done: true, text: '공부하기' },
]
}
}
src/app/todo/todos/todos.component.html 파일에서 todos 객체를 {{ }} 표현식을 이용하여 바인딩한다.
<div class="title">
<h1>나의 일정</h1>
<h2>3월 19일</h2>
</div>
<div>
<div>
<input type="checkbox" [checked]="todos[0].done">{{ todos[0].text }}
</div>
<div>
<input type="checkbox" [checked]="todos[1].done">{{ todos[1].text }}
</div>
</div>
<div>
<input type="text" placeholder="할 일 추가">
</div>
위 소스의 Todo 목록을 *ngFor 문법을 이용하여 반복문으로 변경한다.
<div class="title">
<h1>나의 일정</h1>
<h2>3월 19일</h2>
</div>
<div>
<div *ngFor="let todo of todos">
<input type="checkbox" [checked]="todo.done">{{ todo.text }}
</div>
</div>
<div>
<input type="text" placeholder="할 일 추가">
</div>
여기까지 진행한다면 결과는 아래처럼 나온다.
5. 단방향 바인딩 사용하기 (DOM -> 컴포넌트)
src/app/todo/todos/todos.component.html 파일에서 반복문 부분에 클릭 이벤트인 toggleTodo 메서드를 설정한다.
<div *ngFor="let todo of todos" (click)="toggleTodo(todo)">
<input type="checkbox" [checked]="todo.done">{{ todo.text }}
</div>
src/app/todo/todos/todos.component.ts 파일에서 toggleTodo 메서드 생성한다.
export class TodosComponent {
// 생략...
toggleTodo(todo: any) {
todo.done = !todo.done
}
}
6. 양방향 바인딩 사용하기 (ngModel)
src/app/todo/todos/todos.component.html 파일에서 [할 일 추가] 버튼에 ngModel 바인딩 처리 및 추가 버튼을 생성한다.
<div>
<input type="text" placeholder="할 일 추가" [(ngModel)]="newText">
<button (click)="addTodo(newText)">추가</button>
</div>
ngModel를 사용하기 위해서는 src/app/todo/todo.module.ts 파일에서 FormModule을 import 해야 한다.
// 생략...
import { FormsModule } from '@angular/forms';
@NgModule({
// 생략...
imports: [
CommonModule,
FormsModule // NgModule을 사용하기 위해 추가
],
})
src/app/todo/todos/todos.component.ts 파일에서 newText 변수와 addTodo 메서드를 생성한다.
// 생략...
export class TodosComponent {
newText: string = '';
addTodo(newText: string) {
this.todos.push({
done: false,
text: newText
});
this.newText = '';
}
}
결과는 아래와 같다. 입력란에 일정을 추가하면 새롭게 일정이 추가된다.
파이프
마지막으로 화면에 보이는 하드코딩된 날짜를 바꿔보자. 파이프는 템플릿에서 보이는 데이터를 변환해준다. 앵귤러 1 버전에서는 필터로 제공했다. 참고로 예제에서 {{ todos | json }} 으로 확인하면
- 파이프 형식 : {{ express | pipeName: paramValue }}
- ex. {{ today | date }}
- ex. {{ today | date : "yy/mm/dd" }}
- ex. {{ today | date | uppercase }}
src/app/todo/todos/todos.component.html
<div class="title">
<h1>나의 일정</h1>
<h2>{{ today | date : 'M월 d일'}}</h2>
</div>
여기까지의 최종 소스
src/app/todo/todos/todos.component.html
<div class="title">
<h1>나의 일정</h1>
<h2>{{ today | date : 'M월 d일'}}</h2>
</div>
<div>
<div *ngFor="let todo of todos" (click)="toggleTodo(todo)">
<input type="checkbox" [checked]="todo.done">{{ todo.text }}
</div>
</div>
<div>
<input type="text" placeholder="할 일 추가" [(ngModel)]="newText">
<button (click)="addTodo(newText)">추가</button>
</div>
src/app/todo/todos/todos.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrl: './todos.component.css'
})
export class TodosComponent {
newText: string = '';
todos: {
done: boolean,
text: string
}[]
constructor() {
this.todos = [
{ done: false, text: '운동하기' },
{ done: true, text: '공부하기' },
]
}
toggleTodo(todo: any) {
todo.done = !todo.done
}
addTodo(newText: string) {
this.todos.push({
done: false,
text: newText
});
this.newText = '';
}
}