作者选择 NPower 作为 Write for donors 程序的一部分来接收捐赠。

引言

Angular 是由 Google 开发的一个前端 web 框架。 它允许开发人员围绕模型-视图-控制器(MVC)或模型-视图-视图模型(MVVM)软件体系结构模式构建单页应用程序。 这种体系结构将应用程序划分为不同但相互连接的部分,从而允许并行开发。 按照这种模式,Angular 将其不同的组件分割成 web 应用程序的各个部分。 它的组件管理属于该组件的数据和逻辑,在各自的视图中显示数据,并根据从应用程序其余部分接收到的不同消息调整或控制视图。

Bootstrap 是一个前端库,帮助开发人员快速有效地构建响应式网站(适应不同设备的网站)。 它使用了一个网格系统,将每个页面分成十二列,这样可以确保无论在什么设备上浏览,页面都保持其正确的大小和规模。

Apixu 通过 API 向用户提供全球天气数据。 使用 APIXU,用户可以检索到世界上任何地方的最新天气和未来天气预报。

在本教程中,您将使用 Angular、 Bootstrap 和 apixuapi 创建一个天气应用程序。 你可以在搜索表单中输入一个地点,然后在提交表单时,查看应用程序中显示的当前天气详细信息。 本教程中使用的角度版本是7.2.0,Bootstrap 版本是4.2.1。

先决条件

在你开始这个教程之前,你需要下面的东西:

  • 和 npm 安装在本地机器上。 你可以在 Node.js 网站上安装这两个软件,或者按照本教程安装 Node.js,建立一个本地开发环境。
  • 注册一个免费的 APIXU 帐户,在这里获得一个免费的 API 密钥。
  • 安装了文本编辑器,如 visualstudio 代码、 Atom 或 Sublime Text。
  • 熟悉 JSON 及其格式。 您可以在如何在 Javascript 中使用 JSON 中了解更多关于这方面的知识。
  • 理解 Javascript 中的数组和对象,你可以分别在 Javascript 中的理解数组和 Javascript 中的理解数据类型中学到更多。

第一步ー安装角度

在你开始创建你的应用之前,你需要安装 Angular。 打开你的终端并运行以下命令在你的机器上全局安装 Angular CLI:

Angular CLI 是 Angular 的命令行接口。 它作为创建一个新的角项目的主要途径,以及构成角项目的不同子元素。 使用 -g 参数将在全局安装它。

过一会儿,你就会看到下面的输出:

Output from installing Angular
...
+ @angular/[email protected]7.2.2
...

现在您已经在本地机器上安装了 Angular。接下来,您将创建 Angular 应用程序。

第二步: 创建你的角度应用程序

在这一步中,您将创建并配置新的 Angular 应用程序,安装它的所有依赖项,如 Bootstrap 和 jQuery,然后最后检查默认应用程序是否正常工作。

首先,使用 ng 命令创建 Angular 应用程序,您可以从您的终端运行它。

注意: 如果您使用的是 Windows 系统,即使您已经正确安装了 Node.js 和 npm,在尝试从命令提示符运行 ng 命令时也可能会遇到问题。 例如,您可能会得到一个错误,比如: ng 不被识别为内部或外部命令。 为了解决这个问题,请在 Windows 上 Node.js 文件夹中已安装的 Node.js 命令提示符中运行 ng 命令。

Ng 命令是从命令行使用 Angular 运行任何操作的先决条件。 例如,无论是构建新项目、创建组件还是创建测试,都要使用 ng 命令为每个想要的功能加前缀。 在本教程中,您将希望创建一个新的应用程序; 您将通过执行 ng 新命令来实现这一点。 Ng 新命令创建一个新的 Angular 应用程序,导入必要的库,并创建应用程序所需的所有默认代码搭建。

首先创建一个新的应用程序,在本教程中它将被称为 weather-app,但是你可以随心所欲地更改名称:

  • ng new weather-app

Ng 新命令将提示您提供有关要添加到新应用程序中的特性的其他信息。

Output
Would you like to add Angular routing? (y/N)

Angular 路由允许您使用路由和组件构建具有不同视图的单页应用程序。 继续输入 y 或者按 ENTER 键来接受默认值。

Output
Which stylesheet format would you like to use? (Use arrow keys)

点击回车键接受默认的 CSS 选项。

该应用程序将继续其创建过程,并在短时间后,你会看到以下信息:

Output
... CREATE weather-app/e2e/src/app.e2e-spec.ts (623 bytes) CREATE weather-app/e2e/src/app.po.ts (204 bytes) ... Successfully initialized git.

接下来,在文本编辑器中,打开 weather-app 文件夹。

查看您的目录结构,您将看到几个不同的文件夹和文件。 你可以在这里阅读所有这些文件的完整说明,但是为了本教程的目的,这些是需要理解的最重要的文件:

  • Json 文件。 它位于根 weather-app 文件夹中,与其他任何 Node.js 应用程序一样,包含应用程序将使用的所有库、应用程序的名称、测试时要运行的命令等等。 主要是,这个文件保存了有关外部库的详细信息,您的 Angular 应用程序需要这些库才能正常运行。
  • Ts 文件。 该文件位于 weather-app / src 文件夹中的 app 文件夹中,它告诉 Angular 如何组装应用程序,并保存有关应用程序中的组件、模块和提供程序的详细信息。 在导入数组中已经有了一个导入的模块 BrowserModule。 Browsermodule 为应用程序提供必要的服务和指令,应该始终是导入数组中的第一个导入模块。
  • 文件。 位于应用程序的根天气应用程序文件夹中,这是 Angular CLI 的配置文件。 这个文件包含你的 Angular 应用程序需要运行的内部配置设置。 它为你的整个应用程序设置默认设置,并且有一些选项,比如测试时使用什么配置文件,在你的应用程序中使用什么全局样式,或者输出你的构建文件到哪个文件夹。 您可以在官方的 Angular-CLI 文档中找到关于这些选项的更多信息。

