2. Http
1. Http 요청은 기본적으로 XMLHttpRequest를 기반으로 사용한다.
2. Http는 injectable 클래스로 Http 요청 시 사용.
3. Promise과 Observable(Rxjs)으로 사용할 수 있지만 Angular2.0에서는
기본적으로 Http요청 후 응답이 왔을 시 Observable를 리턴.
4.Promise를 사용할 경우 angular2 http에서는 Observable반환 하기 때문에 새로운
promise로 선언 후 반환해야 된다.(자세한 설명은 예제를 보며..)
5. Rx.js를 알면 편하고 나아가서 반응형 프로그래밍을 이해하면 더욱 좋음.
4. Http @Injectable()
export class HeroService {
constructor (private http: Http){}
private _heroesUrl = 'app/heroes';
getHeroes (): Observable<Hero[]> {
return this.http.get(this._heroesUrl).map(this.extractData).catch(this.handleError);
}
private extractData(res: Response): Hero[] {
if (res.status < 200 || res.status >= 300) {
throw new Error('Bad response status: ' + res.status);
}
let body: any = res.json();
return body.data || [];
}
private handleError (error: any) {
let errMsg = error.message || 'Server error';
console.error(errMsg);
return Observable.throw(errMsg);
}
}
꼭 response 개체를 잘 사용하기 위해서는
2가지를 해야한다.
1. check for a bad response
2. parse the response data into a JSON
object
response 개체 자체를 리턴하는 것은 안좋다!
server의 정보를 숨기고 필요한 정보만을
return하는 것이 좋으며 사용자 입장에서도 그
데이터만 필요로 하기 때문이다. 어디서
무엇을 하는지는 굳이 알 필요가 없다.
getHeroes() {
this._heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes, error => this.errorMessage =
<any>error);
}
5. Http
addHero (name: string) {
if (!name) {return;}
this._heroService.addHero(name)
.subscribe(
hero => this.heroes.push(hero),
error => this.errorMessage = <any>error);
}
@Injectable()
export class HeroService {
constructor (private http: Http){}
private _heroesUrl = 'app/heroes';
addHero (name: string): Observable<Hero> {
let body = JSON.stringify({ name });
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(this._heroesUrl, body, options)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response): Hero[] {
if (res.status < 200 || res.status >= 300) {
throw new Error('Bad response status: ' + res.status);
}
let body: any = res.json();
return body.data || [];
}
private handleError (error: any) {
let errMsg = error.message || 'Server error';
console.log('Error Start');
console.error(errMsg);
return Observable.throw(errMsg);
}
}
Header 정보 등등은
BaseRequestOptions 사용하면 미리 지정 가능
8. Jsonp
1. JSONP는 HTTP서비스의 확장이며, GET요청에 제한을 둔다.
2. JSONP는 읽기 전용이다.
3. JSONP_PROVIDERS로 의존성 주입을 한다.
4. JSONP역시 injectable 클래스
5. Promise과 Observable(Rxjs)으로 사용할 수 있지만 Angular2.0에서는
기본적으로 Http요청 후 응답이 왔을 시 Observable를 리턴.
13. Routing & Navigation
1. Routing의 URL은 기본적으로 HTML5 pushState 스타일이다.
2. 자식과 부모 라우터를 구성할 수 있다.
3. Router Life Cycle Hooks가 존재한다.(3가지!)
4. 자식과 부모 사이의 query parameter은 matrix URL방식이다.
14. Routing & Navigation
Html 추가 및 ROUTER_PROVIDERS 의존성 주입(DI)
import {ROUTER_PROVIDERS} from "angular2/router";
import {AppComponent} from "./component/app.component";
import {bootstrap} from "angular2/platform/browser";
bootstrap(AppComponent, [ROUTER_PROVIDERS]);
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<base href="/">
HTML5 pushState Style
15. Routing & Navigation
/**
* 라우터 설정
*/
@RouteConfig([
{
/* 자식과 부모와의 관계이므로 기본 path 이후는 ...으로 표시 */
path: '/crisis-center/...',
/* 중복이 되면 안되며, PascalCase 방식으로 네이밍을 해야된다. */
name: 'CrisisCenter',
component: CrisisCenterComponent,
/*
해당 url에 어떠한 정보가 없으면 아래의 useAsDefault로 선언된 라우터로 이동된다.
(localhost/ 들어오면 정보가 없기 때문에 아래의 정보가 있는 곳으로 이동)
*/
useAsDefault: true
},
{path: '/heroes', name: 'Heroes', component: HeroListComponent},
{path: '/hero/:id', name: 'HeroDetail', component: HeroDetailComponent},
/* 할당된 url이 없을시 아래와 같이 지정한다. 물론 404 Component를 만들어서 넣어도 된다. */
{ path: '/**', redirectTo: ['CrisisCenter'] }
])
16. Routing & Navigation
@Component({
selector: 'my-app',
template: `
<h1 class="title">Component Router</h1>
<nav>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<!-- 부모의 라우터에서 자식의 라우터중 어디로 갈지 배열로 선언해준다. -->
<a [routerLink]="['CrisisCenter', 'CrisisList']">Crisis Center-list</a>
<a [routerLink]="['Heroes']">Heroes</a>
<!-- parmater 값은 name 배열 다음에 json형식으로 넣어준다. -->
<a [routerLink]="['HeroDetail', {id: 11}]">11. Hero Detail</a>
</nav>
<!-- 라우터에 따라 라우팅 되는 곳 -->
<router-outlet></router-outlet>
`,
providers: [DialogService, HeroService],
/* 이게 선언이 되여 RouterOutlet, RouterLink을 사용할 수 있다. */
directives: [ROUTER_DIRECTIVES]
})
17. Routing & Navigation
Routing 방식
1. URL 변경 방식
1) URL이 변경이 되면 Router의 Path를 찾아 매칭.
2) component instance를 생성해주거나 검색.
3) view에 표시해준다.
2. 이름 방식으로 route 호출
1) 해당 이름의 path로 경로를 구성하고 주소위치랑 히스토리를 업데이트.
2) component instance를 생성해주거나 검색.
3) view에 표시해준다.
18. Routing & Navigation
// AppComponent (부모)
@RouteConfig([
{
/* 자식과 부모와의 관계이므로 기본 path 이후는 …으로 표시 */
path: '/crisis-center/…',
name: 'CrisisCenter',
component: CrisisCenterComponent,
useAsDefault: true
}
])
부모 Component의 Template에 아래와 같이
선언되어야한다.
<router-outlet></router-outlet>
자식 CrisisCenterComponent의 Template에 아래와 같이
선언되어야한다.
<router-outlet></router-outlet>
// CrisisCenterComponent (자식)
@RouteConfig([
{
path:'/',
name: 'CrisisList',
component: CrisisListComponent,
useAsDefault: true
},
{
path:'/:id',
name: 'CrisisDetail',
component: CrisisDetailComponent
}
])
자식과 부모 사이의 query parameter은 matrix URL방식이다.
localhost/crisi-center/;id=1;foo=foo
19. Routing & Navigation
export class HeroListComponent implements OnInit {
heroes: Hero[];
private _selectedId: number;
constructor(
private _service: HeroService,
private _router: Router,
routeParams: RouteParams) {
/* routeParams를 이용하여 parameter값을 가지고 올수 있다. url/query param 전부 가지고 온다. */
this._selectedId = +routeParams.get('id');
}
isSelected(hero: Hero) { return hero.id === this._selectedId; }
onSelect(hero: Hero) {
this._router.navigate( ['HeroDetail', { id: hero.id }] );
}
ngOnInit() {
this._service.getHeroes().then(heroes => this.heroes = heroes)
}
}
20. Routing & Navigation
constructor(
routeParams: RouteParams) {
this._selectedId = +routeParams.get('id');
}
ngOnInit() {
this._selectedId =+ _routeParams.get('id');
}
VS
2가지의 차이점은 결국 시점 차이다.
ngOnInit은 구성요소가 초기화 될때 호출되고, constructor는 구성요소가 구성될때 실행된다.
결론적으로 constructor먼저 실행되고 ngOnInit이 호출된다. Angular에서는 테스트때문에
constructor보다는 ngOnInit방식(자스민에서 테스트가 가능하다)으로 하는걸 추천한다. 하지만 굳이
테스트가 필요하지 않은 것 혹은 해당 시점에 맞게 프로그래밍 할 때는 다른 방식을 해도 된다.
21. Routing & Navigation
Router Life Cycle Hooks
1. CanActivate
2. OnActivate
3. CanDeactivate
이 3가지의 Hooks는 각각의 시점이 서로 다르고 사용용도도 다르다.
22. Routing & Navigation
@CanActivate((next, prev) => {
/* next는 이동하려는 Route, prev는 현재 라우터 */
console.log(`next = ${next.urlPath} // now = ${prev ? prev.urlPath : null}`);
/* false이면 routing이 취소된다. Promise를 통해서 true 혹은 false를 줄수 있다. */
return new Promise(resolve => {
setTimeout(() => resolve(true), 10000);
});
})
@CanActivate
1. 시점 : Routing이 되기 직전.(angular1의 resolve)
2. 용도 : Login/Auth 체크시 많이 사용된다.
3. return : true이면 Routing이 되며, false이면 Routing이 취소된다.
23. Routing & Navigation
routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
this.log = `Finished navigating from "${prev ? prev.urlPath : 'null'}" to "${next.urlPath}"`;
console.log(this.log);
/* Routing이 완료되어 구성되자마자 실행이 된다. */
return new Promise(resolve => {
setTimeout(() => resolve(null), 1000);
});
}
onActivate
1. 시점 : Routing 완료되어 구성되자마자 실행
2. return : promise를 통해서 리턴이되며 해당 promise가 될때까지
기다린다.
24. Routing & Navigation
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : any {
if (!this.crisis || this.crisis.name === this.editName) {
return true;
}
return this._dialog.confirm('Discard changes?');
}
onActivate
1. 시점 : 해당 Route에서 다른 Route로 이동할 때 된다.(이동하기 바로전)
2. return : true이면 이동이되며, false면 이동이 안된다.
26. Routing & Navigation
해당 라우터로 이동시에
<a [routerLink]="['CrisisCenter']">
위와 같이 선언이 되어 있는 부분에 해당 라우터를 호출을 하면
아래와 같이 자동으로 class를 부여한다.
<a href="/crisis-center" class="router-link-active">
27. Routing & Navigation
상세
아래와 같이 부모 자식간의 관계가 아닌 같은 노드의 다른 라우터이기
때문에 heroes의 상세에 들어가도 Heroes에 class가 부여되지 않는다.
서로 다른 라우터로 인식하기 때문이다.
{path: '/heroes', name: 'Heroes', component: HeroListComponent},
{path: '/hero/:id', name: 'HeroDetail', component: HeroDetailComponent},
28. Routing & Navigation
상세
아래와 같이 부모와 자식관계이기 때문에 class가 부여된다.
부모
{
path: '/crisis-center/...',
name: 'CrisisCenter',
component: CrisisCenterComponent,
useAsDefault: true
}
자식
{path:'/', name: 'CrisisList', component: CrisisListComponent, useAsDefault: true},
{path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent}