Angular、Bootstrap、およびAPIXUAPIを使用して天気アプリを構築する方法

提供:Dev Guides
移動先:案内検索

著者は、 Write forDOnationsプログラムの一環として寄付を受け取るためにNPowerを選択しました。

序章

Angular は、Googleによって構築されたフロントエンドWebフレームワークです。 これにより、開発者は、 model-view-controller (MVC)または model-view-viewmodel (MVVM)ソフトウェアアーキテクチャパターンをモデルにしたシングルページアプリケーションを構築できます。 このアーキテクチャは、アプリケーションを異なるが接続された部分に分割し、並列開発を可能にします。 このパターンに従って、AngularはさまざまなコンポーネントをWebアプリケーションのそれぞれの部分に分割します。 そのコンポーネントは、そのコンポーネントに関連するデータとロジックを管理し、それぞれのビューにデータを表示し、アプリの他の部分から受信するさまざまなメッセージに基づいてビューを適応または制御します。

Bootstrap は、開発者がレスポンシブWebサイト(さまざまなデバイスに適応するサイト)を迅速かつ効果的に構築するのに役立つフロントエンドライブラリです。 各ページを12列に分割するグリッドシステムを利用して、表示されているデバイスに関係なく、ページが正しいサイズとスケールを維持するようにします。

APIXU は、APIを介して全球気象データをユーザーに提供します。 APIXUを使用すると、ユーザーは世界の任意の場所の最新の天気と将来の天気予報を取得できます。

このチュートリアルでは、Angular、Bootstrap、およびAPIXUAPIを使用して天気アプリを作成します。 検索フォームに場所を入力し、そのフォームを送信すると、アプリに表示されているその場所の現在の天気の詳細を確認できます。 このチュートリアルで使用されるAngularバージョンは7.2.0であり、使用されるBootstrapバージョンは4.2.1です。

前提条件

このチュートリアルを開始する前に、次のものが必要です。

ステップ1—Angularのインストール

アプリの作成を開始する前に、Angularをインストールする必要があります。 ターミナルを開き、次のコマンドを実行して、AngularCLIをマシンにグローバルにインストールします。

npm install -g @angular/cli

Angular CLI は、Angularのコマンドラインインターフェイスです。 これは、新しいAngularプロジェクトと、Angularプロジェクトを構成するさまざまなサブ要素を作成するための主要な方法として機能します。 -g引数を使用すると、グローバルにインストールされます。

しばらくすると、次の出力が表示されます。

Angularのインストールからの出力

...
+ @angular/[email protected]
...

これで、ローカルマシンにAngularがインストールされました。 次に、Angularアプリケーションを作成します。

ステップ2—Angularアプリを作成する

このステップでは、新しいAngularアプリケーションを作成して構成し、BootstrapやjQueryなどのすべての依存関係をインストールしてから、最後にデフォルトのアプリケーションが期待どおりに機能していることを確認します。

まず、ngコマンドを使用してAngularアプリケーションを作成します。これは、端末から実行できます。

注: Windowsを使用している場合、Node.jsとnpmを正しくインストールしていても、コマンドプロンプトからngコマンドを実行しようとすると問題が発生する可能性があります。 たとえば、ng is not recognized as an internal or external commandなどのエラーが発生する場合があります。 これを解決するには、WindowsのNode.jsフォルダーにあるインストール済みのNode.jsコマンドプロンプト内でngコマンドを実行してください。


ngコマンドは、コマンドラインからAngularでアクションを実行するための前提条件です。 たとえば、新しいプロジェクトを構築する場合でも、コンポーネントを作成する場合でも、テストを作成する場合でも、必要な各機能の前にngコマンドを付けます。 このチュートリアルでは、新しいアプリケーションを作成する必要があります。 これは、ng newコマンドを実行することで実現できます。 ng newコマンドは、新しいAngularアプリケーションを作成し、必要なライブラリをインポートして、アプリケーションに必要なすべてのデフォルトのコードスキャフォールディングを作成します。

新しいアプリケーションを作成することから始めます。このチュートリアルでは、weather-appという名前になりますが、必要に応じて名前を変更できます。

ng new weather-app

ng newコマンドは、新しいアプリケーションに追加する機能に関する追加情報の入力を求めます。

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

