Skip to content

1. Angular 소개


이 문서는 Angular를 이해하기 위한 기본 내용을 다룬다. Angular는 무엇인지, 사용하면 어떤 점이 좋은지, 애플리케이션을 어떻게 시작할 수 있는지 확인해 보자.


Angular는 TypeScript를 기반으로 개발된 개발 플랫폼이다. 플랫폼이면서 동시에:


  • 확장가능한 컴포넌트 구조로 웹 애플리케이션을 만드는 프레임워크이다.
  • 라우팅, 폼 관리, 클라이언트-서버 통신 등 웹 개발에 필요한 라이브러리를 조화롭게 통합한 모음집이다.
  • 애플리케이션 개발, 빌드, 테스트, 수정에 필요한 개발자 도구를 제공한다.


Angular는 혼자 개발하는 프로젝트는 물론이고 기업용 애플리케이션에도 활용할 수 있다. 그리고 최신 기술을 쉽게 도입할 수 있도록 설계되었기 때문에 적은 노력으로 큰 생산성 향상을 낼 수도 있다. 무엇보다도, Angular 생태계에 함께하는 개발자, 라이브러리 개발자, 컨텐츠 작성자는 총 170만명 이상에 달한다.


Note


1. Angular 애플리케이션: 기초

이 섹션에서 Angular의 기본 개념에 대해 알아보자. 애플리케이션을 효율적으로 설계하고 구현하려면 이 개념들을 제대로 알고 있는 것이 좋다.


1) 컴포넌트(Component)

컴포넌트는 애플리케이션을 구성하는 기본 단위이다. 컴포넌트는 @Component 데코레이터가 붙는 TypeScript 클래스, HTML 템플릿, 스타일로 구성된다. @Component() 데코레이터는 다음과 같이 Angular에 필요한 정보를 지정하는 역할을 한다:


  • 컴포넌트가 템플릿에 사용될 CSS 셀렉터를 지정한다. 템플릿에서 이 셀렉터에 해당되는 HTML 엘리먼트마다 컴포넌트 인스턴스가 생성된다.
  • Angular가 컴포넌트 내용으로 렌더링할 HTML 템플릿을 지정한다.
  • 템플릿 HTML 엘리먼트의 모습을 지정해야 한다면 이 때 필요한 CSS 스타일을 지정한다.


기본 내용만 담아 Angular 컴포넌트를 만들어보면 이렇게 구성할 수 있다.


import { Component } from "@angular/core";

@Component({
  selector: "hello-world",
  template: `
    <h2>Hello World</h2>
    <p>This is my first component!</p>
  `,
})
export class HelloWorldComponent {
  // 여기에는 컴포넌트의 동작을 정의하는 코드가 들어갑니다.
}


이 컴포넌트를 사용하려면 템플릿에 이런 코드를 추가하면 된다:


<hello-world></hello-world>


Angular가 컴포넌트를 렌더링하고 나면 DOM이 이렇게 된다:


<hello-world>
  <h2>Hello World</h2>
  <p>This is my first component!</p>
</hello-world>


Angular 컴포넌트는 강력하게 캡슐화되어 있지만 애플리케이션 구조에 맞게 직관적으로 구성된다. 컴포넌트를 사용하면 애플리케이션에 유닛 테스트를 적용하기 쉽고, 코드의 가독성도 높일 수 있다.


Note

  • 컴포넌트가 어떤 역할을 하는지 더 자세하게 알아보려면 컴포넌트 문서를 참고한다.


2) 템플릿(Templates)

컴포넌트는 이 컴포넌트가 어떻게 렌더링될지 정의하기 위해 HTML 템플릿이 존재한다. 템플릿은 인라인으로 정의하거나 별도 파일로 작성해서 불러올 수 있다.


템플릿은 HTML 문법을 기본으로 작성하며 컴포넌트에 있는 값을 동적으로 반영하도록 구성한다. 그래서 컴포넌트의 상태가 변경되면 Angular가 자동으로 렌더링된 DOM을 갱신한다. 아래 예제 코드는 문자열을 동적으로 렌더링하는 컴포넌트의 템플릿 코드이다:


<p>{{ message }}</p>


이 문자열은 컴포넌트 클래스에서 전달된다:


import { Component } from "@angular/core";

@Component({
  selector: "hello-world-interpolation",
  templateUrl: "./hello-world-interpolation.component.html",
})
export class HelloWorldInterpolationComponent {
  message = "Hello, World!";
}


