使用 Angular 2 开发单页应用程序之三

在上一篇文章使用 Angular 2 开发单页应用程序之二 中,我们已经完成了自定义组件的开发。
dw-ng2-app 中包含了三个业务组件:

  • 天气
  • 电影
  • 货币
    接下来我们将创建业务组件的服务。

创建服务

按 Ctrl-C 停止 Angular 进程。在命令提示符下,执行以下命令创建服务。

ng g service Shared --spec false

在根模块文件夹中创建了Shard服务,服务位于 shared.service.ts 文件中。下面修改文件内容如下:

import { Injectable } from '@angular/core';
import { Http, Headers, Response } from "@angular/http";
import 'rxjs/Rx';
import { Observable } from "rxjs";
 
@Injectable()
export class SharedService {
    weatherURL1 = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22";
    weatherURL2 = "%2C%20";
    weatherURL3 = "%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
    findMovieURL1 = "http://www.omdbapi.com/?t=";
    findMovieURL2 = "&y=&plot=short&r=json"; 
    currencyURL = "http://api.fixer.io/latest?symbols="; 
    totReqsMade: number = 0;
    constructor(private _http: Http) { }
 
    findWeather(city, state) { 
        this.totReqsMade = this.totReqsMade + 1; 
        return this._http.get(this.weatherURL1 + city + this.weatherURL2+ state + this.weatherURL3)
            .map(response => {
                { return response.json() };
            })
            .catch(error => Observable.throw(error.json()));
    }
 
    findMovie(movie) { 
        this.totReqsMade = this.totReqsMade + 1; 
        return this._http.get(this.findMovieURL1 + movie + this.findMovieURL2)
            .map(response => {
                { return response.json() };
            })
            .catch(error => Observable.throw(error.json().error));
    }
 
    getCurrencyExchRate(currency) { 
        this.totReqsMade = this.totReqsMade + 1; 
        return this._http.get(this.currencyURL + currency)
            .map(response => {
                { return response.json() };
            })
            .catch(error => Observable.throw(error.json()));
    }
}
  • import ... 语句是任何服务正常运行所必不可少的。
  • @Injectable() 语句特别重要;它表明此 service 可注入到其他组件中 — 该技术通常被称为依赖注入。
  • 服务中定义了 3 个方法,它们的名称表明了自己的功能。在方法执行时,Angular 将让浏览器访问网络来使用Yahoo提供的服务 API。

我们现在把组件链接到所创建的服务上。
修改 movie.component.ts 如下:

import { Component, OnInit } from '@angular/core';
import { SharedService } from "./../shared.service";
 
@Component({
  selector: 'app-movie',
  templateUrl: './movie.component.html',
  styles: []
})
export class MovieComponent implements OnInit {
  id_movie: string = "";
  mv_Title: string = "";
  mv_Rated: string = "";
  mv_Released: string = "";
  mv_Director: string = "";
  mv_Actors: string = "";
  mv_Plot: string = "";
  constructor(private _sharedService: SharedService) {
  }
 
  ngOnInit() {
  }
 
  callMovieService() { 
    this._sharedService.findMovie(this.id_movie)
      .subscribe(
      lstresult => { 
        this.mv_Title = lstresult["Title"];
        this.mv_Rated = lstresult["Rated"];
        this.mv_Released = lstresult["Released"];
        this.mv_Director = lstresult["Director"];
        this.mv_Actors = lstresult["Actors"];
        this.mv_Plot = lstresult["Plot"];
      },
      error => {
        console.log("Error. The findMovie result JSON value is as follows:");
        console.log(error);
      }
      ); 
  }
}

修改 weather.component.ts 如下:

import { Component, OnInit } from '@angular/core';
import { SharedService } from "./../shared.service";
 
@Component({
  selector: 'app-weather',
  templateUrl: './weather.component.html',
  styles: []
 
})
export class WeatherComponent implements OnInit {
  id_city: string = "";
  id_state: string = "";
  op_city: string = "";
  op_region: string = "";
  op_country: string = "";
  op_date: string = "";
  op_text: string = "";
  op_temp: string = "";
  constructor(private _sharedService: SharedService) {
  }
 
  ngOnInit() {
  }
 
  callWeatherService() { 
    this._sharedService.findWeather(this.id_city, this.id_state)
      .subscribe(
      lstresult => { 
        this.op_city = lstresult["query"]["results"]["channel"]["location"]["city"];
        this.op_region = lstresult["query"]["results"]["channel"]["location"]["region"];
        this.op_country = lstresult["query"]["results"]["channel"]["location"]["country"];
        this.op_date = lstresult["query"]["results"]["channel"]["item"]["condition"]["date"];
        this.op_text = lstresult["query"]["results"]["channel"]["item"]["condition"]["text"];
        this.op_temp = lstresult["query"]["results"]["channel"]["item"]["condition"]["temp"]; 
      },
      error => {
        console.log("Error. The findWeather result JSON value is as follows:");
        console.log(error);
      }
      ); 
  }
}

修改 currency.component.ts 如下:

import { Component, OnInit } from '@angular/core';
import { SharedService } from "./../shared.service";
 
@Component({
  selector: 'app-currency',
  templateUrl: './currency.component.html',
  styles: [] 
})
export class CurrencyComponent implements OnInit {
  
  id_currency: string = "";
  my_result: any;
  constructor(private _sharedService: SharedService) {
  }
 
