안녕하세요! Angular 16을 사용하여 Standalone Components와 라우팅을 활용한 CRUD 기능의 To-do 리스트 애플리케이션을 구축하면서, 각 단계별로 코드의 원리와 작동 방식을 상세히 설명해 드리겠습니다.
이 안내서는 주니어 개발자를 대상으로 하며, 각 부분의 개념과 원리를 이해하는 데 도움이 되도록 구성하였습니다.
Angular CLI(Command Line Interface)는 Angular 애플리케이션을 생성하고 관리하는 데 사용되는 도구입니다. 먼저, 전역으로 설치합니다.
npm install -g @angular/cli
ng new
명령어를 사용하여 새로운 프로젝트를 생성합니다.
ng new todo-app --standalone --routing
todo-app
: 프로젝트 이름입니다.--standalone
: Standalone Components 모드를 활성화합니다.--routing
: 라우팅 기능을 포함합니다.이 명령어를 실행하면 Angular는 프로젝트를 생성하고 필요한 파일들을 설정해줍니다.
cd todo-app
컴포넌트는 Angular 애플리케이션의 기본 구성 요소로, 화면에 표시되는 뷰와 그 동작을 정의합니다.
서비스는 컴포넌트 간에 공통된 기능이나 데이터를 공유하기 위해 사용됩니다. 예를 들어, HTTP 요청을 처리하거나, 공통 로직을 관리합니다.
# To-do 목록 컴포넌트 생성
ng generate component components/todo-list --standalone
# To-do 추가/수정 컴포넌트 생성
ng generate component components/todo-add-edit --standalone
# To-do 서비스 생성
ng generate service services/todo
ng generate component
: 새로운 컴포넌트를 생성합니다.--standalone
: Standalone Component로 생성합니다.ng generate service
: 새로운 서비스를 생성합니다.라우팅은 URL 경로에 따라 적절한 컴포넌트를 로드하여 화면을 전환하는 기능입니다. Single Page Application(SPA)에서 중요한 역할을 합니다.
부트스트랩은 애플리케이션을 시작하는 과정을 말합니다. Angular에서는 루트 컴포넌트를 지정하여 애플리케이션을 부트스트랩합니다.
main.ts
파일 설정// src/main.ts
import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter, Routes } from '@angular/router';
import { AppComponent } from './app/app.component';
import { TodoListComponent } from './app/components/todo-list/todo-list.component';
import { TodoAddEditComponent } from './app/components/todo-add-edit/todo-add-edit.component';
const routes: Routes = [
{ path: '', redirectTo: 'todos', pathMatch: 'full' },
{ path: 'todos', component: TodoListComponent },
{ path: 'todos/add', component: TodoAddEditComponent },
{ path: 'todos/edit/:id', component: TodoAddEditComponent },
];
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
provideHttpClient(),
],
}).catch(err => console.error(err));
provideRouter(routes)
: 라우터에 경로를 제공하여 설정합니다.provideHttpClient()
: HTTP 클라이언트를 제공하여 서비스에서 HTTP 요청을 할 수 있게 합니다.bootstrapApplication(AppComponent, { ... })
: AppComponent
를 루트 컴포넌트로 지정하여 애플리케이션을 부트스트랩합니다.AppComponent
는 애플리케이션의 루트 컴포넌트로, 다른 컴포넌트들이 로드되는 기본 틀을 제공합니다.
// src/app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
template: `<router-outlet></router-outlet>`,
})
export class AppComponent {}
selector: 'app-root'
: 이 컴포넌트의 선택자입니다. index.html에서 <app-root></app-root>
로 사용됩니다.template: '<router-outlet></router-outlet>'
: 라우터 아웃렛을 통해 라우팅된 컴포넌트가 이곳에 표시됩니다.imports: [RouterOutlet]
: RouterOutlet
을 사용하기 위해 임포트합니다.TodoService
는 To-do 항목을 가져오거나, 추가, 수정, 삭제하는 기능을 제공합니다.
// src/app/services/todo.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
export interface Todo {
id?: number;
title: string;
completed: boolean;
}
@Injectable({
providedIn: 'root',
})
export class TodoService {
private apiUrl = 'https://jsonplaceholder.typicode.com/todos';
constructor(private http: HttpClient) {}
// To-do 목록 조회 (최대 10개)
getTodos(): Observable<Todo[]> {
return this.http.get<Todo[]>(`${this.apiUrl}?_limit=10`);
}
// 특정 To-do 조회
getTodoById(id: number): Observable<Todo> {
return this.http.get<Todo>(`${this.apiUrl}/${id}`);
}
// 새로운 To-do 생성
createTodo(todo: Todo): Observable<Todo> {
return this.http.post<Todo>(this.apiUrl, todo);
}
// 기존 To-do 수정
updateTodo(todo: Todo): Observable<Todo> {
return this.http.put<Todo>(`${this.apiUrl}/${todo.id}`, todo);
}
// To-do 삭제
deleteTodo(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
}
@Injectable({ providedIn: 'root' })
: 이 서비스가 애플리케이션 전역에서 사용될 수 있도록 제공됩니다.HttpClient
: HTTP 요청을 보내기 위해 Angular에서 제공하는 클라이언트입니다.Observable<T>
: RxJS의 Observable로, 비동기 데이터 스트림을 처리합니다.TodoListComponent
는 To-do 목록을 표시하고, 추가/수정/삭제 기능을 제공합니다.
// src/app/components/todo-list/todo-list.component.ts
import { Component, OnInit } from '@angular/core';
import { Router, RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { TodoService, Todo } from '../../services/todo.service';
@Component({
selector: 'app-todo-list',
standalone: true,
imports: [CommonModule, RouterModule],
templateUrl: './todo-list.component.html',
})
export class TodoListComponent implements OnInit {
todos: Todo[] = [];
constructor(private todoService: TodoService, private router: Router) {}
ngOnInit(): void {
this.loadTodos();
}
// To-do 목록 로드
loadTodos(): void {
this.todoService.getTodos().subscribe((data) => {
this.todos = data;
});
}
// To-do 추가 페이지로 이동
addTodo(): void {
this.router.navigate(['/todos/add']);
}
// To-do 수정 페이지로 이동
editTodo(id: number): void {
this.router.navigate(['/todos/edit', id]);
}
// To-do 삭제
deleteTodo(id: number): void {
this.todoService.deleteTodo(id).subscribe(() => {
alert('삭제되었습니다.');
this.loadTodos(); // 목록을 새로 고침
});
}
}
todos: Todo[] = []
: To-do 항목을 저장하는 배열입니다.ngOnInit()
: 컴포넌트가 초기화될 때 호출되며, 여기서 To-do 목록을 로드합니다.loadTodos()
: TodoService
를 사용하여 To-do 목록을 가져옵니다.addTodo()
, editTodo(id: number)
: 라우터를 사용하여 다른 페이지로 이동합니다.deleteTodo(id: number)
: To-do 항목을 삭제하고, 목록을 새로 고칩니다.템플릿 파일
<!-- src/app/components/todo-list/todo-list.component.html -->
<div>
<h1>To-do 리스트</h1>
<button (click)="addTodo()">추가하기</button>
<ul>
<li *ngFor="let todo of todos">
<input type="checkbox" [checked]="todo.completed" disabled />
{{ todo.title }}
<button (click)="editTodo(todo.id!)">수정</button>
<button (click)="deleteTodo(todo.id!)">삭제</button>
</li>
</ul>
</div>
<ul>
안에서 *ngFor
디렉티브를 사용하여 todos
배열을 반복합니다.todo.completed
값에 따라 체크박스의 상태를 설정합니다.TodoAddEditComponent
는 To-do를 추가하거나 수정하는 폼을 제공합니다.
// src/app/components/todo-add-edit/todo-add-edit.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { TodoService, Todo } from '../../services/todo.service';
@Component({
selector: 'app-todo-add-edit',
standalone: true,
imports: [CommonModule, FormsModule, RouterModule],
templateUrl: './todo-add-edit.component.html',
})
export class TodoAddEditComponent implements OnInit {
todo: Todo = {
title: '',
completed: false,
};
isEditMode = false;
constructor(
private todoService: TodoService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit(): void {
const idParam = this.route.snapshot.paramMap.get('id');
if (idParam) {
this.isEditMode = true;
const id = Number(idParam);
this.todoService.getTodoById(id).subscribe((data) => {
this.todo = data;
});
}
}
// To-do 저장 (추가 또는 수정)
saveTodo(): void {
if (this.isEditMode) {
this.todoService.updateTodo(this.todo).subscribe(() => {
alert('수정되었습니다.');
this.router.navigate(['/todos']);
});
} else {
this.todoService.createTodo(this.todo).subscribe(() => {
alert('추가되었습니다.');
this.router.navigate(['/todos']);
});
}
}
// 취소하여 목록 페이지로 이동
cancel(): void {
this.router.navigate(['/todos']);
}
}
todo: Todo
: 폼에서 사용되는 To-do 객체입니다.isEditMode
: 현재 모드가 추가인지 수정인지를 나타냅니다.ngOnInit()
: URL에서 id
파라미터를 가져와 수정 모드인지 확인합니다.
saveTodo()
: 현재 모드에 따라 createTodo()
또는 updateTodo()
를 호출합니다.cancel()
: 목록 페이지로 이동합니다.템플릿 파일
<!-- src/app/components/todo-add-edit/todo-add-edit.component.html -->
<div>
<h1>To-do {{ isEditMode ? '수정' : '추가' }}</h1>
<form (ngSubmit)="saveTodo()">
<label>
제목:
<input type="text" [(ngModel)]="todo.title" name="title" required />
</label>
<br />
<label>
완료 여부:
<input type="checkbox" [(ngModel)]="todo.completed" name="completed" />
</label>
<br />
<button type="submit">{{ isEditMode ? '수정하기' : '추가하기' }}</button>
<button type="button" (click)="cancel()">취소</button>
</form>
</div>
[(ngModel)]
: 양방향 데이터 바인딩을 사용하여 폼 필드와 todo
객체를 연결합니다.name
속성은 Angular의 폼 제어를 위해 필요합니다.saveTodo()
메서드가 호출됩니다.ng serve
브라우저에서 http://localhost:4200
으로 접속합니다.
''
이며, 라우팅 설정에서 redirectTo: 'todos'
로 설정했으므로 TodoListComponent
가 로드됩니다.jsonplaceholder.typicode.com
은 테스트용 API로, 데이터 변경이 실제로 저장되지 않습니다. 새로 고침하면 데이터가 초기화될 수 있습니다.이번 안내서에서는 Angular 16에서 Standalone Components와 라우팅을 활용하여 CRUD 기능을 갖춘 To-do 리스트 애플리케이션을 구축하는 과정을 상세히 살펴보았습니다.
provideRouter
를 사용하여 경로를 설정하고, 화면 전환을 구현하였습니다.TodoService
를 통해 컴포넌트 간에 데이터를 공유하고, HTTP 요청을 관리하였습니다.provideHttpClient
를 통해 HTTP 요청을 수행하였습니다.[(ngModel)]
을 사용하여 폼과 모델 간의 데이터를 동기화하였습니다.HttpClient
를 사용하여 백엔드 API와 통신하고, Observable을 통해 비동기 데이터를 처리합니다.ngModel
을 사용하여 사용자 입력과 모델 간의 동기화를 쉽게 처리합니다.
2일차: Angular 16 CLI를 사용해 첫 프로젝트 생성하고 구조 이해하기 (2) | 2024.11.08 |
---|---|
1일차: Angular 16과 프레임워크의 기본 개념 이해하기 (8) | 2024.11.07 |
mac 환경에서 angular 4 앵귤러 프로젝트 만들어보기 (0) | 2017.04.23 |
angularjs 의 sql injection 공격 차단 (0) | 2016.06.03 |
angularjs 의 loading 화면 open source (angular-busy) (0) | 2015.12.06 |