Angular routingを使用すると、ルートとコンポーネントを使用して、さまざまなビューでシングルページアプリケーションを構築できます。 先に進み、yと入力するか、ENTERを押してデフォルトを受け入れます。

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

ENTERを押して、デフォルトの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フォルダを開きます。

ディレクトリの構造を見ると、いくつかの異なるフォルダとファイルがあります。 これらすべてのファイルがここで何をするかについての完全な説明を読むことができますが、このチュートリアルの目的のために、これらは理解するための最も重要なファイルです:

  • package.jsonファイル。 ルートweather-appフォルダーにあり、他のNode.jsアプリケーションと同じように機能し、アプリケーションが使用するすべてのライブラリ、アプリケーションの名前、テスト時に実行するコマンドなどを保持します。 主に、このファイルには、Angularアプリケーションを正しく実行するために必要な外部ライブラリに関する詳細が含まれています。
  • app.module.tsファイル。 このファイルは、weather-app/srcフォルダー内のappフォルダーにあり、アプリケーションのアセンブル方法をAngularに指示し、アプリケーションのコンポーネント、モジュール、プロバイダーに関する詳細を保持します。 importsアレイ内には、インポートされたモジュールBrowserModuleがすでにあります。 BrowserModuleは、アプリケーションに不可欠なサービスとディレクティブを提供し、常にimports配列の最初にインポートされるモジュールである必要があります。
  • angular.jsonファイル。 アプリのルートweather-appフォルダーにあり、これはAngularCLIの構成ファイルです。 このファイルには、Angularアプリケーションの実行に必要なものの内部構成設定が含まれています。 アプリケーション全体のデフォルトを設定し、テスト時に使用する構成ファイル、アプリで使用するグローバルスタイル、ビルドファイルを出力するフォルダーなどのオプションがあります。 これらのオプションの詳細については、公式のAngular-CLIドキュメントを参照してください。

次にBootstrapをインストールするので、今のところこれらのファイルはすべてそのままにしておくことができます。

ブートストラップには、Angularで正しく機能するためにインストールする必要のある2つの依存関係があります— jQuerypopper.jsjQueryはクライアント側のスクリプトに焦点を当てたJavaScriptライブラリであり、popper.jsは主にツールチップとポップオーバーを管理するポジショニングライブラリです。

ターミナルで、ルートweather-appディレクトリに移動します。

cd weather-app

次に、次のコマンドを実行してすべての依存関係をインストールし、package.jsonファイルへの参照を保存します。

npm install --save jquery popper.js bootstrap

--saveオプションは、参照をpackage.jsonファイルに自動的にインポートするため、インストール後に手動で追加する必要はありません。

次のように、インストールされたバージョン番号を示す出力が表示されます。

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

これで、Bootstrapとその依存関係が正常にインストールされました。 ただし、これらのライブラリをアプリケーション内に含める必要もあります。 weather-appは、これらのライブラリが必要であることをまだ認識していません。したがって、jquerypopper.jsbootstrap.js、および[ X142X]をangular.jsonファイルに追加します。

popper.jsの場合、含める必要のあるファイルはnode_modules/popper.js/dist/umd/popper.jsです。 jQueryにはnode_modules/jquery/dist/jquery.slim.jsファイルが必要です。 最後に、Bootstrapには、2つのファイル(JavaScriptファイルとCSSファイルの両方)が必要です。 それぞれnode_modules/bootstrap/dist/js/bootstrap.jsnode_modules/bootstrap/dist/css/bootstrap.cssです。

必要なファイルパスがすべて揃ったので、テキストエディタでangular.jsonファイルを開きます。 styles配列は、CSSファイルへの参照を追加する場所であり、scripts配列は、すべてのスクリプトを参照します。 これらの配列は両方とも、angular.jsonファイルの上部の"options":JSONオブジェクト内にあります。 次の強調表示されたコンテンツをファイルに追加します。

angle.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"
]},
...

これで、Bootstrapが正しく機能するために必要なメインの.jsおよび.cssファイルがインポートされました。 angular.jsonファイルからこれらのファイルへの相対パスを指定しました。スタイル配列に.cssファイルを追加し、[のスクリプト配列に.jsファイルを追加します。 X173X]。 このコンテンツを追加した後、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アプリページが表示されます。

