본문 바로가기
옛날

Angular 튜토리얼 1

by 차가운게 조아 2020. 2. 18.

Github

Angular 그냥 시작해보기1

따로 프로젝트를 생성할 필요없에 웹에서 시작해보기

(StackBlitz에 새로운 프로젝트를 생성하려면 여기를 클릭하세요.)

 

StackBlitz에서 생성된 프로젝트 첫 화면

프로젝트 생성  첫화면

 

 

템플릿 문법

Angular 템플릿 문법을 사용하면 HTML과 JavaScript을 확장할 수 있습니다. 이번 섹션에서는 "Products" 영역을 어떻게 확장할 수 있는지 알아봅시다.

(템플릿 문법에만 집중하기 위해 아래 예제에서는 product-list.component.ts 파일에 미리 정의된 제품 데이터와 메소드를 사용합니다.)

 

1. product-list 폴더에 있는 product-list.component.html 템플릿 파일을 엽니다.

2. 제품의 이름을 표시할 수 있도록 템플릿을 수정합니다.

    • 목록에 있는 제품들은 화면에 동일한 모습으로 표현하려고 합니다. 이 때 목록 안에 있는 제품 정보를 반복해서 표시하기 위해 *ngFor 디렉티브를 사용합니다. *ngFor 디렉티브를 <div> 엘리먼트에 다음과 같이 추가합니다

src/app/product-list/product-list.component.html

<h2>Products</h2>
<div *ngFor="let product of products">
</div>

 

<div>에 *ngFor를 사용하면 목록에 있는 제품마다 같은 템플릿을 반복할 수 있습니다.

*ngFor 는 "구조 디렉티브(structural directive)" 중 하나입니다. 구조 디렉티브는 일반적으로 엘리먼트를 추가하거나 제거하고, 변형하는 방식으로 DOM 구조를 구성하는 디렉티브입니다. * 로 시작하는 디렉티브는 모두 구조 디렉티브입니다.

 

  • 제품의 이름을 표시할 때는 문자열 바인딩 문법(interpolation syntax) {{ }} 를 사용합니다. 이 문법을 사용하면 프로퍼티 값을 문자열로 표시할 수 있습니다. 그래서 <div> 안에 제품의 이름을 표시하기 위해 다음과 같이 <h3> 엘리먼트를 추가합니다

<h2>Products</h2>

<div *ngFor="let product of products">

  <h3>
      {{ product.name }}

  </h3>

</div>

 

그러면 다음과 같이 미리보기 화면에 제품 이름이 표시됩니다

3. 최종 결과물에서는 각각의 제품 이름이 제품 상세정보 화면으로 연결되는 링크가 될 것입니다. 지금 단계에서는 앵커 엘리먼트를 추가하고 이 엘리먼트에 제품 이름을 다음과 같이 [] 문법으로 지정합시다

<h2>Products</h2>

<div *ngFor="let product of products">

  <h3>
  
    <a [title]="product.name + ' details'">

      {{ product.name }}

    </a>

  </h3>

</div>

이제 미리보기 화면에서 제품 이름에 마우스 커서를 올려보면 엘리먼트에 어떤 프로퍼티 값이 바인딩되었는지 확인할 수 있습니다. 이 예제처럼 문자열 바인딩 문법 {{ }} 를 사용하면 프로퍼티 값을 텍스트로 렌더링할 수 있으며, 프로퍼티 바인딩 문법 [ ] 를 사용하면 프로퍼티 값을 바인딩하는 템플릿 표현식을 정의할 수 있습니다.

4. 제품 설명을 추가합니다. 이 때 <p> 태그에 *ngIf 디렉티브를 사용했기 때문에, 실제로 제품 설명이 존재할 때만 <p> 태그가 생성됩니다.

<h2>Products</h2>

<div *ngFor="let product of products">

  <h3>

    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>

  </h3>

  <p *ngIf="product.description">
    Description: {{ product.description }}
  </p>

