Programming/Web

[Angular] 02.튜토리얼 (4~8)

쌍쌍바나나 2017. 12. 31. 12:46
반응형

Angular Tutorial

아래 튜토리얼은 4~8

  • Displaying a List
  • Master/Detail Components
  • Services
  • Master/Detail Components
  • Services
  • Routing
  • HTTP

Displaying a List

  • Heroes의 리스트를 보여주고, hero 선택 및 hero의 details까지!
  • Create mock Heroes
    • 실제로는 remote data server로 부터 데이터를 가져와야 하지만, mock heroes를 만들어서 서버에서 동작하듯
    • mock-heroes.ts를 src/app/ 폴더에 생성
  • Displaying heroes
    • HeroesComponents에 보여주기 위해서
    • 위에서 생성한 mock-heroes를 import
    • 그런다음 heroes의 property에 heroes를 가리키도록 바인딩
    • List heroes with ngFor
    • HeroesComponent template file 열고 변경 li, ul태그 추가
    • ngFor는 angular's repeater
    • Style the heroes
    • heroes list는 attractive해야 하고, 유저가 마우스를 리스트 위에 올리거나, 선택할때 visually 응답이 있어야 한다.
    • 전체 스타일을 적용하기 위해서는 styles.css
    • heroes.component.ts에 heroes.component.css스타일을 적용해야 한다.
  • Master/Detail
    • master list에 있는 hero를 유저가 클릭했을때, page아래 hero's details이 표시 되어야 한다.
    • Add a click event binding
    • li에 click event를 binding 하기 위해서 (click)="onSelect(hero)"를 추가
    • Add the click event handler
    • application이 최초에 추가 되었을때는 아무것도 선택된 내용이 없을 것이다.
    • onSelect() 함수에 clicked hero를 selecdtedHero에 assign해준다.
    • Update the details template
    • 이전 hero의 property는 더이상 존재하지 않기 때문에 hero를 selectedHero로 rename
    • Hide empty details with ngif
    • 새로고침을 하게 되면, seletecedHero가 undefined되도록 디자인 되었기 때문에 에러가 발생한다.
    • ngIf를 통해서 selectedHero에 값이 undefined되어 있으면 hero detail이 보이지 않도록 조건을 추가
    • Style the selected hero
    • li중에 선택된 항목에 대해서 특정색을 보여줘야 한다.
    • .selected CSS class를 사용하면 된다.

Master/Detail Components

  • large components를 smaller sub-components로 나누는 방법에 대해서 설명
  • HeroDetailsComponent를 reusable
  • Make the HeroDetailComponent
    • hero-detail component를 Angular CLI를 통해 생성하자.
    • Wrtie the template
    • HeroesComponent의 아래에 있는 hero detail을 HeroDetailComponent에 옮기자
    • Add the @Input() hero property
    • HeroDetailComponent template에서 hero property를 binding하기 위해서 hero를 import
    • hero property는 input property여야하고, @Input() decroator 이여야지만 외부 HeroesComponent에서 bind를 할 수 있다.
    • hero-detail.components.ts에 Input을 import하고, @Input() hero: Hero;
  • Show the HeroDetailComponent
    • HeroesComponent는 아직 master/detail view이다.
    • HerosComponent는 parent로 child HeroDetailComponent를 관리하게 된다. (리스트에서 어떤 히어로가 선택이 되었을때 보여질 새로운 hero를 전달)
    • Update the HeroesComponent template
    • HeroDetailComponent selector는 app-hero-detail
    • element를 HeroesComponents template 아래에 추가
    • HeroesComponent.selectedHero를 hero property로 binding
    • 위 처럼 binding을 하면 HeroComponent에서 선택된 selectedHero는 HeroDetailComponent에 업데이트되고 새로운 hero의 detail을 보여줄 것이다.
  • What Changed?
    • 기존에 HerosComponent에서 모든것을 처리했다면, 지금은 HeroDetailComponent에서 대신 hero의 detail을 보여주고 있다.
    • 기존 HeroesComponent를 Refactoring
    • HeroesComponent의 역할을 줄였다.
    • HeroesComponent의 수정 없이 HeroDetailComponent의 수정을 통해 rich hero editor로 수정이 가능
    • HeroesComponent를 hero detail view 수정 없이 수정 가능
    • 이후 컴포넌트에서 HeroDetailComponent를 re-use 가능하다