これらの出力が表示されない場合は、この手順をもう一度実行して、すべてが正しいことを確認してください。 Port 4200 is already in use. Use '--port' to specify a different portのようなエラーが表示された場合は、次のように入力してポート番号を変更できます。

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

この潜在的なエラーメッセージの理由は、マシンのポート4200が別のプログラムまたはプロセスによって使用されているためです。 そのプロセスが何であるかを知っている場合は、それを終了するか、上記の手順に従って別のポート番号を指定することができます。

これで、アプリケーションのスキャフォールディングが設定されました。 次に、検索場所のメインフォームと関連する天気の詳細を含む天気コンポーネントを作成します。

ステップ3—天気コンポーネントを作成する

Angularアプリケーションは、主にコンポーネントで構成されています。これらのコンポーネントは、アプリケーション内で特定の機能を持つロジックの一部です。 コンポーネントは、アプリケーションの画面の一部を管理するロジックで構成されています。これは、ビューと呼ばれます。

たとえば、このチュートリアルでは、次の2つのタスクの処理を担当するWeather Componentを作成します。

  • 場所を検索する
  • その場所に関連する気象データを表示する

最初の目的を達成するために、場所を検索できるフォームを作成します。 フォームの検索ボタンをクリックすると、その場所を検索する関数がトリガーされます。

2番目の目的を達成するために、取得したデータをきちんと表示するネストされた<p>タグを持つ<div>があります。

アプリがターミナルウィンドウから実行されている間は、その特定のウィンドウに他に何も入力することはできません。 したがって、他のngコマンドを実行する場合は、新しいターミナルウィンドウでweather-appディレクトリを開きます。 または、CTRL + Cを押して、元のターミナルウィンドウでのアプリの実行を停止することもできます。 その後、新しいコンポーネントをインストールし、その後、ng serve --oと入力してアプリを再起動します。

次のコマンドを実行すると、Weather Componentが作成され、app.module.tsファイルに自動的にインポートされます。 app.module.tsファイルには、アプリケーション内のすべてのコンポーネント、モジュール、およびプロバイダーに関する詳細が含まれていることに注意してください。

ng generate component weather

次のような出力が表示されます(正確なバイトサイズは異なる場合があります)。

OutputCREATE 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がコンポーネントに必要な4つのファイルを作成したことを示しています。

  • ビューの.cssおよび.htmlファイル
  • コンポーネントをテストするための.spec.tsファイル
  • コンポーネントの機能を保持する.component.tsファイル

Angularは、src/app/app.module.tsファイルも更新して、新しく作成されたコンポーネントへの参照を追加しました。 コンポーネントファイルは常にsrc/app/name-of-componentディレクトリにあります。

新しいコンポーネントをインストールしたので、ブラウザに戻ってアプリを表示します。 新しいコンポーネントをインストールするためにアプリの実行を停止した場合は、次のように入力してアプリを再起動します。

ng serve --o

「Welcometoapp!」が引き続き表示されていることに気付くでしょう。 (デフォルトのコンポーネント)ページに表示されます。 新しく作成したコンポーネントは表示されません。 次のセクションでは、これを変更して、localhost:4200に移動するたびに、Angularのデフォルトコンポーネントではなく、新しく作成した天気コンポーネントにアクセスできるようにします。

ステップ4—天気コンポーネントへのアクセス

標準のHTMLでは、新しいページを作成するときはいつでも、新しい.htmlファイルを作成します。 たとえば、新しく作成したページに移動する既存のHTMLページがすでにある場合は、それを指すanchorタグを持つhref属性があります。新しいページ。 例えば:

preexisting.html

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

ただし、Angularでは、これは少し異なる動作をします。 この方法でhref属性を使用して、新しいコンポーネントに移動することはできません。 コンポーネントにリンクする場合は、AngularのRouterライブラリを利用して、コンポーネントに直接マップされるファイル内で目的のURLパスを宣言する必要があります。

Angularでは、このファイルをroutes.tsと呼びます。 これはあなたのルート(リンク)のすべての詳細を保持します。 このファイルを正しく機能させるには、@angular/routerライブラリからRoutesタイプをインポートし、Routesタイプの目的のリンクをリストします。 これは、これらがアプリ内のナビゲーション用のルートのリストであることをAngularに通知します。

テキストエディタでファイルroutes.tsを作成し、src/appディレクトリに保存します。 次に、routes.tsファイルに次のコンテンツを追加します。