</div>

이제 애플리케이션 화면을 보면 목록에 존재하는 제품마다 제품의 이름과 설명을 표시합니다. 그리고 아래 그림에서 보듯이, 마지막 제품은 설명이 없기 때문에 제품 설명도 존재하지 않습니다. "Description" 이라는 문구도 마찬가지입니다.

5. 이제 친구에게 제품을 공유할 수 있는 버튼을 추가해 봅시다. 이 버튼에서 click 이벤트가 발생하면 product-list.component.ts 에 정의해 둔 share() 메소드를 실행하려고 합니다. 이벤트 바인딩은 다음 예제처럼 이벤트 이름을 ( ) 로 감싸는 문법을 사용합니다.

<h2>Products</h2>

<div *ngFor="let product of products">

  <h3>
  
    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>

  </h3>

  <p *ngIf="product.description">
    Description: {{ product.description }}
  </p>

  <button (click)="share()">
    Share
  </button>

</div>

이제는 각 제품마다 "Share" 버튼이 추가되었습니다

 

 

"Share" 버튼이 동작하는 것을 확인해 봅시다

Share 버튼 눌렀을때 얼럿

 

 

이제 앱에는 제품 목록이 표시되며 공유할 수 있는 기능도 추가되었습니다. 그리고 이렇게 진행하는 동안 Angular 템플릿 문법 중 자주 사용하는 5가지 기본 기능에 대해 살펴봤습니다

  • *ngFor

  • *ngIf

  • 문자열 바인딩(Interpolation) {{ }}

  • 프로퍼티 바인딩 [ ]

  • 이벤트 바인딩 ( )

 

 

컴포넌트(Components)

특정 UI 영역을 재사용하기 위해 따로 분리해서 정의한 것을 컴포넌트 라고 합니다. 그래서 위에서 살펴본 제품 목록도 컴포넌트라고 할 수 있습니다.

컴포넌트는 다음 3가지로 구성됩니다

  • 컴포넌트 클래스는 데이터를 처리하는 로직과 같은 컴포넌트의 동작을 담당합니다. 위 예제에서 제품 데이터와 share() 메소드는 컴포넌트 클래스에 정의되어 있습니다.

  • HTML 템플릿은 사용자에게 표시되는 화면을 정의합니다. 위 예제에서 제품의 이름, 설명이 표시되도록 태그를 작성하고 "Share" 버튼을 추가한 것도 모두 HTML 템플릿을 수정한 것입니다.

  • 컴포넌트 스타일은 HTML 템플릿의 모양을 정의합니다. 위 예제에서는 아직 스타일을 정의하지 않았습니다.

Angular 애플리케이션은 특정한 용도로 만든 컴포넌트 트리로 구성됩니다.

그리고 지금 시점에 예제 애플리케이션에는 컴포넌트가 3개 존재합니다

  • app-root (오렌지색 영역) 은 애플리케이션의 기본틀입니다. 이 컴포넌트는 가장 처음 로드되는 컴포넌트이며, 모든 컴포넌트의 부모 컴포넌트입니다. 페이지 전체를 의미하는 것으로 이해해도 됩니다.

  • app-top-bar (파란색 영역) 은 쇼핑몰 이름과 주문 버튼이 존재하는 영역입니다.

  • app-product-list (보라색 영역) 은 위 예제에서 수정한 제품 목록 화면입니다.

 

입력 프로퍼티

지금까지 만든 앱을 보면 제품 목록에 있는 제품마다 이름과 설명이 표시됩니다. 그런데 제품 목록을 표시하는 컴포넌트를 보면 products.ts 파일의 products 배열에서 가져온 제품 목록이 products 프로퍼티에 할당되는 것도 확인할 수 있습니다.