您可以暂时将所有这些文件放在一边,因为接下来将安装 Bootstrap。

Bootstrap 有两个依赖项,你需要安装这两个依赖项才能在 Angular ー jQuery 和 popper.js 中正常工作。 Jquery 是一个专注于客户端脚本的 JavaScript 库,而 popper.js 是一个主要管理工具提示和弹出框的定位库。

在您的终端,移动到您的根天气应用程序目录:

  • cd weather-app

然后执行以下命令安装所有依赖项并保存对 package.json 文件的引用:

  • npm install --save jquery popper.js bootstrap

保存选项自动将引用导入 package.json 文件,这样您就不必在安装后手动添加它们。

您将看到显示已安装版本号的输出,如下所示:

Output
+ [email protected] + [email protected] + [email protected] ...

您现在已经成功地安装了 Bootstrap 及其依赖项。 但是,您还需要在应用程序中包含这些库。 您的 weather-app 还不知道它需要这些库,因此需要将 jquery、 popper.js、 bootstrap.js 和 bootstrap.css 的路径添加到 angular.json 文件中。

对于 popper.js,需要包含的文件是 node modules / popper.js / dist / umd / popper。 Js. Jquery 需要节点模块 / jQuery / dist / jQuery。 1. slim.js 文件。 最后,对于 Bootstrap,您需要两个文件(JavaScript 文件和 CSS 文件)。 这些模块分别是 node 模块 / bootstrap / dist / js / bootstrap.js 和 node 模块 / bootstrap / dist / css / bootstrap.css。

现在已经有了所有必需的文件路径,请在文本编辑器中打开 angular.json 文件。 样式数组是您将添加对 CSS 文件的引用的地方,而脚本数组将引用所有的脚本。 您将在 angular.JSON 文件的顶部附近的“ options” : JSON 对象中找到这两个数组。 在文件中添加以下高亮显示的内容:

angular.json
...
"options:" {
...
"styles": [
    "node_modules/bootstrap/dist/css/bootstrap.css",
     "src/styles.css"
],
"scripts": [
    "node_modules/jquery/dist/jquery.slim.js",
    "node_modules/popper.js/dist/umd/popper.js",
    "node_modules/bootstrap/dist/js/bootstrap.js"
]},
...

现在您已经导入了主要的。 Js 和。 你需要的 css 文件引导程序正常工作。 您已经从 angular.json 文件中指定了这些文件的相对路径: 添加您的。 和 css 文件。 的脚本数组中的 js 文件。 在添加了这些内容之后,确保您已经保存了 angular.json 文件。

现在,使用 ng serve 命令启动应用程序,以检查一切是否正常工作。 从终端的 weather-app 目录中,运行:

  • ng serve --o

O 参数将自动打开一个显示应用程序的浏览器窗口。 该应用程序将花费几秒钟的时间来构建,然后将在浏览器中显示。

您将在终端中看到以下输出:

Output
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** ...

一旦浏览器打开,你会看到一个默认的 Angular 应用页面。

如果您没有看到这些输出,请再次运行此步骤并确保所有内容都是正确的。 如果您看到一个错误,例如: 端口4200已经在使用中。 使用“ -- port”指定不同的端口,然后您可以通过输入以下命令更改端口号:

  • ng serve --o --port <different-port-number>

出现此潜在错误消息的原因是,计算机上的端口4200正被其他程序或进程使用。 如果您知道这个进程是什么,您可以终止它,或者您可以按照上面的步骤指定不同的端口号。

现在已经设置了应用程序脚手架。 接下来,您将创建一个天气组件,该组件将包含搜索位置的主要表单和相关的天气详细信息。

第三步ー创建你的天气组件

角度应用程序主要由组件组成,这些组件是在应用程序中具有特定功能的逻辑片段。 该组件由一些逻辑组成,这些逻辑管理应用程序中屏幕的一部分ーー这就是视图。

例如,在本教程中,您将创建一个天气组件,该组件将负责处理两个任务:

  • 搜索位置
  • 显示该位置的相关天气数据

为了实现第一个目标,您将创建一个允许您搜索位置的表单。 当您单击表单上的搜索按钮时,它将触发一个搜索该位置的函数。

为了实现第二个目标,您需要一个包含嵌套 p 标记的 div,它将整齐地显示检索到的数据。

当你的应用程序从你的终端窗口运行时,你不能在那个特定的窗口中输入任何东西。 因此,如果要执行其他 ng 命令,请在新的终端窗口中打开 weather-app 目录。 或者,你也可以通过按 CTRL + c 来停止应用程序在原始终端窗口中运行。 然后您可以安装新组件,然后通过键入 ng serve -- o 重新启动应用程序。

执行以下命令,创建 Weather 组件并自动将其导入到 app.module.ts 文件中。 请记住,app.module.ts 文件包含应用程序中所有组件、模块和提供程序的详细信息。

  • ng generate component weather

您将看到如下输出(确切的字节大小可能有所不同) :