src / app / routers.ts

import { Routes } from '@angular/router'

次に、src/app/routes.tsでURLパスとコンポーネントを宣言します。 ホームページ(http://localhost:4200)にアクセスしたときに、新しく作成した天気コンポーネントにアクセスできるようにアプリを作成します。 次の行をファイルに追加します。これにより、ルートURLが作成したばかりの天気コンポーネントにマップされます。

src / app / routers.ts

import { Routes } from '@angular/router'
import { WeatherComponent } from './weather/weather.component';

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

WeatherComponentをインポートし、Routes型の配列である変数allAppRoutesを作成しました。 allAppRoutes配列は、それぞれがURLパスとマップ先のコンポーネントを含むルート定義オブジェクトを保持します。 ルートURL()に移動するたびに、WeatherComponentに移動するように指定しました。

最終的なroutes.tsファイルは次のようになります。

src / app / routers.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は、ルーター(すべてのアプリナビゲーションの実行を担当)を初期化および構成し、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に渡して、ルーターがURLのルーティング先を認識できるようにします。

最後に、ルーティング自体を有効にする必要があります。 app.component.tsファイルを開きます。 その特定のコンポーネントのHTMLを指定するtemplateUrlプロパティがあります:./app.component.html。 このファイルsrc/app/app.component.htmlを開くと、localhost:4200ページのすべてのHTMLが含まれていることがわかります。

app.component.htmlに含まれるすべてのHTMLを削除し、次のように置き換えます。

src / app / app.component.html

<router-outlet></router-outlet>

router-outletタグはルーティングをアクティブにし、ユーザーがブラウザーに入力したURLを、[X136X]変数の下のroutes.tsファイルで以前に作成したルート定義と照合します。 次に、ルータはビューをHTMLで表示します。 このチュートリアルでは、<router-outlet></router-outlet>タグの直後にweather.component.htmlコードを表示します。

ここで、http://localhost:4200に移動すると、天気予報が機能します!がページに表示されます。

アプリケーションでルーティングを設定しました。 次に、フォームと詳細セクションを作成して、場所を検索し、それに関連する詳細を表示できるようにします。

ステップ5—ユーザーインターフェイスの定義

Bootstrapを使用して、アプリケーションビューのスキャフォールディングとして機能します。 Bootstrapは、あらゆるデバイス(モバイル、タブレット、またはデスクトップ)に適応する既製のレスポンシブWebサイトを作成するのに役立ちます。 これは、Webページのすべての行を12列幅として扱うことで実現されます。 Webページでは、行はページの一方の端からもう一方の端までの単純な行です。 これは、すべてのページのコンテンツがその行に含まれている必要があり、12列に等しい必要があることを意味します。 12列に等しくない場合は、別の行にプッシュダウンされます。 たとえば、Bootstrapのグリッドシステムでは、12列の行が6列の2つのセクションに分割され、次の12列の行が4列の3つのセクションに分割されます。

ブートストラップドキュメントで、このグリッドシステムの詳細を読むことができます。

ページを6列の2つのセクションに分割します。左側の列には検索フォームが表示され、右側の列には天気の詳細が表示されます。

src/app/weather/weather.component.htmlを開いて、WeatherComponentHTMLコードにアクセスします。 現在ファイルにある段落を削除してから、次のコードを追加します。

src / app/講演/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>

すべてのコンテンツを保持するために、クラスcontainer<div>を作成しました。 次に、それぞれ6列の2つのセクションに分割する行を作成しました。 左側には検索フォームが表示され、右側には気象データが表示されます。

次に、フォームを作成するために、最初のcol-md-6列で作業します。 また、フォームに入力した内容をAPIXUに送信するボタンを追加します。これにより、要求された天気の詳細が返されます。 これを行うには、最初のcol-md-6クラスを識別し、<h3>タグの下に次の強調表示されたコンテンツを追加します。

src / app/講演/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>
...

フォームを追加し、検索バーを保持するform-groupクラスを追加しました。 また、天気を検索するためのボタンを作成しました。 ブラウザでは、天気アプリのページは次のようになります。

これは少しコンパクトに見えるので、CSSを追加して、より良い間隔でページのスタイルを設定できます。 Bootstrapの主な利点は、独自のCSSを追加することなく、HTMLに追加できるスペーシングクラスが付属していることです。 ただし、Bootstrapの標準クラスでカバーされていない追加のCSSを組み込みたい場合は、必要に応じて独自のCSSを作成できます。 このチュートリアルでは、Bootstrapの標準クラスを使用します。

<h3>タグごとに、.my-4BoostrapCSSクラスを追加します。 mは要素にマージンを設定し、yは要素にmargin-topmargin-bottomの両方を設定し、最後に4は量を指定します追加するマージンの。 さまざまな間隔のタイプとサイズの詳細については、こちらをご覧ください。 weather.component.htmlファイルに、次の強調表示されたコンテンツを追加して、現在の<h3>タグを置き換えます。

src / app/講演/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から受け取った情報を表示するセクションを作成しました。 次に、フォームを配線して、場所を正しく入力できるようにします。

ステップ6—フォームの配線

Angularでは、アプリケーションでユーザー入力用のフォームを作成する方法が2つあります。reactiveまたはtemplate-drivenです。 それらは同じ結果を達成しますが、各フォームタイプは、ユーザー入力データの処理を異なる方法で処理します。

リアクティブフォームでは、.component.tsファイルにフォームのさまざまな要素のリストを作成します。 次に、それらをそれぞれの.component.htmlファイル内で作成したHTMLフォームに接続します。 これは厳密に一方向です。 つまり、データはHTMLから.component.tsファイルに流れ、データの双方向の流れはありません。

テンプレート駆動型フォームを使用すると、通常のHTMLの場合と同じようにフォームを作成できます。 次に、ngModelなどのディレクティブを使用して、HTMLから一方向または双方向のデータバインディングを作成し、コンポーネントのデータモデルに戻すことができます。その逆も可能です。

それぞれのアプローチには長所と短所がありますが、一般的に、次の理由から反応型が好ましいです。

  • さまざまな複雑さのフォームを作成する柔軟性。
  • コンポーネントの.component.tsファイル内の各フォームコントロールの状態をチェックすることにより、単体テストが簡単になります。
  • フォーム内の値をサブスクライブする機能。 開発者は、フォームの値ストリームをサブスクライブして、フォームに入力されている値に対してリアルタイムで何らかのアクションを実行できるようにすることができます。

これらの長所にもかかわらず、リアクティブフォームは実装がより複雑になる場合があります。 これにより、開発者はテンプレート駆動型のフォームよりも多くのコードを作成する可能性があります。 フォームタイプと最良のユースケースの両方の包括的な概要を確認するには、Angularの公式ガイドが出発点として適しています。 このチュートリアルでは、リアクティブフォームを使用します。

リアクティブフォームを使用するには、ファイルapp.module.tsを開きます。 次に、ファイルの先頭に向かってインポートを宣言して、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.component.tsファイルを開き、FormBuilderクラスとFormGroupクラスをインポートします。

src / app/講演/weather.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';

次に、FormGroupを参照する変数をweather.component.tsファイルに作成します。

Weather.component.ts

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

フォームでアクションを実行するたびに、weatherSearchForm変数を介してフォームを参照します。 次に、FormBuilderインポートをconstructorに追加して、コンポーネントで使用できるようにします。

Weather.component.ts

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

formBuilderconstructorに追加すると、FormBuilderクラスのインスタンスが作成され、コンポーネント内で使用できるようになります。

これで、FormGroupとそれぞれの値をweather.component.tsファイルに作成する準備が整いました。 フォームに複数の入力オプションがある場合は、FormGroupで囲むことをお勧めします。 このチュートリアルでは、1つ(位置入力)しかありませんが、練習にはFormGroupを使用します。

コンポーネントに移動するときに、フォームを使用できるようになっていることが重要です。 リアクティブフォームを使用しているため、フォームをHTMLにバインドする前に、まずフォーム内に要素のツリーを作成する必要があります。 これを実現するには、WeatherComponent内のngOnInitフックにフォーム要素を作成する必要があります。 ngOnInitメソッドは、コンポーネントの初期化時に1回実行され、コンポーネントを使用する準備が整う前に実行する必要があると指定したロジックを実行します。

したがって、HTMLプロセスへのバインドを完了する前に、フォームを作成する必要があります。

WeatherComponentで、ngOnInitフック内でフォームを初期化します。

src / app/講演/weather.component.ts

...
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
    this.weatherSearchForm = this.formBuilder.group({
      location: ['']
    });
  }