애플리케이션이 컴포넌트와 템플릿을 로드하고 나면 사용자가 이런 화면을 볼 수 있다:


<p>Hello, World!</p>


템플릿에 이중 중괄호({{, }})가 사용된 것을 확인해 보자. 이 문법은 템플릿에 문자열을 바인딩(interpolation)하는 문법이다.


문자열 바인딩 외에도, Angular는 HTML 엘리먼트의 프로퍼티나 어트리뷰트에 값을 할당하는 프로퍼티 바인딩(property binding) 문법도 제공한다:


<p [id]="sayHelloId" [style.color]="fontColor">
  You can set my color in the component!
</p>


대괄호([, ])가 사용된 것을 확인해 보자. 이 문법은 컴포넌트 클래스에 있는 값을 프로퍼티나 어트리뷰트로 바인딩하는 문법이다.


키입력, 마우스 이동, 클릭, 터치 등과 같은 사용자의 동작을 감지하고 이 동작에 반응하기 위해 이벤트 리스너를 추가할 수도 있다. 이벤트 이름을 소괄호((, ))로 감싸면 된다:


<button [disabled]="canClick" (click)="sayMessage()">
  Trigger alert message
</button>


그리고 아래 코드는 이벤트가 발생했을 때 실행될 메서드를 컴포넌트 클래스에 구현한 코드이다:


sayMessage() {
  alert(this.message);
}


Angular 템플릿에 문자열 바인딩과 프로퍼티(또는 어트리뷰트) 바인딩, 이벤트 바인딩이 어떻게 사용되는지 예제를 보면서 확인해 보자:


import { Component } from "@angular/core";

@Component({
  selector: "hello-world-bindings",
  templateUrl: "./hello-world-bindings.component.html",
})
export class HelloWorldBindingsComponent {
  fontColor = "blue";
  sayHelloId = 1;
  canClick = false;
  message = "Hello, World";

  sayMessage() {
    alert(this.message);
  }
}
<button [disabled]="canClick" (click)="sayMessage()">
  Trigger alert message
</button>
<p [id]="sayHelloId" [style.color]="fontColor">
  You can set my color in the component!
</p>
<p>My color is {{ fontColor }}</p>


템플릿에 추가 기능을 구현하려면 디렉티브(directives)를 사용하면 된다. Angular 디렉티브 중에서 가장 많이 사용되는 디렉티브는 *ngIf*ngFor가 있다. 디렉티브를 활용하면 DOM 구조를 동적으로 변경할 수 있기 때문에 다양한 용도로 활용할 수 있다. 사용자 경험을 더 좋게 만드는 용도로도 커스텀 디렉티브를 활용할 수 있다.


아래 코드는 *ngIf 디렉티브를 사용하는 예제 코드이다:


import { Component } from "@angular/core";

@Component({
  selector: "hello-world-ngif",
  templateUrl: "./hello-world-ngif.component.html",
})
export class HelloWorldNgIfComponent {
  message = "I'm read only!";
  canEdit = false;

  onEditClick() {
    this.canEdit = !this.canEdit;
    if (this.canEdit) {
      this.message = "You can edit me!";
    } else {
      this.message = "I'm read only!";
    }
  }
}
<h2>Hello World: ngIf!</h2>

<button (click)="onEditClick()">Make text editable!</button>

<div *ngIf="canEdit; else noEdit">
  <p>You can edit the following paragraph.</p>
</div>

<ng-template #noEdit>
  <p>The following paragraph is read only. Try clicking the button!</p>
</ng-template>

<p [contentEditable]="canEdit">{{ message }}</p>


Angular는 선언적인 템플릿 문법을 사용하기 때문에 화면에 표시되는 단위로 애플리케이션 로직을 깔끔하게 분리할 수 있다. 그리고 템플릿에는 표준 HTML 문법을 활용하기 때문에 구성하기 쉽고, 관리하기도 쉬우며, 나중에 수정하기도 쉽다.


Note

  • 템플릿에 대해 더 자세하게 알아보려면 템플릿 문서를 참고한다.


3) 의존성 주입(Dependency injection, DI)

Angular는 TypeScript 클래스를 활용하는 의존성 주입 시스템을 제공하기 때문에, 컴포넌트에 필요한 객체의 인스턴스를 어떻게 생성하는지 직접 신경쓸 필요가 없다. 인스턴스 생성은 Angular가 알아서 처리한다. 이런 패턴 덕분에 애플리케이션 코드를 좀 더 유연하게 작성할 수 있으며, 테스트하기도 쉽다. Angular 애플리케이션을 개발할 때 의존성 주입 시스템을 반드시 알아야 하는 것은 아니다. 하지만 모범사례를 보면서 의존성 주입 시스템을 활용했을 때 얻는 장점이 무엇인지 알아보는 것을 적극 권장한다.