Output
CREATE src/app/weather/weather.component.css (0 bytes) CREATE src/app/weather/weather.component.html (26 bytes) CREATE src/app/weather/weather.component.spec.ts (635bytes) CREATE src/app/weather/weather.component.ts (273 bytes) UPDATE src/app/app.module.ts (400 bytes) ...

这个输出显示 Angular 已经创建了一个组件所需的四个文件:

  • 视图的. css 和. html 文件
  • 用于测试组件的.spec.ts 文件
  • Ts 文件来保存组件的功能

Angular 也更新了 src / app / app。 Ts 文件来添加对新创建组件的引用。 您总是可以在 src / app / name-of-component 目录下找到组件文件。

现在您已经安装了新的组件,返回到您的浏览器查看应用程序。 如果你停止运行应用程序来安装新组件,输入:

  • ng serve --o

你会注意到你仍然可以看到“欢迎来到 app! ” (默认组件)显示在页面上。 您无法看到新创建的组件。 在下一节中,您将改变这一点,以便每当转到 localhost: 4200时,您将访问新创建的天气组件,而不是 Angular 的默认组件。

第四步ー使用天气功能

在标准 HTML 中,无论何时您想要创建一个新页面,都需要创建一个新的。 Html 文件。 例如,如果您已经有一个预先存在的 HTML 页面,您希望从该页面导航到新创建的页面,那么您需要一个带有锚标记的 href 属性来指向该新页面。 例如:

preexisting.html
<a href="/newpage.html">Go to New Page</a>

然而,在《角》中,这种工作方式略有不同。 不能以这种方式使用 href 属性导航到新组件。 当你想链接到一个组件时,你需要使用 Angular 的 Router 库,在一个文件中声明一个想要的 URL 路径,这个文件将直接映射到一个组件。

在 Angular 中,你把这个文件称为 routes.ts。 这包含了路线的所有细节(链接)。 为了使该文件正常工作,您将从@angular / router 库导入 Routes 类型,并将所需链接列为 Routes 类型。 这将告诉 Angular,这些是你的应用程序中导航的路线列表。

在文本编辑器中创建 routes.ts 文件,并将其保存在 src / app 目录中。 接下来,在 routes.ts 文件中添加以下内容:

src/app/routes.ts
import { Routes } from '@angular/router'