이제 알림 기능을 추가해 봅시다. 알림 기능은 제품 정보를 입력 프로퍼티로 받아서 활용할 것입니다. 새로운 컴포넌트는 제품의 가격을 확인한 후에, 제품 가격이 $700 이상이면 이후에 제품을 세일할 때 알림을 받을 수 있도록 "Notify Me" 버튼을 표시할 것입니다. 그리고 이 버튼을 누르면 사용자가 회원가입할 수 있는 화면을 제공하려고 합니다.

 

1. 새로운 컴포넌트를 생성합니다.

    • app 폴더에 마우스 오른쪽 버튼을 클릭하고 Angular Generator를 선택한 후에 product-alerts라는 이름으로 컴포넌트를 생성합니다.

그러면 컴포넌트를 구성하는 다음 3개의 파일이 생성됩니다

  • product-alerts.component.ts

  • product-alerts.component.html

  • product-alerts.component.css

 

2. product-alerts.component.ts 파일을 엽니다.

src/app/product-alerts/product-alerts.component.ts

import { Component, OnInit } from '@angular/core';

@Component({

  selector: 'app-product-alerts',

  templateUrl: './product-alerts.component.html',

  styleUrls: ['./product-alerts.component.css']

})

export class ProductAlertsComponent implements OnInit {

  constructor() { }

  ngOnInit() {

  }

}

  • @Component 데코레이터를 봅시다. 이 데코레이터는 데코레이터 아래에 있는 클래스가 컴포넌트라는 것을 지정하는 데코레이터입니다. 그리고 이 데코레이터는 템플릿, 스타일, 셀렉터와 같이 컴포넌트와 관련된 메타데이터를 인자로 받습니다.

    • selector 는 컴포넌트를 구분하는 id입니다. 그리고 나중에 HTML이 렌더링될 때 이 셀렉터가 사용된 곳에 셀렉터에 해당되는 Angular 컴포넌트가 들어갑니다. 일반적으로 Angular 컴포넌트 셀렉터는 app- 접두사를 사용합니다.

    • 메타데이터에는 템플릿과 스타일 파일을 지정할 수 있습니다. 이 파일들은 컴포넌트를 생성할 때 자동으로 생성됩니다.

  • 컴포넌트를 생성하면 클래스(ProductAlertsComponent)도 함께 생성되는데, 이 클래스는 컴포넌트의 동작을 처리합니다.

 

3. 이제 새로 만든 컴포넌트가 제품 정보를 입력 프로퍼티로 받도록 설정합시다:

  • @angular/core 에서 Input 심볼을 로드합니다.

import { Component, OnInit } from '@angular/core';

import { Input } from '@angular/core';
  • 그리고 ProductAlertsComponent 클래스에 product 프로퍼티를 선언하면서 이 프로퍼티에 @Input 데코레이터를 지정합니다. 이 데코레이터를 사용하면 product 프로퍼티에 할당되는 값이 부모 컴포넌트(이 예제에서는 제품 목록 컴포넌트)에서 전달된다는 것을 의미합니다.

export class ProductAlertsComponent implements OnInit {

  @Input() product;

  constructor() { }

  ngOnInit() {

  }

}

4. 새로운 컴포넌트 화면을 구성합니다.

product-alerts.component.html 템플릿 파일을 열고 <p> 엘리먼트를 수정하는데, 제품의 가격이 $700을 넘을 때 "Notify Me" 버튼을 표시하도록 다음과 같이 작성합니다.

 

src/app/product-alerts/product-alerts.component.html

<p *ngIf="product.price > 700">

  <button>Notify Me</button>

</p>

 

 

5. 제품할인 알림 컴포넌트를 제품 목록 컴포넌트의 자식 컴포넌트로 추가합니다.

  • product-list.component.html 파일을 엽니다.

  • 새로운 컴포넌트를 추가하기 위해 이 컴포넌트에 지정한 app-product-alert 셀렉터를 HTML 엘리먼트인 것처럼 추가합니다.

  • 현재 *ngFor 루프에 해당하는 제품 정보를 프로퍼티 바인딩 문법으로 자식 컴포넌트에 전달합니다.