Services

  • HeroesComponent는 현재 fake data를 통해서 getting and displaying을 하고 있다.
  • HeroesComponent에서 서비스 단위 테스트를 하는것에 대해서 설명한다.
  • Why Services
    • Components는 fetch, save data를 직접 처리하면 안된다. component는 data를 제공하고, 서비스에 data를 delegate하는데 초점을 맞춰야 한다.
    • HeroService를 생성해서 모든 application classes에서 heroes를 가져올 수 있도록 한다.
    • 새로운 서비스를 angular dependency injection을 이용해 생성하고, HeroesComponent constructor에가 inject한다.
    • services는 서로 알지 못하는 classes 사이에 정보를 공유하는데 좋은 방법이다.
    • MessageService를 생성하고, 두개의 장소에 inject
    • HeroService: send message하는데 사용
    • MessageComponent: message를 display
  • Create the HeroService
    • Angular CLI를 사용해 hero service를 생성
    • $ ng generate service hero
    • skeleton HeroService class를 생성한다. (src/app/hero.service.ts)
    • @Injectable() services
    • 새로운 서비스 injectable
    • get hero data
    • HeroService는 어디서든 hero 데이터를 가져올 수 있다. (web, local storage, mock data source 등등)
    • data access를 components에서 제거한다고 해도, 어떤 다른 component의 수정없이 서비스만 동작을 변경시키면 된다.
  • Provide the HeroService
    • Dependency injection system에서 HeroService를 제공해야 Angular가 HeroesComponentdㅔ inject를 할 수 있다.
    • HeroesComponent, AppComponent, AppModuel에서 HeroService를 제공하기 위한 방법이 여러가지 있다. 각각의 장단점이 있는데,
    • 이 tutorial에서는 AppMoudle에서 제공
    • CLI를 통해
    • $ ng generate service hero --module=app
    • AppModule class를 열어서 HeroService를 @NgModule.providers array에 import
    • providers array는 HeroSerivce의 single shared instance를 생성하고, class에 inject하도록 angular에게 지시하는 역할을 한다.
    • HeroService는 이제 HeroesCoponent에 plug into 될 준비가 되었다.
  • Update HeroesComponent
    • HeroesComponent에서 HEROES는 이제 더이상 사용하지 않기 때문에 제거하고, HeroService를 대신 추가하자.
    • Inject the HeroService
    • heroService를 추가
    • Angular에서 HeroesComponent를 생성할때 Dependency Injection system에서는 heroService를 HeroService의 singleton intance로서 세팅
    • Add getHeroes()
    • service로 부터 heroes를 retrieve하는 function을 생성.
    • Call it in ngOnInit
    • 생성자에서 getHeroes()를 호출하는 방법은 좋은 방법이 아니다.
    • constructor는 단순한 초기화만 진행되어야 하고, HTTP request를 생성해 remote server에서 실제 데이터를 가져오는 기능은 하면 안된다.
    • 대신 getHeroes()는 ngOnInit lifecycle hook에서 호출이 되어야 한다. Angular에서는 ngOnInit을 HeroesComponent instance가 생성된 이후에 적절한 시점에서 호출을 한다.
  • Observable data
    • HeroService.getHeroes() method는 synchronous signature를 갖고 있기 때문에 HeroService는 heroes를 synchronously fetch를 할 수 있다.
    • heroService는 서버로 부터 응답을 기다려야만 하기 때문에, getHeroes()를 통해 즉시 hero data를 받아올 수 없다. 결과적으로는 service가 완료될때까지 브라우저는 동작하지 않는다.
    • Heroservice.getHeroes()는 asynchronous signature여야만 한다.
    • callback을 사용해서 해결
    • Observable HeroService
    • Observable은 RxJS library의 key class중 하나이다.
    • 이후에 HTTP tutorial에서는 Angular's HTTPClient methods return RxJS Observable에 대해서 알아볼 것이다.
    • 여기에서는 simulate getting data from the server with the RxJS of() function
    • HeroService file을 열고 RxJS로부터 Observable과 of symbols를 import
    • getHeroes method를 변경한다.
  • Subscribe in HeroesComponent
    • HeroService.getHeroes method는 Hero[]를 리턴하는데, 위 처럼 변경하면 Observable
    • Observable.subscrbie()는 critical하게 다르다.
    • 이전 버전에서 component's heroes property에 heroes의 array를 assign했다. 그 assignment는 synchronously를 발생하게 된다.
    • 위 문제로 server의 응답으로부터 기다려야 하기 때문에 UI는 freeze된다.
    • 새로우 버전은 Observable을 기다린다. 기다린 이후에 subscribe는 array를 callback을 통해 pass를 한다. 이과정을 통해서 heroes property에 set이 된다.
    • 위 asynchronous approach는 HeroService에서 서버로부터 heroes를 requests할때 사용하면 된다.
  • Show message
    • 이번 섹션에서는
    • screen의 아래 부분에 위치하는 app messages를 보여주는 MessagesComponent를 추가
    • displayed되는 message를 보내기 위해 injectable, app-wide MessageService를 생성
    • HeroService에 MessageService를 inject
    • HeroService가 heroes를 성공적으로 fetches할때 message를 화면에 표시
    • Create MessagesComponent
    • CLI를 통해 MessagesComponent를 생성
      • $ ng generate component message
    • AppComponent template에서 MessagesComponent가 보이도록 수정
    • Create The MessageService
    • CLI를 통해 messageService를 생성
      • $ ng generate service message --module=app
    • MessageService의 내용을 수정
    • Inject it into the HeroService
    • HeroService에 MessageService를 import
    • Send a message from HeroService
    • getHeroes method에 heroes가 fetch 되었을때 send message 로직 추가
    • Display the message from HeroService
    • MessagesComponent는 모든 messages를 출력을 해야한다.
    • MessageComponent에 MessageService를 import
    • messageService property는 반드시 public으로 해야 다른 templatedㅔ서도 binding해서 사용 가능
    • Bind to the Message Service
    • mesageComponent template를 수정

Routing

  • Tour of Heroes app의 requirements
    • Add Dashboard view
    • Heroes, Dashboard views사이에 navigat
    • view에서 hero를 클릭하면, selected hero의 detail view가 보이도록
    • email에 있는 deep link를 클릭할때, 특정 영웅에 대한 세부정보보기를 열도록
  • Add the AppRoutingModule
    • Angular에서 best practice는 toload and configure the router in a separate, top-level module that is dedicated to routing and imported by the root AppModule.
    • module class이름을 AppRoutingModule, app-routing.module.ts는 src/app folder에 위치
    • CLI를 통해 생성
    • $ ng generate module app-routing --flat --module=app
    • flat은 its own folder대신에 src/app에 위치하도록
    • --module=app은 AppModule의 array에 register
    • Add Routes
    • Routes는 user가 클릭한 link 또는 browser address bar에 URL을 붙여넣었을때 보여지는 화면을 의미한다.
    • Angular Route는 two properties를 가지고 있다.
      • path: address bar에 있는 URL과 match되는 string
      • component: router로 navigating할때 생성되는 component
    • HeroesComponent를 navigate한다고 의도할때, URL은 localhost:4200/heroes
    • HeroesComponent를 import하고, Routes에 path로 heroes, component로 HeroesComponent를 추가하면 된다.
    • RouterModule.forRoot()
    • router는 반드시 처음 초기화를 하고, browser location changes를 listening해야한다.
    • RouterModule을 @NgModule.imports array에 추가하고, routes를 RouterModule.forRoot()내에 호출한다.
    • Add RouterOutlet
    • AppComponent template에서 의 elements를 element로 변경
  • Add a navigation link(routerLink)
    • User는 항상 URL을 복사해서 붙여넣지 않고, navigate하기 위해서는 클릭을 한다.
    • nav TAG를 이용해서 clicked을 할때 HeroComponent로 이동할 수 있게 한다.
    • routerLink attribute에 "/heroes"를 세팅
  • Add a dashoard view
    • Routing은 multiple views가 있을때 더 적합하다.
    • CLI를 통해 DashboardComponent를 추가하자
    • $ ng generate component dashboard
    • DashboardComponent는 AppModule속에 선언이 된다.
    • Add the dashboard route
    • dashboard를 navigate하기 위해서는 router는 적절한 route가 필요하다.
    • AppRoutingModule에 DashboardComponent를 import
    • AppRoutingModule.routes를 추가하고, path에 dashboard, component에 DashboardComponent를 추가
    • Add a default route
    • app이 시작할때 browser의 주소는 web site's root를 가리키기 된다. 어떤 route에 매치되지 않으면 어디도 이동하지 않는다.
    • app이 시작할때 자동으로 dashoard로 navigate하게 하기 위해서 AppRoutingModules.Routes array에 다음과 같이 추가
    • path에는 '' redirectTo에는 "/dashboard", pathMatch에는 'full'
    • Add dashboard link to the shell
    • DashboardComponent와 HeroesComponent의 사이에서 앞,뒤로 이동을 할수도 있기 때문에 appComponent에 dashboard navigation 추가
  • Navigating to hero details
    • Delete hero details from Heroes Component
    • Add a hero detail route
    • : colon은 indicate :id
    • DashboardComponent hero links
    • HeroesComponent hero links
    • Remove dead code
  • Routable HeroDetailComponent

