HeroServe

使用httpClient中的get(),put(),delete(),update()方法写出之后其他xxxx.ts文件将要调用的增删改查方法。

hero.service.ts

声明httpOptions,heroesUrl(定义根目录),http(创建的HttpClient实例),messageService(记录各类信息)

以下是声明的增删改查方法

getHeroes (): Observable<Hero[]> {return this.http.get<Hero[]>(this.heroesUrl).pipe(tap(_ => this.log('fetched heroes')),catchError(this.handleError('getHeroes', [])));}/** GET hero by id. Return `undefined` when id not found */getHeroNo404<Data>(id: number): Observable<Hero> {const url = `${this.heroesUrl}/?id=${id}`;return this.http.get<Hero[]>(url).pipe(map(heroes => heroes[0]), // returns a {0|1} element arraytap(h => {const outcome = h ? `fetched` : `did not find`;this.log(`${outcome} hero id=${id}`);}),catchError(this.handleError<Hero>(`getHero id=${id}`)));}/** GET hero by id. Will 404 if id not found */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}`)));}/* GET heroes whose name contains search term */searchHeroes(term: string): Observable<Hero[]> {if (!term.trim()) {// if not search term, return empty hero array.return of([]);}return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(tap(_ => this.log(`found heroes matching "${term}"`)),catchError(this.handleError<Hero[]>('searchHeroes', [])));}Save methods ///** POST: add a new hero to the server */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')));}/** DELETE: delete the hero from the server */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')));}/** PUT: update the hero on the server */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')));}

还有一个处理异常和记录日志的方法

/*** Handle Http operation that failed.* Let the app continue.* @param operation - name of the operation that failed* @param result - optional value to return as the observable result*/private handleError<T> (operation = 'operation', result?: T) {return (error: any): Observable<T> => {// TODO: send the error to remote logging infrastructureconsole.error(error); // log to console instead// TODO: better job of transforming error for user consumptionthis.log(`${operation} failed: ${error.message}`);// Let the app keep running by returning an empty result.return of(result as T);};}/** Log a HeroService message with the MessageService */private log(message: string) {this.messageService.add(`HeroService: ${message}`);}

in-memory-data.service.ts

这个文件作为模拟web api来暂存数据

app.module.ts

在这个文件中是申明注册各个模块

HeroesComponent

heroes.component.html

显示所有的英雄,并有增删查的功能

<button (click)="add(heroName.value); heroName.value=''">add
</button><a routerLink="/detail/{{hero.id}}"><span class="badge">{{hero.id}}</span> {{hero.name}}
</a><button class="delete" title="delete hero"(click)="delete(hero)">x
</button>

heroes.component.ts

通过调用hero.service.ts中的方法,并将返回结果订阅至Observable对象中,以实现增删查功能,并且结果可以实时在页面上显示。

getHeroes(): void {this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes);}add(name: string): void {name = name.trim();if (!name) { return; }this.heroService.addHero({ name } as Hero).subscribe(hero => {this.heroes.push(hero);});}delete(hero: Hero): void {this.heroes = this.heroes.filter(h => h !== hero);this.heroService.deleteHero(hero).subscribe();}

HeroDetailComponent

hero-detail.component.html

具体显示每个英雄信息

<div *ngIf="hero"><h2>{{hero.name | uppercase}} Details</h2><div><span>id: </span>{{hero.id}}</div><div><label>name:<input [(ngModel)]="hero.name" placeholder="name"/></label></div><button (click)="goBack()">go back</button><!--返回上个页面--><button (click)="save()">save</button><!--保存修改了的数据,以在页面上实时显示-->
</div>

[(ngModel)] 是 Angular 的双向数据绑定语法

这里把 hero.name 属性绑定到了 HTML 的 textbox 元素上,以便数据流可以双向流动:从 hero.name 属性流动到 textbox,并且从 textbox 流回到 hero.name

使用 *ngIf 隐藏空白的详情

但模板中的绑定表达式引用了 selectedHero 的属性(表达式为 {{selectedHero.name}}),这必然会失败,因为你还没选过英雄呢。

修复:该组件应该只有当 selectedHero 存在时才显示所选英雄的详情。当 selectedHeroundefined 时,ngIf 从 DOM 中移除了英雄详情。因此也就不用担心 selectedHero 的绑定了。

当用户选择一个英雄时,selectedHero 也就有了值,并且 ngIf 把英雄的详情放回到 DOM 中。

hero-detail.component.ts

调用hero.service.ts中的方法来实现页面功能。

 getHero(): void {const id = +this.route.snapshot.paramMap.get('id');this.heroService.getHero(id).subscribe(hero => this.hero = hero);}goBack(): void {this.location.back();}save(): void {this.heroService.updateHero(this.hero).subscribe(() => this.goBack());}

DashboardComponent

dashboard.component.html

这是一个导航栏,可以定位到任意一个英雄的详情

<h3>Top Heroes</h3>
<div class="grid grid-pad"><a *ngFor="let hero of heroes" class="col-1-4"routerLink="/detail/{{hero.id}}"><div class="module hero"><h4>{{hero.name}}</h4></div></a>
</div><app-hero-search></app-hero-search>

HeroSearchComponent

Hero-search.component.html

*ngFor 是在一个名叫 heroes$ 的列表上迭代,而不是 heroes

<input #searchBox id="search-box" (input)="search(searchBox.value)" /><ul class="search-result"><li *ngFor="let hero of heroes$ | async" ><a routerLink="/detail/{{hero.id}}">{{hero.name}}</a></li></ul>

$ 是一个命名惯例,用来表明 heroes$ 是一个 Observable,而不是数组。

*ngFor 不能直接使用 Observable。 不过,它后面还有一个管道字符(|),后面紧跟着一个 async,它表示 Angular 的 AsyncPipe

AsyncPipe 会自动订阅到 Observable,不用再在组件类中订阅了。

每当用户在文本框中输入时,这个事件绑定就会使用文本框的值(搜索词)调用 search() 函数。 searchTerms 变成了一个能发出搜索词的稳定的流。

hero-search.component.ts

实现搜索功能

 search(term: string): void {this.searchTerms.next(term);}

比并且节省服务器资源和网络流量,并最终返回一个可及时给出英雄搜索结果的可观察对象(每次都是 Hero[] )。

ngOnInit(): void {this.heroes$ = this.searchTerms.pipe(// wait 300ms after each keystroke before considering the termdebounceTime(300),// ignore new term if same as previous termdistinctUntilChanged(),// switch to new search observable each time the term changesswitchMap((term: string) => this.heroService.searchHeroes(term)),);}
  • 在传出最终字符串之前debounceTime(300) 将会等待,直到新增字符串的事件暂停了 300 毫秒。 你实际发起请求的间隔永远不会小于 300ms。
  • distinctUntilChanged() 会确保只在过滤条件变化时才发送请求。
  • switchMap() 会为每个从debounce 和distinctUntilChanged中通过的搜索词调用搜索服务。 它会取消并丢弃以前的搜索可观察对象,只保留最近的。

Hero项目分析(基于Angular架构)相关推荐

  1. 微软发布史上最大NLG模型:基于Transformer架构,170亿参数加持

    2020-02-11 18:50 导语:史上最大! 近年来,BERT.GPT-2等深度学习语言模型,极大地提高了问答.摘要.人机对话等下游自然语言处理任务的性能. 而今天,微软研究院重磅发布了有史以来 ...

  2. 微软分享史上最大基于Transformer架构的语言生成模型

    导语:英伟达的"威震天"现在只能屈居第二了. 微软AI&Research今天分享了有史以来最大的基于Transformer架构的语言生成模型Turing NLG(下文简称为 ...

  3. 微服务架构之外的选择——基于服务架构

    来自ThoughtWorks的主管Neal Ford在最近的一次演讲中表达了他对企业软件系统架构转型的看法,他认为从单体架构转向基于服务的架构要比转向微服务架构来得容易.Ford在UberConf 2 ...

  4. javaweb k8s_K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程...

    K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程 课程内容是关于Kubernetes微服务架构学习课程,基于K8S开展ASP.NET核心进行微 ...

  5. java bs架构书_基于BS架构的图书借阅管理模块的分析与设计(JSP+MySQL)(新品)

    基于BS架构的图书借阅管理模块的分析与设计(JSP+MySQL)(新品) 来源:2BYSJ.cn 资料编号:2SJ295500 资料等级:★★★★★ %D7%CA%C1%CF%B1%E0%BA%C5% ...

  6. bs架构 mysql_基于BS架构OA办公系统的设计(PHP,MySQL)(三人组)(含录像)

    基于BS架构OA办公系统的设计(,MySQL)(三人组)(含录像)(毕业论文13000字,程序代码,MySQL数据库,答辩PPT) 系统模块划分 企业部门管理系统(以管理员部分为核心)从功能上划分为5 ...

  7. 如何基于LSM-tree架构实现一写多读

    简介:传统MySQL基于binlog复制的主备架构有它的局限性,包括存储空间有限,备份恢复慢,主备复制延迟等问题,为了解决用户对于云上RDS(X-Engine)大容量存储,以及弹性伸缩的诉求,Pola ...

  8. 基于AgileEAS.NET企业应用平台实现基于SOA架构的应用整合方案-开篇

    为什么80%的码农都做不了架构师?>>>    开篇 系统架构的文章,准备在这段时间好好的梳理和整理一下,然后发布基于AgileEAS.NET平台之上的企业级应用架构实践,结合具体的 ...

  9. 基于插件架构的简单的Winform框架(下)

    前言 最近事情较多,终于有时间来写完这篇.在上一篇的基础上,本篇文章我们开始着手搭建一个简单的基于插件架构的Winform框架.(其实也就是一个小例子,也是对之前写过的代码的总结) 设计思路 写这个W ...

最新文章

  1. 【剑道之道】亦是生存之道
  2. 计算机网络-基本概念(1)【网络层】-ARP协议以及数据传输过程
  3. ie浏览器安全使用网银支付功能方法
  4. springMVC的流程
  5. 高计算密度+低功耗!浪潮新一代高密度服务器SA5248M4横空出世
  6. 把人物用 Unity 进行 2D 传送,拢共分四步 | 原力计划
  7. 产品规划三板斧:商业画布/精益画布/SWOT分析
  8. 计算机视觉教程2-3:图解双线性插值算法最近邻插值算法
  9. 35KV变电站及10KV供配电系统倒闸操作屏QY-PGD09
  10. sop4封装尺寸图_扇出型面板级封装技术的演进
  11. mac系统dns的服务器地址,苹果Mac快速切换DNS地址的方法图文详解
  12. 计算机提示无法访问手机tf卡,SD卡无法访问解决教程
  13. 电脑W ndoWs未能启动怎么办,电脑出现windows未能启动怎么办
  14. Axure中插入Highcharts动态图表
  15. 【数据结构】格洛克怎么上膛?栈的结构帮你解答!
  16. 名帖55 隋代 楷书《苏孝慈墓志》
  17. 通过iscsi协议使用ceph rbd
  18. Unity3D之如何将包大小减少到极致
  19. 【转载】西南大旱,最缺的是水吗?
  20. 【数据结构与算法】->算法-> A* 搜索算法->如何实现游戏中的寻路功能?

热门文章

  1. 简易验收管理系统的设计(php)
  2. 专业音频如何把电平转换成dbu_正确理解音频设备的电平信号
  3. ICMP协议(网际控制报文协议)
  4. 网际协议IP(计算机网络)
  5. 25 Creative Ways to Promote Your App for Free
  6. TCP/IP网络编程_第6章基于UDP的服务器端/客户端
  7. 表头顺序不一样的表格如何合并_不同表头的多表合并
  8. tikz绘图学习(长期更新)
  9. python大战机器学习——人工神经网络
  10. 利用 Django 动态展示 Pyecharts 图表数据的几种方法