リアクティブフォームスタイルに従ってフォームの最初の部分を作成しました。weather.component.tsファイルでフォームコンポーネントを定義します。 フォームの複合要素のグループを作成しました(現時点では、locationという1つの要素があります)。 []配列を使用すると、フォーム入力にいくつかの追加オプションを指定できます。たとえば、データを事前に入力したり、バリデーターを使用して入力を検証したりできます。 このチュートリアルではこれらのいずれも必要ないため、空白のままにすることができます。 要素プロパティここに渡すことができるものについて詳しく知ることができます。

フォームが完成する前に、さらに2つのことを行う必要があります。 まず、weather.component.htmlファイルを開きます。 フォームにプロパティ[formGroup]を割り当てる必要があります。 このプロパティは、weather.component.tsファイルで宣言した変数weatherSearchFormと同じになります。 次に、location要素(weather.component.tsファイルで宣言されている)をHTMLにバインドする必要があります。 weather.component.htmlに、次の強調表示されたコンテンツを追加します。

src / app/講演/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にバインドしました。 また、この特定のinput要素がweather.component.tsファイルのlocation要素にバインドされることを宣言するformControlNameプロパティを追加しました。

ファイルを保存してブラウザに戻ると、アプリがまったく同じように見えることがわかります。 これは、フォームが正しく接続されていることを意味します。 この段階でエラーが発生した場合は、前の手順に戻って、ファイル内のすべてが正しいことを確認してください。