HTTP

  • Angular's HTtpClient로 부터 data persistence features에 대해서 알아본다.
    • HeroService에서 HTTPReqeusts를 통해 데이터를 가져온다.
    • HTTP를 통해서 heroes를 추가, 삭제, 제거가 가능.
    • Users는 heroes를 이름으로 검색이 가능
  • Enable HTTP Services
    • HttpClient는 HTTP를 통해서 remote server와 communicating을 위한 Angular's mechanism
    • HttpClient는 app어디에서도 사용이 가능하다.
    • root AppModule을 열고
    • HttpClientModule을 import한다. (@angular/common/http)
    • @NgModule.imports array에 추가
  • Simulate a data server
    • $ npm install angular-in-memory-web-api --save
    • InMemoryWebApiModule과 InMemoryDataService를 import
  • Heroes and HTTP
    • HTTPClient, HttpHeaders를 @angular/common/http로 부터 import
    • HttpClient를 prviate property http에 inject
    • Get heroes with HttpClient
    • 기존 of의 method를 this.http.get
    • Http methods return one value
    • HttpClient methods는 RxJS Observable을 return
    • HttpClient.get returns response data
    • 기본적으로 untyped JSON으로 응답이 온다.
    • JSON 데이터의 모양은 서버의 데이터 API에 의해 결정, 이 예제에서는 hero data의 array로 반환
    • Error handling
    • catchError를 import (rxjs/operators)
    • pipe method를 통해 에러를 핸들링 한다.
    • Tap into the Observable
    • tap을 통해 메시지의 로그를 출력할 수 있다.
    • Get hero by id
    • api/hero/:id를 통해 API를 제공할 수 있다.
    • Update heroes
    • save()를 통해 업데이트
    • Add HeroService.updateHero()
    • updateHero() method는 getHeroes()와 유사. 다른점은 http.put()을 사용한다는
    • put은 URL, data, options
    • Add a new hero
    • input element를 사용해서
    • Add HeroService.addHero9)
    • put대신 post를 호.
    • Delete a hero
    • Add HeroService.deleteHero()
    • HttpClient.delete 사용
  • Search by name
    • HeroService.searchHeroes
    • Add search to the Dashboard
    • Create HeroSearchComponent
    • AsyncPipe
    • Fix HeroSearchComponent class
    • The serachTerms RxJS subject
    • Chaining RxJS operators
반응형