Angular 5 Overview
Angular 5的快速开发,测试和部署可以使用Angular CLI工具完成。Angular 5是基于Typescript语言开发的Web前端框架。
Angular 5 quick start
Angular 5 basic prject development tutorial
Application shell
Angular 5应用的基本框架,可以用ng new {projectname}命令生成,一个简单的Angular项目需要包含一个app module和app component。在app component中,会定义一个控件,作为整个Angular app的入口,一般写在index.html中。
Angular Component
在已经有的app component基础上,可以用ng generate component {dir/componetname}命令生成更多的组件,新的组件组成元素和app component一样,也是html模板,ts组件功能定义,和css组件风格。一般意义上,在ts中定义控件directive的名称,在html模板中,可以直接调用该directive。
每个已经创建好的component会被自动import进入app.module.ts文件,从而在Angular应用启动时,能自动寻找到对应的component并加载。如果developer需要在自己定义的component中引用其他component/service组件,也需要定义相似的import语句,否则Angualr引擎并不能成功识别调用组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { HeroService } from './hero.service';
@NgModule({ declarations: [ AppComponent, HeroesComponent, HeroDetailComponent, ], imports: [ BrowserModule, FormsModule ], providers: [ HeroService ], bootstrap: [ AppComponent ] })
|
Angular Service
Angular提供了service module来支持现在Web前端数据获取和更新功能。可以用ng generate service {dir/servicename} –module=app命令来生成。
Angular Routing
Angular提供了routing来允许Web前端以single page application(SPA)方式渲染多个url的页面。可以用ng generate module app-routing –flat –module=app生成app.routing.ts模块。app routing模块隐式定义了控件,这是一个可以根据输入url进行跳转的控件。一般放在app componet html模板中,作为Angular应用的跳转渲染单元。这个控件本身,并不能提供跳转入口,一般需要写锚,在html模板显式来定义url。
1 2 3 4 5
| <nav> <a routerLink="/heroes">Heroes</a> <a routerLink="/heroes">Heroes</a> </nav> <router-outlet></router-outlet>
|
此外,app routing模块本身,定义了url跳转的逻辑。由于Angualar的html模块本身具有嵌套性,因而在routing逻辑中,只要引入自定义的directive控件,就能自动渲染出控件中所嵌套的所有元素。可以说,Angular的程序设计思想,就是基于模板设计的,每个模板都是一个自定义的DOM元素,允许在Angular的控制域中任意的复用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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 {}
|
Angular HTTP
Angular提供了HttpClient库作为Restful API的utility来完成Web前端的服务器数据交互。在程序中,HttpClient库一般本身不会单独存在于componnet中,而是作为Angular Service模块的底层调用库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; import { catchError, map, tap } from 'rxjs/operators'; import { Hero } from './hero'; import { MessageService } from './message.service'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; @Injectable() export class HeroService { private heroesUrl = 'api/heroes'; constructor( private http: HttpClient, private messageService: MessageService) { } getHeroes (): Observable<Hero[]> { return this.http.get<Hero[]>(this.heroesUrl) .pipe( tap(heroes => this.log(`fetched heroes`)), catchError(this.handleError('getHeroes', [])) ); } getHeroNo404<Data>(id: number): Observable<Hero> { const url = `${this.heroesUrl}/?id=${id}`; return this.http.get<Hero[]>(url) .pipe( map(heroes => heroes[0]), tap(h => { const outcome = h ? `fetched` : `did not find`; this.log(`${outcome} hero id=${id}`); }), catchError(this.handleError<Hero>(`getHero id=${id}`)) ); } getHero(id: number): Observable<Hero> { const url = `${this.heroesUrl}/${id}`; return this.http.get<Hero>(url).pipe( tap(_ => this.log(`fetched hero id=${id}`)), catchError(this.handleError<Hero>(`getHero id=${id}`)) ); } searchHeroes(term: string): Observable<Hero[]> { if (!term.trim()) { return of([]); } return this.http.get<Hero[]>(`api/heroes/?name=${term}`).pipe( tap(_ => this.log(`found heroes matching "${term}"`)), catchError(this.handleError<Hero[]>('searchHeroes', [])) ); } addHero (hero: Hero): Observable<Hero> { return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe( tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)), catchError(this.handleError<Hero>('addHero')) ); } deleteHero (hero: Hero | number): Observable<Hero> { const id = typeof hero === 'number' ? hero : hero.id; const url = `${this.heroesUrl}/${id}`; return this.http.delete<Hero>(url, httpOptions).pipe( tap(_ => this.log(`deleted hero id=${id}`)), catchError(this.handleError<Hero>('deleteHero')) ); } updateHero (hero: Hero): Observable<any> { return this.http.put(this.heroesUrl, hero, httpOptions).pipe( tap(_ => this.log(`updated hero id=${hero.id}`)), catchError(this.handleError<any>('updateHero')) ); }
private handleError<T> (operation = 'operation', result?: T) { return (error: any): Observable<T> => { console.error(error); this.log(`${operation} failed: ${error.message}`); return of(result as T); }; } private log(message: string) { this.messageService.add('HeroService: ' + message); } }
|
HttpClient除了和真正的服务器交互外,还可以和in-memory的数据服务器进行虚拟交互,也就是说,在不修改(略微)原有程序代码的情况下,可以自己运用一个npm package设立一个in-memory的数据服务器,HttpClient并不知道request已经被这个in-memory服务器拦截并返回内存中的数据。
在前后端分离的开发过程中,如果要引用此功能,需要预先安装angular-in-memory-web-api的npm包。
1
| $ npm install angular-in-memory-web-api@0.5 --save
|
然后,创建in-memory-data.service模块,存储内存中的数据,作为HttpClient访问交互的相关数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService { createDb() { const heroes = [ { id: 11, name: 'Mr. Nice' }, { id: 12, name: 'Narco' }, { id: 13, name: 'Bombasto' }, { id: 14, name: 'Celeritas' }, { id: 15, name: 'Magneta' }, { id: 16, name: 'RubberMan' }, { id: 17, name: 'Dynama' }, { id: 18, name: 'Dr IQ' }, { id: 19, name: 'Magma' }, { id: 20, name: 'Tornado' } ]; return {heroes}; } }
|
最后,在app module模块中引入对in-memory-web-api的引用,和in-memory-data service模块的使用,并配置好in-memeory-server对应的data/service来源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api'; import { InMemoryDataService } from './in-memory-data.service'; import { AppRoutingModule } from './app-routing.module'; 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 { HeroSearchComponent } from './hero-search/hero-search.component'; import { HeroService } from './hero.service'; import { MessageService } from './message.service'; import { MessagesComponent } from './messages/messages.component'; @NgModule({ imports: [ BrowserModule, FormsModule, AppRoutingModule, HttpClientModule, HttpClientInMemoryWebApiModule.forRoot( InMemoryDataService, { dataEncapsulation: false } ) ], declarations: [ AppComponent, DashboardComponent, HeroesComponent, HeroDetailComponent, MessagesComponent, HeroSearchComponent ], providers: [ HeroService, MessageService ], bootstrap: [ AppComponent ] }) export class AppModule { }
|
Angular Data Model – Class
In Angular 5, data model is encapsulated through classes, mainly for rendering templates in components. Creating a new class by Angular Cli:
1
| $ ng generate class {classname}
|