-
2-15 Observable사용하기앵귤러/01 퀵스타트 & 튜토리얼 2017. 8. 9. 09:10
Observable사용하기
Http서비스 메소드는 HTTP Response객채에서 Observable을 리턴한다.
Observable은 배열과 같은 연산자로 처리 할 수 있는 이벤트 스트림이다.
영웅조회 기능 추가
영웅조회용 서비스를 생성한다.
ng g service hero-service –m app
src/app/hero-search.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { Hero } from './hero';
@Injectable()
export class HeroSearchService {
constructor(private http:HttpClient) { }
search(term:string): Observable<Hero[]>{
return this.http
.get(`http://localhost:3000/heroes/?name=${term}`)
.map(response => response as Hero[]);
}
}
http.get()메소드는 Observable을 리턴한다.
map()메소드는 Obaervable 연산자로 response 데이터에서 Hero배열을 추출한다.
영웅조회 컴포넌트를 생성한다.
ng g component hero-search –-flat
만들어진 컴포넌트 html수정
src/app/hero-search.component.html
<div id="search-component">
<h4>영웅 조회</h4>
<input #searchBox id="search-box" (keyup)="search(searchBox.value)"/>
<div>
<div *ngFor="let hero of heroes | async"
(click)="gotoDetail(hero)" class="search-result">
{{hero.name}}
</div>
</div>
</div>
만들어진 컴포넌트 css 수정
src/app/hero-search.component.css
.search-result{
border-bottom: 1px solid gray;
border-left: 1px solid gray;
border-right: 1px solid gray;
width: 195px;
height: 16px;
padding: 5px;
background-color: white;
cursor: pointer;
}
.search-result:hover{
color: #eee;
background-color: #607D8B;
}
#search-box{
width: 200px;
height: 20px;
}
이제 컴포넌트를 수정한다.
src/app/hero-search.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import { HeroSearchService } from './hero-search.service';
import { Hero } from './hero';
@Component({
selector: 'hero-search',
templateUrl: './hero-search.component.html',
styleUrls: ['./hero-search.component.css']
})
export class HeroSearchComponent implements OnInit {
heroes: Observable<Hero[]>;
private searchTerms = new Subject<string>();
constructor(
private heroSearchServie: HeroSearchService,
private router:Router
) { }
ngOnInit() {
this.heroes = this.searchTerms.debounceTime(300)
.distinctUntilChanged()
.switchMap(term => term ? this.heroSearchServie.search(term) : Observable.of<Hero[]>([]))
.catch(error => {
console.log(error);
return Observable.of<Hero[]>([]);
});
}
search(term:string):void{
this.searchTerms.next(term);
}
gotoDetail(hero:Hero): void {
let link = ['/detail', hero.id];
this.router.navigate(link);
}
}
Subject는 Observable 이벤트 스트림을 생산한다. 즉 searchTerms는 문자열 Observable을 생성한다
search ()를 호출 할 때마다, next ()를 호출하여 문자열의 관측 가능한 스트림에 새로운 문자열이 추가된다.
private searchTerms = new Subject<string>();
// Push a search term into the observable stream.
search(term: string): void {
this.searchTerms.next(term);
}
ngOnInit메소드에서는 검색어의 스트림을 Hero배열 스트림으로 변환하고 그 결과를 heroes 속성에 할당 할 수 있다.
heroes: Observable<Hero[]>;
ngOnInit(): void {
this.heroes = this.searchTerms
.debounceTime(300) // wait 300ms after each keystroke before considering the term
.distinctUntilChanged() // ignore if next search term is same as previous
.switchMap(term => term // switch to new observable each time the term changes
// return the http search observable
? this.heroSearchService.search(term)
// or the observable of empty heroes if there was no search term
: Observable.of<Hero[]>([]))
.catch(error => {
// TODO: add real error handling
console.log(error);
return Observable.of<Hero[]>([]);
});
}
키입력이 발생할 때마다 HeroSearchService에 전달하면 과도한 HTTP요청이 만들어져 서버 리소스 및 네트워크 리소스에 부담이 된다.
이를 해결하기 위해 Observable연산자를 연결하여 Observable 문자열에 대한 요청 흐름을 줄인다. HeroSearchService호출 횟수를 줄이기 위해 다음 방법을 사용하였다.
l debounceTime (300) : 새로운 문자열 이벤트의 흐름이 300 밀리 초 동안 일시 중지 될 때까지 기다린 후 최신 문자열을 전달한다. 300ms보다 자주 요청을하지 않는다.
l distinctUntilChanged : 필터 텍스트가 변경된 경우에만 요청이 전송되도록한다.
l switchMap() : debounce 및 distinctUntilChanged를 통해 검색하는 각 검색어에 대해 검색 서비스를 호출한다. 이전 검색 Observable을 취소하고 파기하며 최신 검색 서비스 만 반환한다.
l catch : 실패한 Observable을 차단한다. 간단한 예로 콘솔에 오류를 인쇄한다. 그런 다음 검색 결과를 지우기 위해 빈 배열을 포함하는 Observable 객체를 리턴한다.
RxJS 오퍼레이터 및 Observable 확장을 사용하기 위해서는 해당 오퍼페이터 및 Observable확장을 임포트해야 한다.
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
// Observable class extensions
import 'rxjs/add/observable/of';
// Observable operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
대시보드HTML에 조회컴포넌트를 추가한다.
src/app/dashboard.component.html
<h3>최고 영웅들</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
<hero-search></hero-search>
'앵귤러 > 01 퀵스타트 & 튜토리얼' 카테고리의 다른 글
2-14 http를 이용한 영웅 추가 (0) 2017.08.09 2-13 http를 이용한 영웅 수정 (0) 2017.08.09 2-12 HttpClient Promise를 사용하여 영웅목록 가져오기 (0) 2017.08.09 2-11 json-server 설치 (0) 2017.08.08 2-10 스타일 적용하기 (0) 2017.08.08