现在,在 src / app / routes 中声明 URL 路径和组件。 Ts. 你要让你的应用程序这样,当你去主页( http://localhost:4200) ,你访问你新创建的天气组件。 将这些行添加到文件中,它将把根 URL 映射到您刚刚创建的 Weather Component:

src/app/routes.ts
import { Routes } from '@angular/router'
import { WeatherComponent } from './weather/weather.component';

export const allAppRoutes: Routes = [
  { path: '', component: WeatherComponent }
];

您已经导入了 WeatherComponent,然后创建了一个变量 allAppRoutes,它是类型 Routes 的数组。 Allapproutes 数组保存路由定义对象,每个对象包含要映射到的 URL 路径和组件。 您已经指定,任何时候转到根 URL (”) ,它都应该导航到 WeatherComponent。

最终的 routes.ts 文件如下所示:

src/app/routes.ts
import { Routes } from "@angular/router";
import { WeatherComponent } from "./weather/weather.component";

export const allAppRoutes: Routes = [
  { path: '', component: WeatherComponent }
];

现在需要将这些路由添加到主 app.module.ts 文件中。 您需要将刚刚创建的数组 allAppRoutes 传递到一个名为 RouterModule 的 Angular 模块中。 Routermodule 将初始化和配置 Router (负责执行所有应用程序导航) ,并向它提供来自 allAppRoutes 的路由数据。 添加以下突出显示的内容:

src/app/app.module.ts
...
import {WeatherComponent} from './weather/weather.component';
import {RouterModule} from '@angular/router';
import {allAppRoutes} from './routes';
...
@NgModule({
    declarations:[
      ...
    ],
    imports: [
        BrowserModule,
        RouterModule.forRoot(allAppRoutes)
    ]
    ...
})
...

在这个文件中,您导入了路由对象的 RouterModule 和 allAppRoutes 数组。 然后将 allAppRoutes 数组传递到 RouterModule,这样您的 Router 就知道将 url 路由到哪里。

最后,您需要启用路由本身。 打开 app. com ponent.ts 文件。 有一个 templateUrl 属性为特定组件指定 HTML: 。 / app. com / ponent. html. 打开这个文件 src / app / app. com ponent. HTML,您将看到它包含 localhost: 4200页面的所有 HTML。

删除 app. com / ponent. HTML 中包含的所有 HTML 代码,并用以下代替:

src/app/app.component.html
<router-outlet></router-outlet>

Router-outlet 标记激活路由,并将用户在浏览器中键入的 URL 与之前在 allAppRoutes 变量下的 routes.ts 文件中创建的路由定义匹配。 然后路由器在 HTML 中显示视图。 在本教程中,您将在 router-outlet / router-outlet 标记之后直接显示 weather. com ponent. html 代码。

现在,如果你导航到 http://localhost:4200,你会看到天气工程。

您已经在应用程序中设置了路由。 接下来,您将创建表单和详细信息部分,该部分将使您能够搜索位置并显示其相关的详细信息。

第五步ー定义用户界面

您将使用 Bootstrap 作为应用程序视图的脚手架。 Bootstrap 对于创建适用于任何设备(移动设备、平板电脑或桌面)的现成的响应式网站非常有用。 它通过将网页上的每一行视为十二列宽来实现这一点。 在网页上,行只是从页面的一端到另一端的一行。 这意味着每个页面的内容必须包含在该行中,并且必须等于十二列。 如果它不等于十二列,它将被推到另一行。 例如,在 Bootstrap 的网格系统中,将有一个12列的行分为两部分,每部分分为六列,接下来的12列的行分为三部分,每部分分为四列。

在 Bootstrap 文档中,您可以了解有关这个网格系统的更多信息。

你将把你的页面分成两个部分,分为六栏,左栏保存你的搜索表格,右栏显示天气详细信息。

打开 src / app / weather / weather. com ponent. HTML 以访问 WeatherComponent HTML 代码。 删除文件中当前的段落,然后添加以下代码:

src/app/weather/weather.component.html
<div class="container">
  <div class="row">
    <div class="col-md-6"><h3 class="text-center">Search for Weather:</h3></div>
    <div class="col-md-6"><h3 class="text-center">Weather Details:</h3></div>
  </div>
</div>

您创建了一个带有类容器的 div 来保存所有内容。 然后创建一行,将其分成两部分,每部分包含六列。 左边是你的搜索表格,右边是你的天气数据。

接下来,要构建表单,您将在第一个 col-md-6列中工作。 您还可以添加一个按钮,将输入到表单中的内容提交给 APIXU,然后 APIXU 将返回所需的天气详细信息。 为此,请确定第一个 col-md-6类,并在 h3标记下添加以下突出显示的内容:

src/app/weather/weather.component.html
...
<div class="col-md-6">
  <h3 class="text-center">Search for Weather:</h3>
  <form>
    <div class="form-group">
      <input
        class="form-control"
        type="text"
        id="weatherLocation"
        aria-describedby="weatherLocation"
        placeholder="Please input a Location"
      />
     </div>
     <div class="text-center"> 
      <button type="submit" class="btn btn-success btn-md">
        Search for the weather</button>
     </div>
   </form> 
</div>
...

您已经添加了窗体并添加了一个保存搜索栏的窗体组类。 您还创建了搜索天气的按钮。 在你的浏览器中,你的天气应用程序页面看起来是这样的:

这看起来有点紧凑,所以你可以添加一些 CSS,以便更好的间距设计页面样式。 Bootstrap 的主要优点是,它带有间距类,可以添加到 HTML 中,而不需要编写任何额外的 CSS。 但是,如果你想加入一些 Bootstrap 的标准类没有涵盖的 CSS,你可以根据需要自己编写 CSS。 对于本教程,您将使用 Bootstrap 的标准类。

对于每个 h3标记,您将添加。 我的 -4 Boostrap CSS 类。 M 设置元素的边距,y 设置元素的上边距和下边距,最后4指定要添加的边距数量。 你可以在这里找到更多关于不同间距类型和大小的详细信息。 在你的 weather. com / ponent. html 文件中,添加以下高亮显示的内容来替换当前的 h 3标签:

src/app/weather/weather.component.html
<div class="col-md-6">
  <h3 class="text-center my-4">Search for Weather:</h3>
  <form>
    <div class="form-group">
      <input
        class="form-control"
        type="text"
        id="weatherLocation"
        aria-describedby="weatherLocation"
        placeholder="Please input a Location"
      />
    </div>
    <div class="text-center">
      <button type="submit" class="btn btn-success btn-md">
        Search for the weather
      </button>
    </div>
  </form>
</div>
<div class="col-md-6">
  <h3 class="text-center my-4">Weather Details:</h3>
</div>

在你的浏览器中重新加载页面,你会发现你有更多的空间。

您已经创建了表单以及显示从 apixuapi 接收到的信息的部分。 接下来,您将连接您的表单,以便能够正确输入您的位置。

第六步ー装饰你的表格

在 Angular 中,有两种方法可以为应用程序中的用户输入创建表单——反应式表单或模板驱动表单。 虽然它们获得相同的结果,但每种表单类型处理用户输入数据的方式不同。

使用反应式表单,您可以创建表单中不同元素的列表。 文件。 然后将它们连接到各自内部创建的 HTML 表单。 文件。 这完全是单向的; 也就是说,数据从 HTML 流向您的。 Ts 文件中,没有双向的数据流。

使用模板驱动的表单,您可以像在普通 HTML 中一样创建表单。 然后,使用 ngModel 之类的指令,可以从 HTML 创建单向或双向数据绑定,返回到组件中的数据模型,反之亦然。

每种方法都有优点和缺点,但一般来说,反应式方法更可取,因为:

  • 创建各种复杂形式的灵活性。
  • 通过检查组件的.component.ts 文件中每个表单控件的状态来简化单元测试。
  • 订阅窗体中的值的能力。 开发人员可以订阅表单的值流,允许他们对实时输入到表单中的值执行一些操作。

尽管有这些优点,反应形式有时候实现起来更加复杂。 这可能导致开发人员编写比模板驱动表单更多的代码。 为了全面了解形式类型和最佳用例,Angular 的官方指南提供了一个很好的起点。 在本教程中,您将使用反应式表单。

要使用反应式表单,请打开文件 app.module.ts。 接下来,通过在文件顶部声明 import 来导入 ReactiveFormsModule。

src/app/app.module.ts
...
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
    ...
})
...

最后,将 ReactiveFormsModule 添加到导入列表中。

src/app/app.module.ts
...
@NgModule({
    ...
    imports: [
        BrowserModule,
        RouterModule.forRoot(allAppRoutes),
        ReactiveFormsModule
    ]
    ...
})
...