次に、ボタンを配線して、フォームへの入力データを受け入れることができるようにします。

ステップ7—ボタンを接続する

このステップでは、ユーザーの入力データを受け入れることができるように、検索ボタンをフォームに接続します。 また、最終的にユーザーの入力データをAPIXU天気APIに送信するメソッドのスキャフォールディングを作成します。

weather.component.htmlのコードを振り返ると、ボタンのタイプがsubmitであることがわかります。

src / app/講演/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.component.tsで、フォームに入力した値という1つの引数を取るメソッドsendToAPIXU()を作成します。 次の強調表示されたコンテンツをファイルに追加します。

src / app/講演/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.component.tsに追加することでこの動作をテストできます。

Weather.component.ts

...
sendToAPIXU(formValues){
    console.log(formValues);
}

ブラウザに移動し、Webサイトページの任意の場所を右クリックしてコンソールを開き、要素の検査をクリックします。 コンソールと呼ばれるポップアップするタブがウィンドウに表示されます。 フォームにLondonと入力します。 天気検索ボタンをクリックすると、現在地が囲まれたオブジェクトが表示されます。

コンソールからの出力はJSONオブジェクト{location: "London"}です。 ロケーション値にアクセスする場合は、formValues.locationにアクセスしてアクセスできます。 同様に、フォーム内に他の入力がある場合は、.locationを他の要素名と交換します。

注:リアクティブフォームのすべての値はオブジェクトに保存されます。ここで、キーはformBuilder.group({})に渡した値の名前です。


これでボタンが配線され、正しく入力を受け取ることができます。 次に、sendToAPIXU()メソッドでAPIXUAPIへのHTTPリクエストを作成します。

ステップ8—APIXUAPIを呼び出す

APIXU APIは位置情報を受け取り、現在の天気の詳細でその位置を検索して、クライアントに返します。 次に、アプリがAPIに位置データを送信し、応答を取得して、結果をページに表示するようにアプリを変更します。

AngularでHTTPリクエストを行うには、HttpClientModuleをインポートする必要があります。 src/app/app.module.tsを開き、次の強調表示された行を追加します。

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呼び出しを行うためのコードを記述する必要があります。 HTTPリクエストを行うためにAngularサービスを作成することをお勧めします。 関心の分離は、作成するすべてのアプリで重要です。 サービスを使用すると、アプリが作成するすべてのHTTPリクエストを1つのファイルに移動して、作成した.component.tsファイル内で呼び出すことができます。 これらのHTTPリクエストを特定の.component.tsファイルに「合法的に」書き込むことはできますが、これはベストプラクティスではありません。 たとえば、リクエストの一部が複雑で、データの受信後に後処理アクションを実行する必要がある場合があります。 アプリ内のいくつかの異なるコンポーネントがHTTPリクエストの一部を使用する可能性があり、同じメソッドを複数回記述したくない場合があります。