  ngOnInit() {
  }
 
  callCurrencyService() {  
    this._sharedService.getCurrencyExchRate(this.id_currency.toUpperCase())
      .subscribe(
      lstresult => { 
                this.my_result = JSON.stringify(lstresult); 
      },
      error => {
        console.log("Error. The callCurrencyService result JSON value is as follows:");
        console.log(error);
      }
      ); 
  }
}

更新 app.module.ts 以引入 Shared 服务,如下所示添加以下两行,

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
 
import { AppComponent } from './app.component';
import { MenuComponent } from './menu.component';
import { WeatherComponent } from './weather/weather.component';
import { CurrencyComponent } from './currency/currency.component';
import { MovieComponent } from './movie/movie.component';
import { CONST_ROUTING } from './app.routing';
import { SharedService } from "./shared.service"; // 新添加
 
@NgModule({
  declarations: [
    AppComponent,
    MenuComponent,
    WeatherComponent,
    CurrencyComponent,
    MovieComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    CONST_ROUTING
  ],
  providers: [SharedService], // 新添加
  bootstrap: [AppComponent]
})
export class AppModule { }

修改组件视图

现在在HTML视图中调用 Shared 服务的方法。
修改 movie.component.html 如下,

<h2>Open Movie Database</h2>
<div class="col-md-8 col-md-offset-2">
  <div class="form-group">
    <input type="text" required [(ngModel)]="id_movie" (change)="callMovieService()" class="form-control" placeholder="Enter Movie name ...">
    <br><br>
    <h3>Movie Details</h3>
    <br>
    <p class="well lead">
      <i> Title :</i> {{ this.mv_Title }} <br>
      <i> Plot :</i> {{ this.mv_Plot }} <br>
      <i> Actors :</i> {{ this.mv_Actors }} <br>
      <i> Directed by :</i> {{ this.mv_Director }} <br>
      <i> Rated :</i> {{ this.mv_Rated }} <br>
      <i> Release Date :</i> {{ this.mv_Released }} <br>
    </p>
    <p class="text-info">Total # of all the service requests including Weather, Movie, and Currency is :
      <span class="badge">{{this._sharedService.totReqsMade}}</span>
    </p>
  </div>
</div>

修改 weather.component.html 如下,

<h2>Yahoo! Weather </h2>
<div class="col-md-8 col-md-offset-2">
  <div class="form-group">
    <input type="text" [(ngModel)]="id_city" class="form-control" placeholder="Enter City name ..."><br>
    <input type="text" [(ngModel)]="id_state" class="form-control" placeholder="Enter State. Example CA for California ..."><br>
    <button type="button" class="btn btn-primary" (click)="callWeatherService()">Submit</button>
    <br><br><br>
    <br>
    <p class="well lead">
      <i>City, State, Country :</i> {{ this.op_city }} {{ this.op_region }} {{ this.op_country }} <br>
      <i>Current Condition :</i> {{ this.op_text }} <br>
      <i>Current Temperature :</i> {{ this.op_temp }} <br>
    </p>
    <p class="text-info">Total # of all the service requests including Weather, Movie, and Currency is :
      <span class="badge">{{this._sharedService.totReqsMade}}</span>
    </p>
  </div>
</div>

修改 currency.component.html 如下,

<h2>Currency Exchange Rates</h2>
<div class="col-md-8 col-md-offset-2">
  <div class="form-group">
    <input type="text" [(ngModel)]="id_currency" (change)="callCurrencyService()" class="form-control" placeholder="Enter Currency Symbol. Example: GBP(,AUD,INR)...">
    <br><br>
    <h3>Rate Details</h3>
    <br>
    <p class="well lead">Exchange rate relative to Euro in a JSON format: : {{ this.my_result }} </p>
    <p class="text-info">Total # of all the service requests including Weather, Movie, and Currency is :
      <span class="badge">{{this._sharedService.totReqsMade}}</span>
    </p>
  </div>
</div>

完成以上的开发后,dw-ng2-app 就可以在浏览器接受用户的输入了。

运行应用程序

启动应用程序,在浏览器里面输入一些信息,查看结果。例如,在 Weather 页面,输入 San Francisco 来查看该城市的天气情况:


天气服务页面

工作正常,但我们还可以让 UI 更具吸引力。改进 GUI 的一种方法是使用 Bootstrap,改进以后的页面如下,

使用Bootstrap改进后的天气服务页面

结束语

我们学习了如何使用 Angular 2 编写一个 SPA,并在开发计算机和沙箱服务器中运行它。
对于实际业务需求,可能还需要服务端的功能支持,来提供如身份验证、业务功能等服务。这些服务器端技术,可以使用 Node.js,也可以使用 Java、PHP等。
在应用程序性能方面的,可以继续关注和研究以下方面:

  • 捆绑:该进程将您的许多程序组合到一个文件中。
  • 微型化:压缩捆绑的文件,以便尽可能地减小项目大小。
  • 提前 (AoT) 编译:服务器复杂在构建过程中提前编译,而不是浏览器在运行时期间执行即时 (JIT) 编译。

文章导航

  1. 使用 Angular 2 开发单页应用程序之一
  2. 使用 Angular 2 开发单页应用程序之二
  3. 使用 Angular 2 开发单页应用程序之三

进一步的学习

免费获取项目源代码,咨询老师进行答疑指导,请加QQ:1628145742 ,或报名我们的实战课程:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容