의존성 주입 시스템이 동작하는 방식을 간단한 예제로 확인해 보자. 첫 번째 파일 logger.service.ts에는 Logger 클래스가 정의되어 있다. 이 클래스에는 인자로 받은 숫자를 콘솔에 출력하는 writeCount 함수가 정의되어 있다.


import { Injectable } from "@angular/core";

@Injectable({ providedIn: "root" })
export class Logger {
  writeCount(count: number) {
    console.warn(count);
  }
}


그리고 hello-world-di.component.ts 파일에는 Angular 컴포넌트가 정의되어 있다. 이 컴포넌트에는 버튼이 하나 있는데, 이 버튼을 클릭하면 Logger 클래스에 있는 writeCount 함수를 실행하려고 한다. 그러면 HelloWorldDI 클래스 생성자에 private logger: Logger라는 코드를 추가해서 Logger 서비스가 의존성 객체로 주입되도록 요청할 수 있다.


import { Component } from "@angular/core";
import { Logger } from "../logger.service";

@Component({
  selector: "hello-world-di",
  templateUrl: "./hello-world-di.component.html",
})
export class HelloWorldDependencyInjectionComponent {
  count = 0;

  constructor(private logger: Logger) {}

  onLogMe() {
    this.logger.writeCount(this.count);
    this.count++;
  }
}


Note


2. Angular CLI

Angular 애플리케이션을 가장 빠르고, 쉽게, 모범사례로 개발하려면 Angular CLI를 활용하면 된다. Angular CLI를 활용하면 수많은 작업들을 간단하게 처리할 수 있다:


명령어 설명
ng build Angular 앱을 컴파일한다.
ng serve 애플리케이션을 빌드하고 개발서버로 서비스한다. 파일이 변경되면 바로 반영한다.
ng generate 스키매틱에 정해진 대로 Angular 구성요소를 생성하거나 수정한다.
ng test 유닛 테스트를 실행한다.
ng e2e 애플리케이션을 빌드하고 개발서버로 띄운 후에 엔드-투-엔드 테스트를 실행한다.


이밖에도 Angular CLI를 활용할 수 있는 방법은 많다.


Note

  • Angular CLI에 대해 자세하게 알아보려면 CLI 참고 문서를 참고한다.


3. 기본 라이브러리

이 문서는 Angular 애플리케이션을 구성하는 중요한 구성요소들에 대해 간단하게 알아봤다. Angular의 진정한 가치는 애플리케이션이 점점 커지면서 필요한 화면으로 전환하고 사용자의 동작에 반응하는 다양한 로직을 추가할수록 그 뛰어난 효율성을 제대로 확인할 수 있다. 이 때 사용할 수 있도록 Angular가 제공하는 퍼스트-파티 라이브러리들은 이런 것들이 있다:


라이브러리 설명
Angular Router Angular 컴포넌트를 기반으로 클라이언트에서 화면을 전환한다. 지연로딩과 중첩 라우팅, 커스텀 주소 매칭 등 다양한 기능을 제공한다.
Angular Forms 일관된 방식으로 폼(form)을 구성하고 유효성을 검사할 수 있다.
Angular HttpClient 클라이언트-서버 통신에 사용하는 강력한 HTTP 클라이언트이다.
Angular Animations 애플리케이션 상태에 따라 자동으로 연동되는 애니메이션을 구현할 수 있다.
Angular PWA 프로그레시브 웹 애플리케이션(Progressive Web Applications, PWA)을 구성할 때 사용하는 툴이다. 서비스 워커, 웹 앱 매니페스트를 지원한다.
Angular Schematics 대규모 프로젝트 개발을 단순화하기 위해 구성요소의 기본틀 생성을 자동화하거나 리팩토링 할 수 있는 툴이다.


이 라이브러리들은 애플리케이션에 기능이 필요할 때마다 도입해서 확장할 수 있기 때문에, 개발자는 애플리케이션 자체 기능에만 신경쓸 수 있다. 그리고 이 라이브러리들은 Angular 프레임워크와 자연스럽게 연동되며 버전업도 동시에 이루어지도록 설계되었다.


이 라이브러리들은 사용할 필요가 있을 때만 애플리케이션에 로드해서 사용하면 된다.


References