新しいターミナルウィンドウから、または現在のターミナルセッションでサーバーを停止して、次のコマンドを実行し、apixuというサービスを作成します。

ng g service apixu

次のような出力が表示されます。

Outputcreate 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をプロバイダーとしてprovidersブロックに追加します。

src / app/app.module.tsファイル

...
@NgModule({
    ...
    providers: [ApixuService],
    ...
})
...

Angularでは、作成したサービスを使用する場合は、module.tsファイル内でそのサービスをプロバイダーとして指定する必要があります。 この場合、app.module.tsでアプリケーション全体のプロバイダーとして指定しました。

最後に、src/app/apixu.service.tsファイルを開きます。 サービスを作成するために必要なもののボイラープレートコードが表示されます。最初に、AngularからのInjectableインターフェースのインポート。 次に、サービスがprovidedInルートインジェクターを使用する必要があるという事実(アプリケーション全体)。 次に、サービスの装飾(これは事実上指定を意味します)を@Injectableとして指定します。

src / app / apixu.service.ts

import { Injectable } from '@angular/core';

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

  constructor() { }
}

サービスを@Injectableとして装飾すると、このサービスをweather.component.tsのコンストラクター内に挿入して、コンポーネント内で使用できるようになります。

アプリケーションを停止した場合は、次のコマンドを実行してアプリケーションを再起動します。

ng serve --o

前述のように、サービスはAPIXU APIにHTTPリクエストを送信し、HttpClientModuleapp.module.tsファイルにインポートしてアプリケーション全体でHTTPリクエストを作成する必要があります。 さらに、HttpClientライブラリをapixu.service.tsファイルにインポートして、apixu.service.tsファイル自体からAPIXUAPIにHTTPリクエストを送信する必要があります。 apixu.service.tsファイルを開き、次の強調表示されたコンテンツを追加します。

src / app / apixu.service.ts

...
import { HttpClient } from '@angular/common/http';
...

次に、場所という1つのパラメータを使用するメソッドgetWeather()を作成する必要があります。 このメソッドは、APIXUにAPIリクエストを行い、取得した位置データを返します。

このため、APIXU APIにサインアップするときに、提供されたAPIキーが必要になります。 APIXU にログインすると、ダッシュボードが表示されます。

キーが表示され、その下に、現在の天気天気予報の両方にキーが事前に入力されたAPIURLへのリンクが表示されます。 現在の天気の詳細のHTTPSリンクをコピーすると、次のようになります。

https://api.apixu.com/v1/current.json?key=YOUR_API_KEY&q=Paris

このURLは、パリの現在の天気の詳細を提供します。 代わりに、フォームから&q=パラメーターにlocationを渡せるようにする必要があります。 したがって、apixu.service.tsファイルに追加するときに、URLからParisを削除します。

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キーを使用しました。 本番環境では、これをサーバー側に安全に保存し、このキーを安全な方法で取得して、アプリケーション内で使用する必要があります。 サーバー側に安全に保存するか、 HashicorpVaultAzureKeyVaultなどのキー管理アプリケーションを使用できます。


これで、HttpClientがコンストラクターにインポートされて挿入され、使用できるようになりました。 また、locationパラメーターを受け取り、指定されたURLに対してGET要求を行うメソッドgetWeather()を作成しました。 メソッドのlocationパラメーターから直接この場所を指定するため、&q=パラメーターは空白のままにしました。 最後に、メソッドを呼び出した人にデータを返しました。

これでサービスは完了です。 サービスをWeatherComponentにインポートし、コンストラクターに挿入して使用してから、sendToAPIXU()メソッドを更新して、新しく作成したサービスに現在地を送信する必要があります。 weather.component.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()メソッドに現在地を渡すことになります。 次に、そのデータをApixuServicegetWeather()メソッドに渡し、その後、その場所でAPIにHTTPリクエストを送信しました。 次に、返された応答をサブスクライブし、この例では、そのデータをコンソールに記録しました。 返されるObservable応答を読み取る方法が得られるまで要求は開始されないため、HTTP要求では常にsubscribeメソッドを呼び出す必要があります。 Observables は、パブリッシャーとサブスクライバーの間でメッセージを送信する方法であり、あらゆる種類のデータをやり取りできます。 オブザーバブルはサブスクライバーがサブスクライブするまで、その時点より前に実行されないため、オブザーバブルからデータを受信することはできません。

