๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Angular

Angular summary

๐Ÿ“‡ Index
Intro
Architecture
Angular vs AngularJS
Component
Directive
Service
Pipe
Data share
Data binding
Guard
@NgModules
Routing
๐ŸŽฌ Intro
Angular๋Š” 2014๋…„์— ng ์ปจํผ๋Ÿฐ์Šค์—์„œ ์ฒ˜์Œ ์†Œ๊ฐœ ๋˜์—ˆ์œผ๋ฉฐ 2016๋…„ 2.0๋ฒ„์ „์ด ์ •์‹ ๋ฆด๋ฆฌ์ฆˆ ๋˜์—ˆ์œผ๋ฉฐ ์ง€๊ธˆ ํ˜„์žฌ๋Š” 7.x.x๋ฒ„์ „ ๊นŒ์ง€ ๋ฆด๋ฆฌ์ฆˆ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
Angular๋Š” SPA(Single Page Application) ๊ฐœ๋ฐœ์„ ์œ„ํ•œ Javascript based Open Source Front End Web Application์ž…๋‹ˆ๋‹ค.
Angular ๋Š” ์ˆ˜ ๋งŽ์€ ๋ผ์ด๋ฆฌ๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š”๋ฐ ์ฝ”์–ด ๋ชจ๋“ˆ๊ณผ ์˜ต์…˜ ๋ชจ๋“ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ฝ”์–ด ๋ชจ๋“ˆ์€ Angular application์˜ ์ฃผ์š” ๊ตฌ์„ฑ์„ ๋งŒ๋“œ๋Š” Decorator ๋‚˜ LifeCycle ๊ฐ™์€ ์นœ๊ตฌ๋“ค์ด ์ฃผ๋กœ ์ด๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜, ๋„ค์ดํ‹ฐ๋ธŒ ๋ชจ๋ฐ”์ผ, ๋ฐ์Šคํฌํƒ‘ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊นŒ์ง€ ํ”„๋ก ํŠธ์•ค๋“œ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ”๊ณ  ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
Angular๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ง€์›ํ•˜์ง€๋งŒ IE๋Š” 9๋ฒ„์ „ ์ด์ƒ๋ถ€ํ„ฐ ์ง€์›ํ•˜์—ฌ Cross Browsing Issue๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
Angular1.x ๋Š” AngularJS๋ผ Angular2+ ๋Š” Angular๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.
Angular๋ฅผ ์ด์šฉํ•œ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด ์„ ํ–‰ ๋˜์–ด์•ผ ํ•  ๊ฒƒ
Typescript
Javascript
RxJS
OOP
Angular๋Š” Typescript๋ฅผ ์ฃผ๋ ฅ ์–ธ์–ด๋กœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— Typescript ์— ๋Œ€ํ•œ ์‚ฌ์ „ ์ง€์‹์ด ์—†๋‹ค๋ฉด
Steep Learning Curve๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ”ฅ Angular vs AngularJS
Angular์™€ AngularJS๋Š” Architecture, Concept, Syntax ๋“ฑ ๋งŽ์€ ๋ถ€๋ถ„์—์„œ ์ฐจ์ด๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค.
ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ด๋ฆ„๋งŒ ๋†“๊ณ  ๋ณด๋ฉด (์ฒ˜์Œ์—๋Š” Angular1, Angular2๋กœ ๋ถˆ๋ ธ์Šต๋‹ˆ๋‹ค.) AngularJS์—์„œ ์—…๊ทธ๋ ˆ์ด๋“œ๊ฐ€ ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์‚ฌ์‹ค์€ ์ƒˆ๋กœ์šด ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋งŒ๋“ค์–ด์กŒ๋‹ค๊ณ  ๋ด๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค.
๋‘ ํ”„๋ ˆ์ž„์›Œํฌ์— ์ฐจ์ด๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๊ธฐ์กด AngularJS์˜ Controller์™€ $scope๊ธฐ๋ฐ˜์—์„œ CBD Component Based Development ์ „ํ™˜ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
์ฃผ๋ ฅ ๊ฐœ๋ฐœ ์–ธ์–ด๋กœ์„œ Typescript ๋ฅผ ๋„์ž…ํ•˜์—ฌ ํƒ€์ž…์ฒดํฌ, ์ œ๋„ˆ๋ฆญ, ์ธํ„ฐํŽ˜์ด์Šค๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
๊ฐœ๋ฐœํ™˜๊ฒฝ ์ง€์› ๋„๊ตฌ์ธ Angular CLI๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
CBD vs (Controller + $scope)
๊ฐ„๋žตํ•˜๊ฒŒ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
<div ng-app="myApp" ng-controller="personCtrl"> First Name: <input type="text" ng-model="firstName"><br> Last Name: <input type="text" ng-model="lastName"><br> <br> Full Name: {{fullName()}} </div> <script> var app = angular.module('myApp', []); app.controller('personCtrl', function($scope) { $scope.firstName = "John"; $scope.lastName = "Doe"; $scope.fullName = function() { return $scope.firstName + " " + $scope.lastName; }; }); </script>
TypeScript
AngularJS ๊ฐ™์€ ๊ฒฝ์šฐ angular.controller ํ•จ์ˆ˜์— ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ด๋ฆ„์„ ๋„ฃ๊ณ  ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ํ•จ์ˆ˜๋กœ ๋„ฃ์Šต๋‹ˆ๋‹ค. ์ด ๋•Œ ํ•จ์ˆ˜์— $scope๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜์—ฌ View์— ๋ฐ”์ธ๋”ฉ ๋  ๋ฐ์ดํ„ฐ๋“ค์„ ๋„ฃ์–ด ์ค๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Template์— ng-controller ๋ผ๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ $scope ๋Š” View์™€ Controller๋ฅผ ์ด์–ด์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ng-controller ๋ฅผ ์ด์šฉํ•˜์—ฌ ์–ด๋Š ์—˜๋ฆฌ๋จผํŠธ๋‚˜ Controller์˜ scope๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ  ์ค‘์ฒฉ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
๋‹ค์Œ์€ Angular ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
// app.component.ts import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { constructor() {} firstName: string = 'John'; lastName: string = 'Doe'; ngOnInit() { console.log(this.firstName); } fullName(): string { return `${this.firstName} ${this.lastName}`; } }
TypeScript
<!--app.component.html--> <p>{{fullName()}}</p>
HTML
Angular ๊ฐ™์€ ๊ฒฝ์šฐ ํ…œํ”Œ๋ฆฟ๊ณผ (๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ)๋ฅผ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค. Angular๋Š” CBD๋ผ MVC ๋‚˜ MVVM ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋‚˜ ํ…œํ”Œ๋ฆฟ์€ View, ์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค๋Š” Controller์™€ ViewModel์˜ ์ผ๋ถ€๋ฅผ ๋‹ด๋‹น ํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋“ฏ Angular๋Š” ํ…œํ”Œ๋ฆฟ๊ณผ (๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง + ๋ฐ์ดํ„ฐ)๊ฐ€ 1๋Œ€1์ž…๋‹ˆ๋‹ค.
๐Ÿ‘Œ Component
Component๋Š” Angular application๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
์ปดํฌ๋„ŒํŠธ๋Š” ๋ทฐ(View)๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๊ณ  Angular๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์กฐ๋ฆฝํ•˜์—ฌ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ํ•˜๋‚˜์˜ ํ™”๋ฉด์„ ์ถฉ๋ถ„ํžˆ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„์„ ํ•˜๊ฒŒ ๋˜๋ฉด ๋น„์Šทํ•œ ํ˜•ํƒœ์˜ ์ฝ”๋“œ๋“ค์ด ์ค‘๋ณต ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ ์žฌ์‚ฌ์šฉ์ด ์šฉ์ดํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ค„์ด๊ณ  ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๋…๋ฆฝ์„ฑ์ด ๋ถ€์—ฌ๋˜์–ด ๋ฐ์ดํ„ฐ๋‚˜ ๋กœ์ง๋“ค์˜ ์˜์กด์„ฑ์„ ์ œ๊ฑฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ
Caption
Original
์šฐ๋ฆฌ๊ฐ€ ์›น์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋‹ค ๋ณด๋ฉด ๋ณดํ†ต ์œ„ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋ธ”๋ก ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿด ๊ฒฝ์šฐ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ํ—ค๋”, ํ‘ธํ„ฐ, ์‚ฌ์ด๋“œ๋ฐ” ๊ฐ™์€ ์˜์—ญ์€ ๊ฑฐ์˜ ๋ชจ๋“  ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉ ๋˜๊ณ  ์„น์…˜ ์˜์—ญ๋งŒ ๋ณ€๊ฒฝ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.
์ด๋Ÿด ๊ฒฝ์šฐ ๋ชจ๋“  ํŽ˜์ด์ง€๋งˆ๋‹ค ํ—ค๋”, ํ‘ธํ„ฐ, ์‚ฌ์ด๋“œ๋ฐ”๋ฅผ ๊ทธ๋ ค์ค€๋‹ค๋ฉด ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์ด๋‚˜ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์ค‘๋ณต์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋ฉฐ ์‹œ๊ฐ„๋„ ๋งŽ์ด ๊ฑธ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ด๋Ÿด ๋•Œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„ํ•  ํ•˜๊ณ  ์กฐ๋ฆฝํ•˜์—ฌ ํ™”๋ฉด์„ ๊ตฌ์„ฑ ํ•œ๋‹ค๋ฉด ์ฝ”๋“œ์˜ ๊ฒฝ๋Ÿ‰ํ™” + ์œ ์ง€๋ณด์ˆ˜ + ๊ฐœ๋ฐœ ์ธก๋ฉด์—์„œ ํšจ๊ณผ๋ฅผ ๊ฐ€์ ธ ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ„ ํ™”๋ฉด์„ Angular ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌ์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. DOMํŠธ๋ฆฌ์™€ ๋น„์Šทํ•œ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋ฅผ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
Caption
Original
์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ๊ตฌ์กฐ
์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ๊ตฌ์กฐ๋Š” ํฌ๊ฒŒ 3์˜์—ญ์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Import ์˜์—ญ
Decorator ์˜์—ญ
์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค ์˜์—ญ
import { Component, OnInit } from '@angular/core'; // import ์˜์—ญ // ์ปดํฌ๋„ŒํŠธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์˜์—ญ @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) // ์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค ์˜์—ญ export class AppComponent implements OnInit { constructor() {} firstName: string = 'John'; lastName: string = 'Doe'; ngOnInit() { console.log(this.firstName); } fullName(): string { return `${this.firstName} ${this.lastName}`; } }
TypeScript
์‚ฌ์‹ค ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์š”์†Œ(Service, Pipe ๋“ฑ)๋“ค์€ ๊ตฌ์กฐ๊ฐ€ ๋‹ค ์ด๋Ÿฐ ํ˜•ํƒœ์ด๋‹ค.
Import ์˜์—ญ - ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“ˆ์ด๋‚˜ ์„œ๋น„์Šค๋“ฑ์„ ๊ฐ€์ ธ์˜จ๋‹ค.
Decorator ์˜์—ญ - ์ปดํฌ๋„ŒํŠธ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๋ฆฌ๊ณ  ํ•„์š”ํ•œ ์ •๋ณด๋“ค์„ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ฐ์ฒด์— ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋„ฃ์–ด ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค ์˜์—ญ - ๋ทฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ๋ฐ ๋กœ์ง์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
Angular์˜ ๋ชจ๋“  ๋ชจ๋“ˆ์€ ์•ž์— @angular๊ฐ€ ๋ถ™๋Š”๋‹ค.
๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
@Component ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์ „๋‹ฌ ํ•˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ž ์‹œ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
selector: ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งˆํฌ์—…์œผ๋กœ ํ‘œํ˜„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด๋ฆ„์„ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” ์—˜๋ฆฌ๋จผํŠธ ๋‹จ์œ„์˜ ์š”์†Œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
<app-root></app-root>
HTML
templateUrl: ์ปดํฌ๋„ŒํŠธ์˜ ๋ทฐ๋กœ ์ƒ์„ฑํ•  ๋งˆํฌ์—… ํŒŒ์ผ ๊ฒฝ๋กœ์„ stringํ˜•ํƒœ๋กœ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
template: templateUrl๊ฐ€ ํŒŒ์ผ ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋‹ค๋ฉด ์ด ํ”„๋กœํผํ‹ฐ๋Š” ๊ฐ™์€ ํŒŒ์ผ์— ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
@Component({ selector: 'sw-btn', template:` <button>Click</button> `, styleUrls: ['styles.scss'] })
TypeScript
styleUrls: ์Šคํƒ€์ผ์‹œํŠธ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. value์˜ ํ˜•ํƒœ๋‚˜ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์—์„œ ์œ ์ถ” ํ•  ์ˆ˜ ์žˆ๋“ฏ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํŒŒ์ผ์„ ์ง€์ • ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ๋ฐ–์—๋„ moduleId, providers, exportAs๋“ฑ ๋„ˆ๋ฌด๋‚˜๋„ ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๐Ÿš€ Service
Service์˜ ์—ญํ• ์€ ์–ดํ”Œ์ผ€์ด์…˜์˜ ๊ด€์‹ฌ์™€ ์ปดํฌ๋„ŒํŠธ์˜ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ ๋  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์ด๋‚˜ ๋ฐ์ดํ„ฐ๋“ค์€ ์„œ๋น„์Šค์—์„œ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
์„œ๋น„์Šค ์ด์šฉํ•˜๋ฉด ์šฐ๋ฆฌ๋Š” ๋‹ค์–‘ํ•œ ํšจ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ๋ณด๋ฉด ์›๋ž˜๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฐ ์ปดํฌ๋„ŒํŠธ์— ์ค‘๋ณต ๋˜๋˜ ์ฝ”๋“œ๋“ค์„ ์„œ๋น„์Šค์— ์ž‘์„ฑํ•จ์œผ๋กœ์จ ์ฝ”๋“œ๋ฅผ ๊ฒฝ๋Ÿ‰ํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์‹ ์˜ ๊ด€์‹ฌ์‚ฌ์— ์ง‘์ค‘ํ•˜๊ฒŒ ๋˜๊ณ  ๋…๋ฆฝ์„ฑ์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฉด์„œ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์•„์ง€๊ณ  ๋ณต์žก์„ฑ์€ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
Service code
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CountService { constructor() { } count: number = 0; sayCurrentCount(): void { console.log('count:',this.count); } }
TypeScript
import { Component } from '@angular/core'; import { CountService } from './count.service'; @Component({ selector: 'app-root', template: ` <plus-btn></plus-btn> <minus-btn></minus-btn> <button (click)="countService.sayCurrentCount()">Click me!</button> `, styleUrls: ['./app.component.scss'] }) export class AppComponent { constructor(private countService: CountService) {} }
TypeScript
import { Component } from '@angular/core'; import { CountService } from './count.service'; @Component({ selector: 'minus-btn', template: `<button (click)="subtractCount()">Minus<button>` }) export class MinusButtonComponent { constructor(private countService: CountService) {} subtractCount() { this.countService.count -= 1; } }
TypeScript
import { Component, OnInit } from '@angular/core'; import { CountService } from './count.service'; @Component({ selector: 'plus-btn', template: `<button (click)="addCount()">Plus<button>` }) export class PlusButtonComponent implements OnInit { constructor(private countService: CountService) {} addCount() { this.countService.count += 1; }; }
TypeScript
์„œ๋น„์Šค๋Š” ์˜์กด์„ฑ ์ฃผ์ž… Dependency Injection์ด ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. @injectable ์€ Dependency Injection ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ฃผ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.
@Injectable ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ฐ์ฒด์˜ providedIn์€ Angular6 ๋ฒ„์ „๋ถ€ํ„ฐ ๋„์ž…๋œ ๊ฒƒ์œผ๋กœ ๊ฐ’์€ 'root' | null์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
root๋กœ ์ง€์ •ํ•˜๊ฒŒ ๋˜๋ฉด ๋ชจ๋“  ๊ตฌ์„ฑ์š”์†Œ๊ฐ€ ์„œ๋น„์Šค๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Code Description
1.
countService๋ผ๋Š” ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
2.
plus button, minus button ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ฐ๊ฐ count ๋”ํ•˜๊ธฐ ๊ธฐ๋Šฅ๊ณผ count ๋นผ๊ธฐ ๊ธฐ๋Šฅ์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.
3.
plus button, minus button ์— countService๋ฅผ ์˜์กด์„ฑ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
4.
1์”ฉ ๋”ํ•˜๊ธฐ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” plus button ์€ count๋ฅผ click ํ• ๋•Œ๋งˆ๋‹ค 1์”ฉ ์ฆ๊ฐ€ ์‹œํ‚ต๋‹ˆ๋‹ค.
5.
1์”ฉ ๋นผ๊ธฐ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” minus button ์€ count๋ฅผ click ํ• ๋•Œ๋งˆ๋‹ค 1์”ฉ ๊ฐ์†Œ ์‹œํ‚ต๋‹ˆ๋‹ค.
6.
app component ์˜ Click me! ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ํ˜„์žฌ ๊ณ„์‚ฐ๋œ ์นด์šดํŠธ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค.
์„œ๋น„์Šค๋Š” ์ด๋ ‡๊ฒŒ ๊ณตํ†ต ๋ฐ์ดํ„ฐ๋‚˜ ๋กœ์ง์„ ๊ฐ€์ง€๊ณ  ๊ฐ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์˜ค์ง ๊ฐ์ž์˜ ๊ด€์‹ฌ์‚ฌ์— ์ง‘์ค‘ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
๐Ÿน Directive
Directive ๋Š” DOM์˜ ์–ด๋– ํ•œ ๋™์ž‘์„ ์ง€์‹œํ•˜์—ฌ DOM์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅ ์‹œ์ผœ์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” Elementํ˜•ํƒœ๋กœ ์‚ฌ์šฉ ๋˜๊ฑฐ๋‚˜ Attributeํ˜•ํƒœ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
Elementํ˜•ํƒœ์˜ ๋Œ€ํ‘œ์ ์ธ ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” <router-outlet><router-outlet> ์žˆ๊ณ 
Attributeํ˜•ํƒœ์˜ ๋Œ€ํ‘œ์ ์ธ ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” *ngIf ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
Directive ๋Š” 3๊ฐ€์ง€ ์ข…๋ฅ˜๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Component Directive - ์œ„ component ์˜ˆ์ œ์—์„œ ๋ณธ selector property ๋ฅผ ์ด์šฉํ•˜์—ฌ Component๋ฅผ ๋””๋ ‰ํ‹ฐ๋ธŒ๋กœ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.
Attribute Directive - HTML Element์˜ Attribute๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. built-in ํ˜•ํƒœ๋กœ๋Š” ngClass ๊ฐ™์€ ๊ฒƒ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.
Structural Directive - DOM์˜ ๊ตฌ์กฐ๋ฅผ ์ œ์–ดํ•˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ์ž…๋‹ˆ๋‹ค. *ngIF, *ngFor๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์—˜๋ฆฌ๋จผํŠธ์—๋Š” ํ•˜๋‚˜์˜ Structural Directive๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
<div *ngFor="let num of numberList">{{num}}</div> <div *ngIf="isTrue">isTrue</div> <div *ngIf="!isTrue">isFalse</div> <div [hidden]="isTrue">hidden</div> <div [ngStyle]="{'color': 'orangered'}">orangered</div>
HTML
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { constructor(private countService: CountService) {} isTrue: boolean = true; numberList: Array<number> = [1, 2, 3]; }
TypeScript
Result
Caption
Original
AngularJS์—์„œ๋Š” ๋ถˆํ•„์š”ํ•œ ๋””๋ ‰ํ‹ฐ๋ธŒ๊ฐ€ ๋งŽ์•˜์Šต๋‹ˆ๋‹ค. ์˜ˆ๋กœ ng-hide ์™€ ng-show๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค display on/off๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ์ž…๋‹ˆ๋‹ค. Angular2+๋Š” ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ [hidden] ํ•˜๋‚˜๋งŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„ ์ธก๋ฉด?์—์„œ๋„ ๊ฐ€๋…์„ฑ์„ ๋งŽ์ด ํ–ฅ์ƒ ์‹œํ‚จ ๋…ธ๋ ฅ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋””๋ ‰ํ‹ฐ๋ธŒ ์œ ํ˜•์— ์ƒ๊ด€์—†์ด ng prefix๋งŒ ๋ถ™ํ˜€์„œ ์‚ฌ์šฉํ•˜์˜€๋Š”๋ฐ Angular2+๋Š” * () []๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ ํ˜•์„ ํŒŒ์•… ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค. *ngIf *๋Š” ng-template์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. () ์™€ []๋Š” ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ๊ณผ ์—ฐ๊ด€์ด ์žˆ๋Š” ๋ถ€๋ถ„์ด๋ผ ๋’ค์—์„œ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
๐ŸฆŠ Pipe
Pipe ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”์ธ๋”ฉ ํ•  ๋•Œ ์›๋ณธ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ์ถœ๋ ฅ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. Pipe์˜ ๋ฌธ๋ฒ•์€ '|' ์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.
<p>{{name | uppercase}}</p>
HTML
Pipe๋Š” ๋‘ ๊ฐ€์ง€ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ Pure์™€ Impure ์ž…๋‹ˆ๋‹ค.
pure : Change to a primitive input value (String, Number, Boolean, Symbol) ๋˜๋Š” Changed object reference (Date, Array, Function, Object)) ์„ ๊ฐ์ง€ํ•  ๋•Œ๋งŒ ์‹คํ–‰ํ•œ๋‹ค. ์ œํ•œ์ ์ด์ง€๋งŒ ๋น ๋ฆ…๋‹ˆ๋‹ค. (์˜ˆ : date, uppercase, number Pipe)
Impure: ์ œํ•œ์—†์ด ์–ด๋– ํ•œ ๊ฒฝ์šฐ์—๋„ ๋ฐ์ดํ„ฐ์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
@Pipe({ name: 'flyingHeroesImpure', pure: false })
TypeScript
Custom Pipe๋ฅผ ๋งŒ๋“ค ๊ฒฝ์šฐ Impure pipe๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ @pipe ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ฐ์ฒด์˜ pure ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ false๋กœ ๋„ฃ์–ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
Parameterizing a pipe
pipe์ด๋ฆ„ ๋’ค์— ':'์„ ๋ถ™ํ˜€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„ฃ์–ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
<p>The hero's birthday is {{ birthday | date:"MM/dd/yy" }} </p>
HTML
Chaining pipes
pipe๋Š” '|' ์„ ๋ถ™ํ˜€ ์ฒด์ด๋‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
The chained hero's birthday is {{ birthday | date:'fullDate' | uppercase}}
HTML
๐Ÿ“Š Data share
Angular ๋Š” ์…€๋ ‰ํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿผ ๋‘ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง์œผ๋กœ์จ ๋‘ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋กœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ  ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๊ฐ€ ํ˜•์„ฑ ๋˜์—ˆ๋‹ค๊ณ  ํ•ด์„œ ์„œ๋กœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋งˆ์Œ๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” ๋…๋ฆฝ์„ฑ์„ ๊ฐ€์ง€๋Š” ์กด์žฌ์ด๊ธฐ ๋•Œ๋ฌธ ์ž…๋‹ˆ๋‹ค. Angular๋Š” ๋ฐ์ดํ„ฐ ๊ณต์œ ๋ฅผ ์œ„ํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๋ฐ์ดํ„ฐ ๊ณต์œ ๋ฅผ ์œ„ํ•œ ๋Œ€ํ‘œ์ ์ธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ 2๊ฐœ๋ฅผ ์†Œ๊ฐœํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
@Input
@Output
@Input
@Input ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ถ€๋ชจ โ†’ ์ž์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.
// child component import { Component, Input, OnInit } from '@angular/core'; @Component({ selector: 'app-child', template: ` <div style="background-color: orangered; color: white">message: {{message}}</div> ` }) export class ChildComponent implements OnInit { @Input() parentsMessage: string = ''; message: string = ''; constructor() {} ngOnInit() { this.message = this.parentsMessage; console.log(this.message); } }
TypeScript
// parents component import { Component } from '@angular/core'; @Component({ selector: 'parents', templateUrl: './parents.component.html', styleUrls: ['./parents.component.scss'] }) export class ParentsComponent { constructor() {} message: string = 'Wellcome to My blog'; }
TypeScript
// parents.component.html <div style="background-color: #00ff6a; padding: 10px"> Parents <app-child [parentsMessage]="message"></app-child> </div>
HTML
Child Component ์—์„œ ๋ฐ›์„ @Input ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ๋ณ€์ˆ˜ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ณ€์ˆ˜๋Š” app-child
์˜ Attribute๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ €๋Š” parentsMessage๋ผ๊ณ  ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. Parents component๋Š” Child Component ๋ฅผ ํ˜ธ์ถœ ํ• ๋•Œ parentsMessage Attribute๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ์ž…ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
Child Component ์ปดํฌ๋„ŒํŠธ๋Š” parentsMessage๋ฅผ ํ†ตํ•ด ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์— ๋‹ด์•„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋งŒ์•ฝ ์†์„ฑ ์ด๋ฆ„๊ณผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ ํ•  ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋‹ค๋ฅด๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์„ ์–ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
@Input('message') parentsMessage: string = ''; @Input('attribute') variable: string = '';
TypeScript
@Output
@Output์€ ์ž์‹ โ†’ ๋ถ€๋ชจ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.
// child component import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-child', template: ` <div style="background-color: orangered; color: white">message: {{message}}</div> <button (click)="onClick()">Click me!</button> ` }) export class ChildComponent { message: string = 'Welcome to my blog'; constructor() {} @Output() sendMessage = new EventEmitter(); onClick() { this.sendMessage.emit(this.message); } }
TypeScript
// parents component import { Component, OnInit } from '@angular/core'; import { CountService } from './count.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { constructor(private countService: CountService) {} message: string = 'Hello!'; ngOnInit() {} receiveMessage($event) { this.message = $event; } }
TypeScript
// app.component.html <div style="background-color: #00ff6a; padding: 10px"> Parents: {{message}} <app-child (sendMessage)="receiveMessage($event)"></app-child> </div>
HTML
Caption
Original
@Output ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” EventEmitter ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ์ž์‹์ปดํฌ๋„ŒํŠธ๋Š” EventEmitter ์˜ emit ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค๋Š” ์•Œ๋ฆผ๊ณผ ํ•จ๊ป˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋Š” event binding ์„ ์ด์šฉํ–์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›์Šต๋‹ˆ๋‹ค.
์ด ๋ฐ–์—๋„ @Viewchild ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ“ˆ Data binding
Angular๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ทฐ์™€ ๋ชจ๋ธ์ด ๋ถ„๋ฆฌ ๋˜์–ด ์žˆ๊ณ  ์ด ๋‘˜์„ ํ•˜๋‚˜๋กœ ์—ฐ๊ฒฐํ•˜๊ณ  ์œ ๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์ž…๋‹ˆ๋‹ค. Angular๋Š” 7๊ฐ€์ง€์˜ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
Interpolation
Property binding
Attribute binding
Class binding
Style binding
Event binding
Two-way binding
๊ฐ„๋‹จํžˆ ์ •๋ฆฌ๊ฐ€ ์–ด๋ ค์šด ๋ถ€๋ถ„์ด๋ผ ์ด ๊ธ€์—์„œ๋Š” Interpolation์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฐ„๋žตํ•˜๊ฒŒ ์•Œ์•„๋ณด๊ณ  ๋”ฐ๋กœ ์ •๋ฆฌ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
Interpolation
{{}}์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์„ ํ•ฉ๋‹ˆ๋‹ค. {{}} ์ค‘๊ด„ํ˜ธ ์‚ฌ์ด์—๋Š” ๋ณ€์ˆ˜ ์ด๋ฆ„, ์—ฐ์‚ฐ, ํ•จ์ˆ˜ ํ˜ธ์ถœ, ์˜ค๋ธŒ์ ํŠธ์˜ ํ”„๋กœํผํ‹ฐ๋“ฑ์ด ๋“ค์–ด ๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
import { Component, OnInit } from '@angular/core'; import { CountService } from './count.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { constructor(private countService: CountService) {} message: string = 'Hello!'; firstName: string = 'John'; lastName: string = 'Doe'; age: number = 27; isTrue: boolean = true; foo: any = { bar: 'bar', baz: 'baz' }; getFullName() { return `${this.firstName} ${this.lastName}` } }
TypeScript
<div style="background-color: orange; padding: 10px"> <p>{{firstName}}</p> <p>{{lastName}}</p> <p>{{age}}</p> <p>{{isTrue}}</p> <p>{{foo.bar}}</p> <p>{{getFullName()}}</p> <p>{{1 + 2}}</p> </div>
HTML
Caption
Original
๐Ÿถ @NgModules
@NgModule์€ ๋ฃจํŠธ๋ชจ๋“ˆ๊ณผ ์ผ๋ฐ˜๋ชจ๋“ˆ์„ ์ •์˜ ํ•˜๋Š” ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.
๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์˜ ์ฃผ์š” ํ”„๋กœํผํ‹ฐ๋Š” 5๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด 5๊ฐ€์ง€ ํ”„๋กœํผํ‹ฐ์˜ value๋Š” ๋ชจ๋‘ Array type ์ž…๋‹ˆ๋‹ค.
providers - Injectable ๊ฐ์ฒด๋“ค์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. ex) service class
declartions - components, directive, and pipes๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
imports - export๋œ ๋ชจ๋“ˆ๋“ค์„ ๊ฐ€์ ธ์˜ฌ๋•Œ ์ด ๊ณณ์— ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
bootstraps - ์Šค์Šค๋กœ ๊ตฌ๋™ ๋˜์–ด์•ผ ํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
exports - ์™ธ๋ถ€๋กœ ๊ณต๊ฐœ ํ•  ๋ชจ๋“ˆ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
// app.module.ts import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { MinusButtonComponent } from './minus-button.component' import { PlusButtonComponent } from './plus-button.component' import { CountService } from './count.service'; @NgModule({ declarations: [ AppComponent, PlusButtonComponent, MinusButtonComponent, ], imports: [ BrowserModule, AppRoutingModule, ], providers: [CountService], bootstrap: [AppComponent] }) export class AppModule { }
TypeScript
๐Ÿ”‰ Routing
Angular์˜ ๋ผ์šฐํŒ…์— ๋Œ€ํ•ด ์•Œ์•„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Angular๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ๋•๊ธฐ ์œ„ํ•ด RotingModule ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
forRoot ํ•จ์ˆ˜์— routing ์„ค์ •์„ ํ•  ์ •๋ณด๋“ค์„ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.
forRoot๋Š” Router service provider์™€ ์ง€์‹œ์ž๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ดˆ๊ธฐ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Root ๋ชจ๋“ˆ์€ Routing ๋ชจ๋“ˆ์„ ์ž„ํฌํŠธ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ๋ผ์šฐํŒ… ์„ค์ •์€ ๋๋‚ฉ๋‹ˆ๋‹ค.
Routes๋Š” ๋‹ค์–‘ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
path - ํ•ด๋‹น ๋ผ์šฐํ„ฐ์˜ URL์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.
component - ํ•ด๋‹น path๋กœ ๋“ค์–ด์™”์„๋•Œ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์ •ํ•ด์ค๋‹ˆ๋‹ค.
redirectTo - ํ•ด๋‹น path๋กœ ๋“ค์–ด์™”์„๋•Œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋  path๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
children - ํ•ด๋‹น ๋ผ์šฐํ„ฐ์˜ ์ž์‹ ๋ผ์šฐํ„ฐ๋ฅผ ์„ค์ • ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ex) example.com/parents/child
pathMatch - value๋ฅผ 'full' ๋กœ ๋„ฃ์œผ๋ฉด ์ง€์ •๋œ ํŒจ์Šค๊ฐ€ ์™„๋ฒฝํžˆ ์ผ์น˜ ํ•  ๊ฒฝ์šฐ์—๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
์ด ๋ฐ–์—๋„ ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฐธ๊ณ  ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
// app.routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { DashboardComponent } from './dashboard/dashboard.component'; import { HeroesComponent } from './heroes/heroes.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component'; const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, { path: 'dashboard', component: DashboardComponent }, { path: 'detail/:id', component: HeroDetailComponent }, { path: 'heroes', component: HeroesComponent } ]; - @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [ RouterModule ] }) export class AppRoutingModule {}
TypeScript
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component'; import { HeroesComponent } from './heroes/heroes.component'; import { MessagesComponent } from './messages/messages.component'; import { AppRoutingModule } from './app-routing.module'; @NgModule({ imports: [ BrowserModule, FormsModule, AppRoutingModule ], declarations: [ AppComponent, DashboardComponent, HeroesComponent, HeroDetailComponent, MessagesComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
TypeScript
Router Outlet
๊ทธ๋Ÿผ ์ด์ œ ๋ผ์šฐํ„ฐ๋ฅผ ์„ค์ • ํ–ˆ์œผ๋‹ˆ ๋‚ด๊ฐ€ ์ง€์ •ํ•œ ๋ผ์šฐํ„ฐ๋กœ ๋“ค์–ด์™”์„๋•Œ ์ง€์ •๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ‘œ์‹œ ๋˜๋„๋ก ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. <router-outlet></router-outlet> ๋””๋ ‰ํ‹ฐ๋ธŒ๊ฐ€ ๊ทธ ์—ญํ• ์„ ํ•ด์ค๋‹ˆ๋‹ค. ๋ฃจํŠธ์ปดํฌ๋„ŒํŠธ์˜ ํ…œํ”Œ๋ฆฟ์— ์œ„์— ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ์ ‘๊ทผ๋œ ๋ผ์šฐํ„ฐ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ‘œ์‹œ ๋ฉ๋‹ˆ๋‹ค.
<router-outlet></router-outlet>
HTML
Router Link
๊ทธ๋Ÿผ ์ด์ œ ๋ผ์šฐํ„ฐ๋ฅผ ์ด๋™ ์‹œ์ผœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
์ด๋ฒˆ์—๋Š” routerLink๋ผ๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ์‚ฌ์šฉ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. routerLink ๋””๋ ‰ํ‹ฐ๋ธŒ์— ์ด๋™์‹œํ‚ค๊ณ  ์‹ถ์€ ๋ผ์šฐํ„ฐ path๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ”์ธ๋”ฉ ์‹œ์ผœ์ค๋‹ˆ๋‹ค.
<a routerLink="/dashboard"></a>
HTML
์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ์œ„ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด dashboard ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
๐Ÿ’‚โ€โ™€๏ธ Guard
์ด๋ฒˆ์—๋Š” Angular Guard์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
Guard๋Š” ๋ผ์šฐํ„ฐ ์„ค์ • ์‹œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ์ง€์ • ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค๋ฉด ๋น„๋กœ๊ทธ์ธ, ๋กœ๊ทธ์ธ ๊ฐ™์€ ์ƒํ™ฉ๊ณผ ๋น„ํšŒ์›, ์ค€ํšŒ์›, ์ •ํšŒ์›์œผ๋กœ ๋“ฑ๊ธ‰์ด ๋‚˜๋ˆ„์–ด์ ธ ์žˆ์„ ๊ฒฝ์šฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
4๊ฐ€์ง€์˜ ๊ฐ€๋“œ๊ฐ€ ์ฃผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
canActivate - ๋ผ์šฐํ„ฐ๋กœ ์ ‘๊ทผ ํ•˜๋ ค ํ•  ๋•Œ ํ˜ธ์ถœ ๋œ๋‹ค. ์ฃผ๋กœ ์ ‘๊ทผ ์ œ์–ด๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค.
canActivateChild - canActivate์™€ ๋น„์Šทํ•˜์ง€๋งŒ ๋‹ค๋ฅธ์ ์€ canActivate๊ฐ€ ์ง€์ •๋œ ๋ผ์šฐํ„ฐ์—์„œ๋งŒ ํ˜ธ์ถœ ๋œ๋‹ค๋ฉด canActivateChild๋Š” children router์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•  ๋•Œ ํ˜ธ์ถœ ๋œ๋‹ค.
canDeactivate - ํ•ด๋‹น ๋ผ์šฐํ„ฐ๊ฐ€ ๋น„ํ™œ์„ฑํ™” ๋˜๊ณ  ๋ฒ—์–ด๋‚˜๋ ค๊ณ  ํ•  ๋•Œ ํ˜ธ์ถœ ๋œ๋‹ค.
Resolve - ๋ผ์šฐํ„ฐ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
import { AuthGuard } from '../auth/auth.guard'; const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, canActivate: [AuthGuard], children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ], } ] } ]; @NgModule({ imports: [ RouterModule.forChild(adminRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {}
TypeScript
Reference

'Angular' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Angular summary  (0) 2018.12.26
Google Analytics in Angular ์ ์šฉ๊ธฐ  (0) 2018.04.11
์•Œ์•„ ๋‘๋ฉด ์œ ์šฉํ•œ Angular CLI 1ํƒ„!  (0) 2017.12.11
Angular ๋‚ด์žฅ ํŒŒ์ดํ”„  (0) 2017.06.28