添加以下代码之后,app.module.ts 将如下所示:

src/app/app.module.ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { WeatherComponent } from "./weather/weather.component";
import { RouterModule } from "@angular/router";
import { allAppRoutes } from "./routes";
import { ReactiveFormsModule } from "@angular/forms";

@NgModule({
  declarations: [AppComponent, WeatherComponent],
  imports: [
    BrowserModule,
    RouterModule.forRoot(allAppRoutes),
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

添加了这两行之后,打开 weather. com ponent.ts 文件,导入 FormBuilder 和 FormGroup 类。

src/app/weather/weather.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';

现在在 weather. com ponent.ts 文件中创建一个参考 FormGroup 的变量:

weather.component.ts
export class WeatherComponent implements OnInit {
   public weatherSearchForm: FormGroup;
   constructor() { }
...

每次希望在窗体上执行操作时,都将通过 weatherSearchForm 变量引用它。 现在将 FormBuilder 导入到构造函数中,以便可以在组件中使用它。

weather.component.ts
...
public weatherSearchForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
...

通过将 formBuilder 添加到构造函数中,它创建了 formBuilder 类的一个实例,允许您在组件中使用它。

现在可以在 weather. com ponent.ts 文件中创建 FormGroup 及其各自的值了。 如果表单中有多个输入选项,最好将其包含在 FormGroup 中。 在本教程中,您将只有一个(您的位置输入) ,但是无论如何您将使用 FormGroup 进行练习。

在导航到组件时,窗体已经准备好可以使用,这一点很重要。 因为使用的是反应式表单,所以必须首先在表单中创建元素树,然后再将其绑定到 HTML。 要实现这一点,您需要确保在 WeatherComponent 内部的 ngOnInit 挂钩中创建表单元素。 Ngoninit 方法在组件的初始化过程中运行一次,在组件准备使用之前执行您指定的任何逻辑。

因此,您必须先创建表单,然后才能完成到 HTML 进程的绑定。

在 WeatherComponent 中,您将在 ngOnInit 钩子中初始化窗体:

src/app/weather/weather.component.ts
...
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
    this.weatherSearchForm = this.formBuilder.group({
      location: ['']
    });
  }

您已经根据反应式表单样式创建了表单的第一部分: 在 weather. com ponent.ts 文件中定义表单组件。 您已经创建了一组窗体的复合元素(目前只有一个元素,位置)。 数组允许您为表单输入指定一些额外的选项,例如: 用一些数据预填充它,并使用验证器验证输入。 在本教程中,您不需要任何这些内容,因此您可以将其保留为空白。 您可以在这里找到更多关于可以传递到元素属性的信息。

在表单完成之前,您还有两件事要做。 首先打开你的 weather.com / ponent. html 文件。 您需要为窗体分配一个属性[ formGroup ]。 此属性将等于您刚刚在 weather. com ponent.ts 文件中声明的变量: weatherSearchForm。 其次,必须将 location 元素(在 weather. com ponent.ts 文件中声明)绑定到 HTML。 在 weather.com / ponent. html 中,添加以下突出显示的内容:

src/app/weather/weather.component.html
...
<form
  [formGroup]="weatherSearchForm" >
  <div class="form-group">
    <input
      class="form-control"
      type="text"
      id="weatherLocation"
      aria-describedby="weatherLocation"
      placeholder="Please input a Location"
    />formControlName="location" />
  </div>
  <div class="text-center">
    <button type="submit" class="btn btn-success btn-md">
      Search for the weather
    </button>
  </div>
</form>
...

您已经添加了[ formGroup ]属性,将表单绑定到 HTML。 您还添加了 formControlName 属性,该属性声明这个特定的输入元素绑定到 weather. com ponent.ts 文件中的 location 元素。

保存你的文件并返回到你的浏览器,你会看到你的应用看起来完全一样。 这意味着您的窗体已经正确连接。 如果您在这个阶段看到任何错误,那么请返回前面的步骤,以确保文件中的所有内容都是正确的。

接下来,您将连接您的按钮,以便能够接受输入数据到表单中。

第七步ー连接你的按钮

在这一步中,您将连接您的搜索按钮到您的表单,以便能够接受用户的输入数据。 您还将为最终将用户输入数据发送到 APIXU 天气 API 的方法创建脚手架。

如果你在 weather.com / ponent. html 中查看你的代码,你可以看到你的按钮有一个类型 submit:

src/app/weather/weather.component.html
<form>
...
<div class="text-center">
    <button type="submit" class="btn btn-success btn-md">Search for the weather</button>
</div>
</form>

这是一个标准的 HTML 值,它将表单值提交给某个函数以便采取操作。

在 Angular 中,在(ngSubmit)事件中指定该函数。 当您单击表单中的按钮时,只要它具有某种类型的 submit,它就会触发(ngSubmit)事件,该事件随后将调用您分配给它的任何方法。 在这种情况下,您希望能够获得用户输入的位置并将其发送到 apixuapi。

首先要创建一个方法来处理这个问题。 在 weather.com ponent.ts 中,创建一个 sendToAPIXU ()方法,该方法只有一个参数: 输入到表单中的值。 在文件中添加以下高亮显示的内容:

src/app/weather/weather.component.ts
...
ngOnInit() {
    this.weatherSearchForm = this.formBuilder.group({
      location: [""]
    });
  }

sendToAPIXU(formValues) {

}
...

接下来,将 ngSubmit 事件添加到 HTML 中,并将提交表单的值传递到 sendToAPIXU ()方法中:

weather.component.html
...
<form [formGroup]="weatherSearchForm" (ngSubmit)="sendToAPIXU(weatherSearchForm.value)">
  ...
</form>
...

您已经在表单中添加了 ngSubmit 事件,连接了提交表单时要运行的方法,并将 weatherSearchForm 的值作为参数传递给处理程序方法(weatherSearchForm.value)。 现在你可以使用 console.log 打印你的 formValues,在你的 sendToAPIXU ()方法中,添加以下高亮显示的内容到 weather. com ponent.ts:

weather.component.ts
...
sendToAPIXU(formValues){
    console.log(formValues);
}

进入浏览器,右键点击网页上的任何地方,打开控制台,然后点击 Inspect Element。 窗口上会弹出一个名为 Console 的选项卡。 在表格中输入 London。 当你点击搜索天气按钮时,你会看到一个封闭了你的位置的物体。

控制台的输出是一个 JSON 对象{ location: “ London”}。 如果您想访问您的位置值,可以通过访问 formValues.location 来实现。 类似地,如果在表单中有任何其他输入,您将交换。 所有其他元素名的位置。

注意: 反应窗体的所有值都存储在一个对象中,其中键是传递给 formBuilder.group ({})的值的名称。

该按钮现在连接起来,可以正确地接收输入。 接下来,您将使 sendToAPIXU ()方法向 APIXU API 发出 HTTP 请求。

第八步ー调用 API

Api 接受位置信息,搜索当前天气详细信息,并将其返回给客户机。 现在,您可以修改应用程序,以便它向 API 发送位置数据,获取响应,然后在页面上显示结果。

为了在 Angular 中发出 HTTP 请求,您必须导入 HttpClientModule。 打开你的 src / app / app。 然后添加以下高亮显示的行:

src/app/app.module.ts
...
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
    ...
    imports: [
        BrowserModule,
        RouterModule.forRoot(allAppRoutes),
        ReactiveFormsModule,
        HttpClientModule
    ]
    ...
})
...

接下来,您需要编写代码来对 apixuapi 进行 HTTP 调用。 最好的做法是创建一个 Angular 服务来发出 HTTP 请求。 关注点分离是你开发的任何应用程序的关键。 一个服务允许你将所有的 HTTP 请求转移到一个文件中,然后你可以在任何文件中调用它。 创建的 component.ts 文件。 您可以“合法地”在特定的。 Ts 文件,但这不是最佳实践。 例如,您可能会发现有些请求非常复杂,需要在接收到数据后执行一些后处理操作。 应用程序中的几个不同组件可能会使用您的一些 HTTP 请求,您不希望多次编写相同的方法。

从一个新的终端窗口或通过停止当前终端会话中的服务器,执行以下命令来创建一个名为 apixu 的服务:

  • ng g service apixu

你会看到类似如下的输出:

Output
create src/app/apixu.service.spec.ts (328 bytes) create src/app/apixu.service.ts (134 bytes) ...

该命令创建了服务文件(apixu.service.ts)和测试文件(apixu.service.spec.ts)。

现在需要将此服务作为提供者添加到 app.module.ts 文件中。 这使得它可以在你的应用程序中使用。 打开这个文件,首先导入 ApixuService:

src/app/app.module.ts
...
import { HttpClientModule } "@angular/common/http";
import { ApixuService } from "./apixu.service";
...

接下来将新导入的 ApixuService 作为提供者添加到提供者块中:

src/app/app.module.ts file
...
@NgModule({
    ...
    providers: [ApixuService],
    ...
})
...

在 Angular 中,如果您想使用已经创建的服务,则需要在 module.ts 文件中将该服务指定为提供者。 在本例中,您已经在 app.module.ts 中将其指定为整个应用程序中的提供程序。

最后,打开 src / app / apixu。 Service.ts 档案。 您将看到创建服务所需的样板代码: 首先从 Angular 导入注入接口; 然后是服务应该使用 providedIn 根注入器(针对整个应用程序) ; 然后是将服务的装饰(这实际上意味着指定)为@Injectable。

src/app/apixu.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ApixuService {

  constructor() { }
}

将服务装饰为@injectable 允许您在 weather. com ponent.ts 中的构造函数中注入此服务,以便您可以在组件中使用它。

如果你停止了应用程序,通过运行以下命令重新启动它:

  • ng serve --o

如前所述,您的服务需要向 apixuapi 发出 HTTP 请求,并导入 app.module.ts 文件中的 HttpClientModule,以便在整个应用程序中发出 HTTP 请求。 您还需要将 HttpClient 库导入到 APIXU.service.ts 文件中,以便从 APIXU.service.ts 文件本身向 apixuapi 发出 HTTP 请求。 打开 apixu.service.ts 文件,添加以下突出显示的内容:

src/app/apixu.service.ts
...
import { HttpClient } from '@angular/common/http';
...

现在需要编写一个方法 getWeather () ,它接受一个参数: location。 此方法将向 APIXU 发出一个 API 请求,并返回检索到的位置数据。

为此,您需要在注册 apixuapi 时使用提供的 API 键。 如果您登录到 APIXU,您将看到 dashboard:

您将看到您的键,并在下面,链接到 API 的网址与您的键已经预先填写的当前天气和天气预报。 复制当前天气细节的 HTTPS 链接,它会是这样的:

Https://api.apixu.com/v1/current.json?key= 你的 api 键 & q

这个网址将提供巴黎当前天气的详细信息。 您希望能够将位置从窗体传递到 & q 参数。 因此,在将 Paris 添加到 apixu.service.ts 文件时,将其从 URL 中删除:

src/app/apixu.service.ts
...
export class ApixuService {

  constructor(private http: HttpClient) {}

  getWeather(location){
      return this.http.get(
          'https://api.apixu.com/v1/current.json?key=YOUR_API_KEY&q=' + location
      );
  }
}

注意: 您已经在代码中直接使用了 API 键。 在生产环境中,应该安全地存储这个服务器端,以安全的方式检索这个密钥,并在应用程序中使用它。 您可以在服务器端安全地存储它,或者使用密钥管理应用程序,比如 Hashicorp Vault 或 Azure Key Vault 等等。

现在已经将 HttpClient 导入并注入到构造函数中,以便可以使用它。 您还创建了一个 getWeather ()方法,该方法需要一个位置参数并向您提供的 URL 发出 GET 请求。 你把 & q 参数留为空白,因为你要在方法中直接从位置参数提供这个位置。 最后,将数据返回给调用方法的人。

你的服务现在结束了。 您需要将服务导入到 WeatherComponent 中,将其注入到构造函数中以使用它,然后更新 sendToAPIXU ()方法以将您的位置发送到新创建的服务。 打开 weather. com ponent.ts 文件,添加突出显示的内容来完成这些任务:

src/app/weather.component.ts
...
import { FormBuilder, FormGroup } from "@angular/forms";
import { ApixuService } from "../apixu.service";
...
constructor(
    private formBuilder: FormBuilder,
    private apixuService: ApixuService
  ) {}
...
ngOnInit(){...}
sendToAPIXU(formValues){
    this.apixuService
      .getWeather(formValues.location)
      .subscribe(data => console.log(data));
}

您已经删除了 sendToAPIXU ()方法中以前的 console.log 语句,并使用以下内容对其进行了更新。 现在将位置从表单传递给前面创建的 sendToAPIXU ()方法。 然后将该数据传递给 ApixuService 的 getWeather ()方法,该方法随后向具有该位置的 API 发出 HTTP 请求。 然后,您已经订阅了回复的响应,并且在本例中,将该数据记录到控制台。 你总是不得不在 HTTP 请求上调用 subscribe 方法,因为请求不会开始,直到你有办法读取回来的观察到的响应。 Observable 是一种在发布者和订阅者之间发送消息的方式,允许您来回传递任何类型的数据。 在订阅者订阅之前,你不能从观察对象接收数据,因为在那之前它不会执行。

再次打开浏览器中的控制台。 现在,输入英国伦敦,然后点击搜索天气。 如果您单击标签箭头,您将在控制台中看到天气详细信息列表。

输出显示了包含所有需要的天气信息的 JSON 对象。 返回两个对象: 当前对象和位置对象。 前者提供所需的天气信息,后者提供你所在位置的详细信息。

现在您已经在控制台中成功地显示了天气数据。 为了完成本教程,您将在 HTML 中显示这些天气细节。

第九步ー在应用程式中显示天气资料

在控制台中显示结果是一个很好的初始步骤,可以检查一切是否正常工作。 但是,您希望最终以 HTML 的形式为用户显示天气数据。 要做到这一点,您需要创建一个变量来保存返回的天气数据,然后在 HTML 中使用插值来显示这些数据。

插值允许您在视图中显示数据。 为此,需要通过{{}样式绑定属性,以在 HTML 中显示该属性。

打开 weather. com ponent.ts 文件,创建一个名为 weatherData 的变量,将从 API 中检索到的 JSON 数据分配给该变量。 此外,删除以前在。 Subscribe ()括号,并用以下突出显示的代码替换它:

src/app/weather/weather.component.ts
...
export class WeatherComponent implements OnInit {
public weatherSearchForm: FormGroup;
public weatherData: any;
...
sendToAPIXU(formValues){
    this.apixuService
    .getWeather(formValues.location)
    .subscribe(data => this.weatherData = data)
      console.log(this.weatherData);
    }
}

您已经创建了变量 weatherData,并声明它可以保存任何类型的数据。 然后将从 API 调用中接收到的数据分配给该变量。 最后,添加了 console.log ()语句,以便再次检查 weatherData 是否保存了所有检索到的信息。

你的 weather. com ponent.ts 文件在这个阶段应该是这样的:

src/app/weather/weather.component.ts
import { Component, OnInit } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";
import { ApixuService } from "../apixu.service";

@Component({
  selector: "app-weather",
  templateUrl: "./weather.component.html",
  styleUrls: ["./weather.component.css"]
})
export class WeatherComponent implements OnInit {
  public weatherSearchForm: FormGroup;
  public weatherData: any;

  constructor(
    private formBuilder: FormBuilder,
    private apixuService: ApixuService
  ) {}

  ngOnInit() {
    this.weatherSearchForm = this.formBuilder.group({
      location: [""]
    });
  }

  sendToAPIXU(formValues) {
    this.apixuService.getWeather(formValues.location).subscribe(data => {
      this.weatherData = data;
      console.log(this.weatherData);
    });
  }
}

如果您返回并再次搜索 London,UK,您将看到您的对象正常地输出到控制台。 现在,您希望在 HTML 中显示这些数据。 如果你从控制台中检索天气数据来检查当前对象,你会看到诸如条件、感觉像 c、感觉像 f、临时温度 c、临时温度 f 等等的值。

再次打开 weather. com / ponent. html 文件,将字幕添加到要显示的数据中。 您将在第二个 col-md-6中添加这些 p 标记:

src/app/weather/weather.component.html
...
<div class="col-md-6">
  <h3 class="text-center my-4">Weather Details:</h3>
  <p class="text-center">Current weather conditions:</p>
  <p class="text-center">Temperature in Degrees Celsius:</p>
  <p class="text-center">Temperature in Degrees Farenheit:</p>
  <p class="text-center">Feels like in Degrees Celsius:</p>
  <p class="text-center">Feels like in Degrees Farenheit:</p>
  <p class="text-center">Location Searched:</p>
</div>

接下来,将从 JSON 对象接收到的数据添加到 HTML 中:

weather.component.html
...
<h3 class="text-center my-4 ">Weather Details:</h3>
<p class="text-center">
  Current weather conditions: {{this.weatherData?.current.condition.text}}
</p>
<p class="text-center">
  Temperature in Degrees Celsius: {{this.weatherData?.current.temp_c}}
</p>
<p class="text-center">
  Temperature in Degrees Farenheit: {{this.weatherData?.current.temp_f}}
</p>
<p class="text-center">
  Feels like in Degrees Celsius: {{this.weatherData?.current.feelslike_c}}
</p>
<p class="text-center">
  Feels like in Degrees Farenheit:
  {{this.weatherData?.current.feelslike_f}}
</p>
<p class="text-center">
  Location Searched: {{this.weatherData?.location.name}},
  {{this.weatherData?.location.country}}
</p>

你用过接线员吗? 当您从 HTML 中的 weatherData 变量中检索数据时。 这个操作员被称为猫王操作员。

因为您正在进行一个 HTTP 调用,所以您正在进行一个异步请求。 您将在某个时候获得该数据,但它不会立即作出响应。 然而,Angular 仍将继续使用您从 weatherData 变量指定的数据填充 HTML。 如果在 Angular 开始填充你的段落时,你还没有收到数据,那么将会有一个错误声明 Angular 找不到这些数据。 例如:。 电流或。 位置显示为未定义。

Elvis 操作器是一个安全的导航器,可以防止这种情况发生。 它告诉 Angular 等待并检查是否首先定义了 weatherData,然后在 HTML 中显示该数据。 一旦天气数据得到了所有的信息,Angular 将更新绑定并显示正常的数据。

你最终的 weather.com ponent.ts 文件看起来如下所示:

weather.component.html
<div class="container">
  <div class="row">
    <div class="col-md-6">
      <h3 class="text-center my-4">Search for Weather:</h3>
      <form
        [formGroup]="weatherSearchForm"
        (ngSubmit)="sendToAPIXU(weatherSearchForm.value)"
      >
        <div class="form-group">
          <input
            class="form-control"
            type="text"
            id="weatherLocation"
            aria-describedby="weatherLocation"
            placeholder="Please input a Location"
            formControlName="location"
          />
        </div>
        <div class="text-center">
          <button type="submit" class="btn btn-success btn-md">
            Search for the weather
          </button>
        </div>
      </form>
    </div>
    <div class="col-md-6">
      <h3 class="text-center my-4">Weather Details:</h3>
      <p class="text-center">
        Current weather conditions: {{ this.weatherData?.current.condition.text
        }}.
      </p>
      <p class="text-center">
        Temperature in Degrees Celsius: {{ this.weatherData?.current.temp_c }}
      </p>
      <p class="text-center">
        Temperature in Degrees Farenheit: {{ this.weatherData?.current.temp_f }}
      </p>
      <p class="text-center">
        Feels like in Degrees Celsius: {{ this.weatherData?.current.feelslike_c
        }}
      </p>
      <p class="text-center">
        Feels like in Degrees Farenheit: {{
        this.weatherData?.current.feelslike_f }}
      </p>
      <p class="text-center">
        Location Searched: {{ this.weatherData?.location.name }}, {{
        this.weatherData?.location.country }}.
      </p>
    </div>
  </div>
</div>

为了输出所需的数据,您已经遵循返回的 JSON 天气对象的模式。 保存您的文件,返回到您的浏览器,然后输入 London,UK,您将看到您的天气数据出现在右侧。

尝试不同的地方,如: 旧金山,美国,达喀尔,塞内加尔,Honololu,夏威夷。 您将看到所有这些地点的相应天气数据。

总结

您已经使用 Angular、 Bootstrap 和 apixuapi 创建了一个天气应用程序。 你已经建立了一个角项目从头开始,遵循角的最佳实践,同时确保您的应用程序是良好的设计和设置适当。

Angular 是一个先进的框架,允许您轻松创建从小型网络应用程序到大型复杂应用程序的任何东西。 和任何框架一样,Angular 确实有一个学习曲线,但是像这样的小项目可以帮助你快速学习并开始有效地使用它。

另一个需要考虑添加到应用程序的特性是处理来自 HTTP 请求的错误; 例如,如果键入了无效的位置。 另一个增强将显示不同的图像,如果温度之间的某些阈值。 您还可以使用其他 api 创建不同的应用程序。

你可能还想使用 NgBootstrap,它是为 Angular 构建的一种特殊类型的 Bootstrap。 这允许您使用所有标准 Bootstrap JavaScript 窗口小部件以及一些特殊的窗口小部件,这些小部件并不包含在专门为 Angular 设计的标准安装中。

本教程的完整代码可以在 GitHub 上找到。