ブラウザでコンソールをもう一度開きます。 次に、 London、UK と入力し、 Search forWeatherをクリックします。 タブの矢印をクリックすると、コンソールに天気の詳細のリストが表示されます。

出力には、必要なすべての気象情報を含むJSONオブジェクトが表示されます。 currentオブジェクトとlocationオブジェクトの2つのオブジェクトが返されます。 前者は希望する天気の詳細を示し、後者はあなたの場所に関する詳細を示します。

これで、気象データがコンソールに正常に表示されました。 このチュートリアルを終了するには、これらの天気の詳細をHTMLで表示します。

ステップ9—アプリに天気データを表示する

結果をコンソールに表示することは、すべてが機能していることを確認するための良い最初のステップです。 ただし、最終的には気象データをHTMLでユーザーに表示する必要があります。 これを行うには、返された気象データを保持する変数を作成し、HTMLで補間を使用してそれを表示します。

補間を使用すると、ビューにデータを表示できます。 これを行うには、{{ }}スタイルを介してプロパティをバインドし、そのプロパティをHTMLで表示する必要があります。

weather.component.tsファイルを開き、weatherDataという変数を作成します。この変数に、APIから取得したJSONデータを割り当てます。 さらに、以前は.subscribe()括弧内にあったコードを削除し、次の強調表示されたコードに置き換えます。

src / app/講演/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を作成し、anyタイプのデータを保持できることを宣言しました。 次に、API呼び出しから受け取ったデータをその変数に割り当てました。 最後に、console.log()ステートメントを追加して、weatherDataが取得したすべての情報を保持していることを再確認しました。

この段階では、weather.component.tsファイルは次のようになっているはずです。

src / app/講演/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で表示します。 コンソールで取得した気象データからcurrentオブジェクトを調べると、conditionfeelslike_cfeelslike_ftemp_ctemp_fなどこれらの5つのプロパティすべてを利用します。

weather.component.htmlファイルをもう一度開き、表示するデータに字幕を追加します。 これらの<p>タグを2番目のcol-md-6内に追加します。

src / app/講演/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がそのデータを見つけられないことを示すエラーが発生します。 たとえば、.currentまたは.locationは未定義として表示されます。

エルビス演算子は安全なナビゲーターであり、これが発生するのを防ぎます。 Angularに、weatherDataが最初に定義されているかどうかを確認してから、そのデータをHTMLで表示するように指示します。 weatherDataにすべての情報が含まれると、Angularはバインディングを更新し、データを通常どおりに表示します。

最終的なweather.component.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 と入力すると、右側に気象データが表示されます。

サンフランシスコ、米国ダカール、セネガルホノルル、ハワイなどのさまざまな場所で試してみてください。 これらすべての場所のそれぞれの気象データが表示されます。

結論

Angular、Bootstrap、およびAPIXUAPIを使用して天気アプリを作成しました。 アプリケーションが適切に設計および設定されていることを確認しながら、Angularのベストプラクティスに従って、Angularプロジェクトを最初から設定しました。

Angularは高度なフレームワークであり、小さなWebアプリケーションから大規模で複雑なアプリケーションまで、あらゆるものを簡単に作成できます。 Angularは、他のフレームワークと同様に学習曲線がありますが、このような小さなプロジェクトは、Angularをすばやく学習し、生産的に使用し始めるのに役立ちます。

アプリケーションへの追加を検討するもう1つの機能は、HTTP要求からの処理エラーです。 たとえば、無効な場所に入力した場合です。 別の機能強化は、温度が特定のしきい値の間にある場合に異なる画像を表示することです。 他のAPIを使用してAngularでさまざまなアプリケーションを作成することもできます。

NgBootstrap を使用することもできます。これは、Angular用に構築された特別なタイプのブートストラップです。 これにより、すべての標準のBootstrap JavaScriptウィジェットと、Angular用に特別に適合された標準のインストールに含まれていないいくつかの特別なウィジェットを使用できます。

このチュートリアルの完全なコードは、GitHubで入手できます。