src/app/product-list/product-list.component.html

<button (click)="share()">

  Share

</button>

<app-product-alerts

  [product]="product">

</app-product-alerts>

 

이제 제품할인 알림 컴포넌트는 제품 목록 컴포넌트에서 제품 정보를 입력 프로퍼티로 받습니다. 그리고 이렇게 입력 프로퍼티로 받은 제품의 가격에 따라 "Notify Me" 버튼을 표시할지 결정합니다. 아래 예제에서 Phone XL의 가격은 $700을 넘기 때문에 "Notify Me"버튼이 표시되는 것을 확인할 수 있습니다.

 

 

 

출력 프로퍼티

아직까지 "Notify Me" 버튼은 아무 동작도 하지 않습니다. 이번 섹션에서는 사용자가 "Notify Me" 버튼을 클릭했을 때 제품 목록 컴포넌트로 이벤트를 보내도록 구현해 봅시다. 이 이벤트를 받아서 사용자에게 표시하는 동작은 제품 목록 컴포넌트에 구현할 것입니다.

  1. product-alerts.component.ts 파일을 엽니다.

  2. @angular/core 에서 Output과 EventEmitter 심볼을 로드합니다:

src/app/product-alerts/product-alerts.component.ts

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

import { Input } from '@angular/core';

import { Output, EventEmitter } from '@angular/core';

 

3. 이 컴포넌트 클래스에서 컴포넌트 밖으로 이벤트를 보낼 notify 프로퍼티를 정의하고, 이 프로퍼티에 @Output 데코레이터를 지정합니다. @Output 데코레이터를 지정하면 제품할인 컴포넌트에서 이벤트를 보낼 수 있습니다.

export class ProductAlertsComponent {

  @Input() product;

  @Output() notify = new EventEmitter();

}

 

4. 그리고 템플릿 파일(product-alerts.component.html)의 "Notify Me" 버튼이 notify.emit() 메소드를 실행하도록 이벤트를 바인딩합니다.

src/app/product-alerts/product-alerts.component.html

<p *ngIf="product.price > 700">

  <button (click)="notify.emit()">Notify Me</button>

</p>

 

5. 버튼이 클릭되었을 때 동작할 로직을 작성합니다. 이 로직은 제품할인 알림 컴포넌트가 아니라 부모 컴포넌트인 제품 목록 컴포넌트에 작성합니다. product-list.component.ts 파일에 onNotify() 메소드를 추가하고 share() 메소드와 비슷하게 다음과 같이 정의합니다

src/app/product-list/product-list.component.ts

export class ProductListComponent {

  products = products;

  share() {

    window.alert('The product has been shared!');

  }

  onNotify() {

    window.alert('You will be notified when the product goes on sale');

  }

}

 

6.마지막으로 제품할인 알림 컴포넌트에서 발생하는 이벤트를 제품 목록 컴포넌트가 받을 수 있도록 제품 목록 컴포넌트의 템플릿을 수정합니다.

app-product-alerts 컴포넌트가 보내는 notify 이벤트를 제품 목록 컴포넌트가 받으면 onNotify() 메고드를 실행하도록 product-list.component.html 파일을 수정합니다

<button (click)="share()">

  Share

</button>

<app-product-alerts

  [product]="product" 

  (notify)="onNotify()">

</app-product-alerts>

 

7. "Notify Me" 버튼을 클릭해 봅시다

 

 

 

 

 

 

'옛날' 카테고리의 다른 글

Angular 튜토리얼 3  (0) 2020.02.20
Angular 튜토리얼 2  (0) 2020.02.19
포르쉐 다이캐스트  (0) 2020.01.14
레고 페라리  (0) 2020.01.14
"브레드 인 헤븐" 용인 본점  (0) 2020.01.14