著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにNPowerを選択しました。
前書き
Angularは、Googleによって構築されたフロントエンドWebフレームワークです。 これにより、開発者は、model-view-controller(MVC)またはmodel-view-viewmodel(MVVM)ソフトウェアアーキテクチャパターンをモデルにしたシングルページアプリケーションを構築できます。 このアーキテクチャは、アプリケーションを異なるが接続された部分に分割し、並行開発を可能にします。 このパターンに従って、AngularはそのさまざまなコンポーネントをWebアプリケーションの各部分に分割します。 そのコンポーネントは、そのコンポーネントに関連するデータとロジックを管理し、それぞれのビューにデータを表示し、アプリの他の部分から受信するさまざまなメッセージに基づいてビューを調整または制御します。
Bootstrapは、開発者がレスポンシブWebサイト(さまざまなデバイスに適応するサイト)を迅速かつ効果的に構築するのに役立つフロントエンドライブラリです。 各ページを12列に分割するグリッドシステムを使用します。これにより、ページがどのデバイスで表示されていても、ページのサイズとスケールが適切に維持されます。
APIXUは、APIを介して全球気象データをユーザーに提供します。 APIXUを使用すると、ユーザーは世界のあらゆる場所の最新の天気予報と将来の天気予報を取得できます。
このチュートリアルでは、Angular、Bootstrap、およびAPIXU APIを使用して天気アプリを作成します。 検索フォームに場所を入力し、そのフォームを送信すると、その場所の現在の天気の詳細がアプリに表示されます。 このチュートリアルで使用されるAngularバージョンは7.2.0で、使用されるBootstrapバージョンは4.2.1です。
前提条件
このチュートリアルを始める前に、次のものが必要です。
-
Node.js and npm installed on your local machine. これらの両方をNode.js websiteからインストールするか、このチュートリアルに従ってinstalling Node.js and setting up a local development environmentにインストールすることができます。
-
APIXU APIキー。 無料のAPIXUアカウントにサインアップして、無料のAPIキーhereを取得します。
-
Visual Studio Code、Atom、Sublime Textなどのテキストエディタがインストールされています。
-
JSONとその形式に精通している。 これについて詳しくは、how to work with JSON in Javascriptをご覧ください。
-
それぞれUnderstanding arrays in JavascriptとUnderstanding data types in Javascriptでさらに学ぶことができるJavascriptの配列とオブジェクトの理解。
[[step-1 -—- installing-angular]] ==ステップ1—Angularのインストール
アプリの作成を開始する前に、Angularをインストールする必要があります。 端末を開き、次のコマンドを実行して、Angular CLIをマシンにグローバルにインストールします。
npm install -g @angular/cli
Angular CLIは、Angularのコマンドラインインターフェイスです。 これは、新しいAngularプロジェクトとAngularプロジェクトを構成するさまざまなサブ要素を作成する主な方法として機能します。 -g
引数を使用すると、グローバルにインストールされます。
しばらくすると、次の出力が表示されます。
Angularのインストールからの出力
...
+ @angular/[email protected]
...
これで、Angularがローカルマシンにインストールされました。 次に、Angularアプリケーションを作成します。
[[step-2 -—- creating-your-angular-app]] ==ステップ2—Angularアプリを作成する
この手順では、新しいAngularアプリケーションを作成および構成し、BootstrapやjQueryなどのすべての依存関係をインストールし、最後にデフォルトのアプリケーションが期待どおりに動作することを確認します。
まず、ng
コマンドを使用してAngularアプリケーションを作成します。これは、ターミナルから実行できます。
[.note]#Note: 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)
Angularrouting
を使用すると、ルートとコンポーネントを使用して、さまざまなビューを持つシングルページアプリケーションを構築できます。 先に進み、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
フォルダを開きます。
ディレクトリの構造を見ると、いくつかの異なるフォルダーとファイルが表示されます。 これらすべてのファイルがhereを実行することの完全な説明を読むことができますが、このチュートリアルの目的のために、これらは理解するための最も重要なファイルです。
-
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 documentationをご覧ください。
次にBootstrapをインストールするので、これらのファイルはすべてそのままにしておくことができます。
ブートストラップには、Angularで正しく機能するためにインストールする必要がある2つの依存関係があります—jQueryとpopper.js。 jQuery
はクライアントサイドスクリプトに焦点を合わせた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
は、これらのライブラリが必要であることをまだ認識していません。したがって、jquery
、popper.js
、bootstrap.js
、およびbootstrap.css
へのパスを追加する必要があります。 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.js
とnode_modules/bootstrap/dist/css/bootstrap.css
です。
必要なファイルパスがすべて揃ったので、テキストエディタでangular.json
ファイルを開きます。 styles
配列は、CSSファイルへの参照を追加する場所ですが、scripts
配列はすべてのスクリプトを参照します。 これらの配列は両方とも、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"
]},
...
これで、Bootstrapが正しく機能するために必要なメインの.js
ファイルと.css
ファイルがインポートされました。 angular.json
ファイルからこれらのファイルへの相対パスを指定しました。.css
ファイルをstyles配列に追加し、.js
ファイルをangular.json
のscripts配列に追加します。 このコンテンツを追加した後、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
この潜在的なエラーメッセージの理由は、マシンのポート4200
が別のプログラムまたはプロセスによって使用されているためです。 そのプロセスが何かを知っている場合は、それを終了するか、上記の手順に従って別のポート番号を指定できます。
これで、アプリケーションの足場を設定できました。 次に、メインフォームと検索場所の関連する天気の詳細を含む天気コンポーネントを作成します。
[[step-3 -—- creating-your-weather-component]] ==ステップ3—天気コンポーネントの作成
Angularアプリケーションは、主にcomponentsで構成されています。これは、アプリケーション内で特定の機能を持つロジックの一部です。 このコンポーネントは、アプリケーションの画面の一部を管理するいくつかのlogicで構成されています。これは、viewと呼ばれます。
たとえば、このチュートリアルでは、次の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
ページに「アプリへようこそ!」(デフォルトのコンポーネント)が表示されたままであることに気付くでしょう。 新しく作成したコンポーネントは表示されません。 次のセクションでは、これを変更して、localhost:4200
に移動するたびに、Angularのデフォルトコンポーネントではなく、新しく作成した天気コンポーネントにアクセスできるようにします。
[[step-4 -—- accessing-your-weather-component]] ==ステップ4—天気コンポーネントへのアクセス
標準のHTMLでは、新しいページを作成するときはいつでも、新しい.html
ファイルを作成します。 たとえば、新しく作成したページに移動する既存のHTMLページがすでにある場合は、その新しいページを指すanchor
タグを持つhref
属性があります。 。 例えば:
preexisting.html
ただし、Angularでは、これは少し異なります。 この方法で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'
ここで、URLパスとコンポーネントをsrc/app/routes.ts
で宣言します。 ホームページ(http://localhost:4200
)にアクセスしたときに、新しく作成した天気予報コンポーネントにアクセスできるようにアプリを作成します。 これらの行をファイルに追加します。これにより、作成したばかりのWeatherコンポーネントにルートURLがマップされます。
src/app/routes.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/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
は、ルーター(すべてのアプリナビゲーションの実行を担当)を初期化および構成し、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
タグはルーティングをアクティブにし、ユーザーがブラウザーに入力したURLを、allAppRoutes
変数の下のroutes.ts
ファイルで以前に作成したルート定義と照合します。 次に、ルーターはHTMLでビューを表示します。 このチュートリアルでは、<router-outlet></router-outlet>
タグの直後にweather.component.html
コードを表示します。
ここで、http://localhost:4200
に移動すると、ページにweather works!が表示されます。
アプリケーションでルーティングを設定しました。 次に、場所を検索して関連する詳細を表示できるフォームと詳細セクションを作成します。
[[step-5 -—- defining-the-user-interface]] ==ステップ5—ユーザーインターフェイスの定義
Bootstrapを使用して、アプリケーションビューの足場として機能します。 ブートストラップは、あらゆるデバイス(モバイル、タブレット、またはデスクトップ)に適合する既製のレスポンシブWebサイトを作成するのに役立ちます。 これは、Webページ上のすべての行を幅12列として扱うことで実現しています。 Webページでは、行はページの一方の端からもう一方の端までの単なる線です。 つまり、すべてのページのコンテンツはその行内に含まれ、12列に等しくなければなりません。 12列に等しくない場合、別の行にプッシュダウンされます。 たとえば、Bootstrapのグリッドシステムでは、12列の行が6列の2つのセクションに分割され、次の12列の行が4列の3つのセクションに分割されます。
Bootstrap documentationで、このグリッドシステムの詳細を読むことができます。
ページを6列の2つのセクションに分割し、左側の列に検索フォームを、右側に天気の詳細を表示します。
src/app/weather/weather.component.html
を開いて、WeatherComponent
HTMLコードにアクセスします。 現在ファイル内にある段落を削除してから、次のコードを追加します。
src/app/weather/weather.component.html
Search for Weather:
Weather Details:
すべてのコンテンツを保持するために、クラスcontainer
で<div>
を作成しました。 次に、それぞれ6列の2つのセクションに分割する行を作成しました。 左側には検索フォームが、右側には天気データが表示されます。
次に、フォームを作成するために、最初のcol-md-6
列で作業します。 また、フォームに入力した内容をAPIXUに送信するボタンを追加します。APIXUは、要求された天気の詳細を返します。 これを行うには、最初のcol-md-6
クラスを識別し、<h3>
タグの下に次の強調表示されたコンテンツを追加します。
src/app/weather/weather.component.html
...
Search for Weather:
...
フォームを追加し、検索バーを保持するform-group
クラスを追加しました。 また、天気を検索するためのボタンを作成しました。 ブラウザでは、天気アプリのページは次のようになります。
これは少しコンパクトに見えるので、CSSを追加してページをより良い間隔でスタイルできます。 Bootstrapの主な利点は、独自のCSSを追加することなくHTMLに追加できるスペーシングクラスが付属していることです。 ただし、Bootstrapの標準クラスがカバーしていない追加のCSSを組み込む場合は、必要に応じて独自のCSSを作成できます。 このチュートリアルでは、Bootstrapの標準クラスを使用します。
<h3>
タグごとに、.my-4
BoostrapCSSクラスを追加します。 m
は要素にマージンを設定し、y
は要素にmargin-top
とmargin-bottom
の両方を設定し、最後に4
は追加するマージンの量を指定します。 さまざまな間隔のタイプとサイズhereの詳細を確認できます。 weather.component.html
ファイルで、次の強調表示されたコンテンツを追加して、現在の<h3>
タグを置き換えます。
src/app/weather/weather.component.html
Search for Weather:
Weather Details:
ブラウザでページをリロードすると、スペースが増えていることがわかります。
フォームと、APIXU APIから受け取った情報を表示するセクションを作成しました。 次に、フォームを接続して、現在地を正しく入力できるようにします。
[[step-6 -—- wiring-up-your-form]] ==ステップ6—フォームの配線
Angularでは、アプリケーションでユーザー入力用のフォームを作成する方法が2つあります—reactiveまたはtemplate-drivenです。 同じ結果が得られますが、各フォームタイプはユーザー入力データの処理方法が異なります。
リアクティブフォームを使用して、.component.ts
ファイルにフォームのさまざまな要素のリストを作成します。 次に、それらをそれぞれの.component.html
ファイル内で作成したHTMLフォームに接続します。 これは厳密に一方向です。つまり、データはHTMLから.component.ts
ファイルに流れ、双方向のデータの流れはありません。
テンプレート駆動フォームでは、通常のHTMLの場合と同じようにフォームを作成します。 次に、ngModel
などのディレクティブを使用して、HTMLから一方向または双方向のデータバインディングを作成し、コンポーネントのデータモデルに戻すことができます。その逆も可能です。
それぞれのアプローチには長所と短所がありますが、一般的に、次の理由により、リアクティブ形式が望ましいです:
-
さまざまな複雑さのフォームを作成する柔軟性。
-
コンポーネントの
.component.ts
ファイル内の各フォームコントロールの状態をチェックすることによる単体テストの単純さ。 -
フォーム内の値に対するsubscribeの機能。 開発者は、フォームの値ストリームにサブスクライブして、フォームに入力された値に対してリアルタイムでアクションを実行できます。
これらの長所にもかかわらず、リアクティブフォームは実装がより複雑になる場合があります。 これにより、テンプレート駆動型フォームと比較して、開発者がより多くのコードを記述することになります。 フォームタイプと最良の使用例の両方の包括的な概要を確認するには、Angular’s official guideが出発点として適しています。 このチュートリアルでは、リアクティブフォームを使用します。
リアクティブフォームを使用するには、ファイル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/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) {}
...
formBuilder
をconstructor
に追加することにより、FormBuilder
クラスのインスタンスが作成され、コンポーネント内で使用できるようになります。
これで、FormGroup
とそれぞれの値をweather.component.ts
ファイルに作成する準備が整いました。 フォームに複数の入力オプションがある場合は、FormGroup
で囲むことをお勧めします。 このチュートリアルでは、1つ(位置入力)しかありませんが、練習のためにとにかくFormGroup
を使用します。
コンポーネントに移動するときにフォームを使用する準備ができていることが重要です。 リアクティブフォームを使用しているため、フォームをHTMLにバインドする前に、まずフォーム内に要素のツリーを作成する必要があります。 これを実現するには、WeatherComponent
内のngOnInit
フックにフォーム要素を作成する必要があります。 ngOnInit
メソッドは、コンポーネントの初期化時に1回実行され、コンポーネントを使用する準備が整う前に実行する必要があると指定したロジックを実行します。
したがって、HTMLプロセスへのバインディングを完了する前に、フォームを作成する必要があります。
WeatherComponent
で、ngOnInit
フック内でフォームを初期化します。
src/app/weather/weather.component.ts
...
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.weatherSearchForm = this.formBuilder.group({
location: ['']
});
}
リアクティブフォームスタイルに従ってフォームの最初の部分を作成しました。weather.component.ts
ファイルでフォームコンポーネントを定義します。 フォームの複合要素のグループを作成しました(現時点では、location
という1つの要素があります)。 ['']
配列を使用すると、フォーム入力にいくつかの追加オプションを指定できます。たとえば、データを事前に入力したり、バリデーターを使用して入力を検証したりできます。 このチュートリアルではこれらのいずれも必要ないため、空白のままにしておくことができます。 要素プロパティhereに渡すことができるものについて詳しく知ることができます。
フォームが完成する前に、さらに2つの作業が必要です。 まず、weather.component.html
ファイルを開きます。 フォームにプロパティ[formGroup]
を割り当てる必要があります。 このプロパティは、weather.component.ts
ファイルで宣言した変数weatherSearchForm
と同じになります。 次に、location
要素(weather.component.ts
ファイルで宣言されている)をHTMLにバインドする必要があります。 weather.component.html
に、次の強調表示されたコンテンツを追加します。
src/app/weather/weather.component.html
...
...
[formGroup]
プロパティを追加し、フォームをHTMLにバインドしました。 また、この特定のinput
要素がweather.component.ts
ファイルのlocation
要素にバインドされることを宣言するformControlName
プロパティを追加しました。
ファイルを保存してブラウザに戻ると、アプリがまったく同じに見えることがわかります。 これは、フォームが正しく接続されていることを意味します。 この段階でエラーが発生した場合は、前の手順に戻って、ファイルのすべてが正しいことを確認してください。
次に、入力データをフォームに受け入れることができるようにボタンを接続します。
[[ステップ-7 ---ボタンを接続する]] ==ステップ7—ボタンを接続する
このステップでは、ユーザーの入力データを受け入れることができるように、検索ボタンをフォームに接続します。 また、最終的にユーザーの入力データをAPIXU天気APIに送信するメソッドの足場を作成します。
weather.component.html
のコードを振り返ると、ボタンのタイプがsubmit
であることがわかります。
src/app/weather/weather.component.html
これは、アクションを実行するためにフォームの値を何らかの関数に送信する標準のHTML値です。
Angularでは、その関数を(ngSubmit)
イベントで指定します。 フォーム内のボタンをクリックすると、タイプがsubmit
である限り、(ngSubmit)
イベントがトリガーされ、その後、割り当てられたメソッドが呼び出されます。 この場合、ユーザーが入力した場所を取得し、それをAPIXU APIに送信できるようにします。
まず、これを処理するメソッドを作成します。 weather.component.ts
で、1つの引数(フォームに入力した値)を受け取るメソッドsendToAPIXU()
を作成します。 次の強調表示されたコンテンツをファイルに追加します。
src/app/weather/weather.component.ts
...
ngOnInit() {
this.weatherSearchForm = this.formBuilder.group({
location: [""]
});
}
sendToAPIXU(formValues) {
}
...
次に、ngSubmit
イベントをHTMLに追加し、送信されたフォームの値をsendToAPIXU()
メソッドに渡します。
weather.component.html
...
...
ngSubmit
イベントをフォームに追加し、フォームを送信するときに実行するメソッドを接続し、weatherSearchForm
の値を引数としてハンドラーメソッド(%(weatherSearchForm.value
)。 これで、console.log
を使用してformValues
を出力することにより、これが機能することをテストできます。sendToAPIXU()
メソッドで、次の強調表示されたコンテンツをweather.component.ts
に追加します。
weather.component.ts
...
sendToAPIXU(formValues){
console.log(formValues);
}
ブラウザに移動し、Webサイトページの任意の場所を右クリックしてコンソールを開き、Inspect Elementをクリックします。 ウィンドウ上にConsoleというタブがポップアップ表示されます。 フォームにLondonと入力します。 Search for Weatherボタンをクリックすると、場所が囲まれたオブジェクトが表示されます。
コンソールからの出力はJSONオブジェクト{location: "London"}
です。 ロケーション値にアクセスする場合は、formValues.location
にアクセスしてアクセスできます。 同様に、フォーム内に他の入力がある場合は、.location
を他の要素名と交換します。
[.note]#Note:
リアクティブフォームのすべての値はオブジェクトに格納されます—ここで、キーはformBuilder.group({})
に渡した値の名前です。
#
これでボタンが配線され、正しく入力を受け取ることができます。 次に、sendToAPIXU()
メソッドにAPIXUAPIへのHTTPリクエストを作成させます。
[[step-8 -—- calling-the-apixu-api]] ==ステップ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
]
...
})
...
次に、APIXU APIへのHTTP呼び出しを行うコードを記述する必要があります。 HTTPリクエストを行うためにAngularserviceを作成することをお勧めします。 懸念事項の分離は、作成するアプリで重要です。 サービスを使用すると、アプリが作成するすべての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 file
...
@NgModule({
...
providers: [ApixuService],
...
})
...
Angularでは、作成したサービスを使用する場合は、そのサービスをmodule.ts
ファイル内のプロバイダーとして指定する必要があります。 この場合、アプリケーション全体のプロバイダーとしてapp.module.ts
で指定しました。
最後に、src/app/apixu.service.ts
ファイルを開きます。 サービスを作成するために必要なものの定型コードが表示されます。最初に、AngularからInjectable
インターフェースをインポートします。次に、サービスがprovidedIn
ルートインジェクターを使用する必要があるという事実(アプリケーション全体)。次に、サービスのdecorating(これは事実上指定することを意味します)を@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リクエストを送信し、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';
...
次に、場所という1つのパラメーターを受け取るメソッドgetWeather()
を作成する必要があります。 このメソッドは、APIXUにAPIリクエストを行い、取得した位置データを返します。
これには、APIXU APIにサインアップしたときに提供されたAPIキーが必要です。 APIXUにログインすると、ダッシュボードが表示されます。
キーが表示され、その下に、Current WeatherとForecast Weatherの両方にキーが事前に入力されたAPIURLへのリンクが表示されます。 Current Weatherの詳細の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
);
}
}
[.note]#Note:コード内で直接APIキーを使用しました。 本番環境では、これをサーバー側に安全に保存し、このキーを安全な方法で取得して、アプリケーション内で使用する必要があります。 サーバー側に安全に保存するか、Hashicorp VaultやAzure Key Vaultなどのキー管理アプリケーションを使用していくつか例を挙げます。
#
これで、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()
メソッドに場所を渡すことになります。 次に、そのデータをApixuService
のgetWeather()
メソッドに渡し、その後、その場所でAPIにHTTPリクエストを送信しました。 次に、返された応答をサブスクライブし、この例では、そのデータをコンソールに記録しました。 返されるObservable
応答を読み取る方法が得られるまで要求は開始されないため、HTTP要求では常にsubscribeメソッドを呼び出す必要があります。 Observablesは、パブリッシャーとサブスクライバーの間でメッセージを送信する方法であり、あらゆる種類のデータをやり取りできます。 サブスクライバーがサブスクライブするまで、オブザーバブルからデータを受信することはできません。その時点まで実行されないためです。
ブラウザでコンソールをもう一度開きます。 ここで、London, UKと入力し、Search for Weatherをクリックします。 タブの矢印をクリックすると、コンソールに天気の詳細のリストが表示されます。
出力には、必要なすべての天気情報を含むJSONオブジェクトが表示されます。 返されるオブジェクトは、current
オブジェクトとlocation
オブジェクトの2つです。 前者は希望する天気の詳細を提供し、後者はあなたの場所に関する詳細を提供します。
これで、天気データがコンソールに正常に表示されました。 このチュートリアルを完了するには、これらの天気の詳細をHTMLで表示します。
[[step-9 --- displaying-your-weather-data-in-your-app]] ==ステップ9—アプリに天気データを表示する
コンソールに結果を表示することは、すべてが機能していることを確認するための良い最初のステップです。 ただし、最終的にはユーザーの天気データをHTMLで表示する必要があります。 これを行うには、返された気象データを保持する変数を作成し、HTMLでinterpolationを使用してそれを表示します。
補間により、ビューにデータを表示できます。 これを行うには、{{ }}
スタイルを介してプロパティをバインドし、そのプロパティをHTMLで表示する必要があります。
weather.component.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
を作成し、any
タイプのデータを保持できることを宣言しました。 次に、API呼び出しから受け取るデータをその変数に割り当てました。 最後に、console.log()
ステートメントを追加して、weatherData
が取得したすべての情報を保持していることを再確認しました。
この段階では、weather.component.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で表示します。 コンソールで取得した気象データからcurrent
オブジェクトを調べると、condition
、feelslike_c
、feelslike_f
、temp_c
、などの値が表示されます。 temp_f
など。これらの5つのプロパティすべてを利用します。
weather.component.html
ファイルをもう一度開き、表示するデータに字幕を追加します。 次の<p>
タグを2番目のcol-md-6
内に追加します。
src/app/weather/weather.component.html
...
Weather Details:
Current weather conditions:
Temperature in Degrees Celsius:
Temperature in Degrees Farenheit:
Feels like in Degrees Celsius:
Feels like in Degrees Farenheit:
Location Searched:
次に、JSONオブジェクトから受け取ったデータをHTMLに追加します。
weather.component.html
...
Weather Details:
Current weather conditions: {{this.weatherData?.current.condition.text}}
Temperature in Degrees Celsius: {{this.weatherData?.current.temp_c}}
Temperature in Degrees Farenheit: {{this.weatherData?.current.temp_f}}
Feels like in Degrees Celsius: {{this.weatherData?.current.feelslike_c}}
Feels like in Degrees Farenheit:
{{this.weatherData?.current.feelslike_f}}
Location Searched: {{this.weatherData?.location.name}},
{{this.weatherData?.location.country}}
HTML内のweatherData
変数からデータを取得するときに、演算子?
を使用しました。 この演算子はElvis Operatorと呼ばれます。
HTTP呼び出しを行っているため、asynchronousリクエストを行っています。 ある時点でそのデータを取得できますが、すぐに応答するわけではありません。 ただし、Angularは引き続き、weatherData
変数から指定したデータをHTMLに入力します。 Angularが段落にデータを入力し始めるまでにデータを受信していない場合、Angularがそのデータを見つけられないというエラーが表示されます。 たとえば、.current
または.location
は未定義として表示されます。
エルビス演算子はsafe navigatorであり、これが発生するのを防ぎます。 Angularに、weatherData
が最初に定義されているかどうかを確認してから、そのデータをHTMLで表示するように指示します。 weatherData
にすべての情報が含まれると、Angularはバインディングを更新し、データを通常どおりに表示します。
最終的なweather.component.ts
ファイルは次のようになります。
weather.component.html
Search for Weather:
Weather Details:
Current weather conditions: {{ this.weatherData?.current.condition.text
}}.
Temperature in Degrees Celsius: {{ this.weatherData?.current.temp_c }}
Temperature in Degrees Farenheit: {{ this.weatherData?.current.temp_f }}
Feels like in Degrees Celsius: {{ this.weatherData?.current.feelslike_c
}}
Feels like in Degrees Farenheit: {{
this.weatherData?.current.feelslike_f }}
Location Searched: {{ this.weatherData?.location.name }}, {{
this.weatherData?.location.country }}.
目的のデータを出力するために、返されたJSON天気オブジェクトのパターンに従いました。 ファイルを保存してブラウザに戻り、London, UKと入力すると、右側に天気データが表示されます。
San Francisco, US、Dakar, Senegal、Honololu, Hawaiiなどのさまざまな場所で試してください。 これらすべての場所について、それぞれの気象データが表示されます。
結論
Angular、Bootstrap、およびAPIXU APIを使用して天気アプリを作成しました。 Angularのベストプラクティスに従って、Angularプロジェクトをゼロからセットアップし、アプリケーションが適切に設計およびセットアップされていることを確認しました。
Angularは、小さなWebアプリケーションから大規模で複雑なアプリケーションまで、あらゆるものを簡単に作成できる高度なフレームワークです。 Angularは、他のフレームワークと同様に学習曲線を持っていますが、このような小さなプロジェクトは、すぐに学習し、生産的に使用するのに役立ちます。
アプリケーションへの追加を検討するもう1つの機能は、HTTPリクエストからのhandling errorsです。たとえば、無効な場所に入力した場合です。 別の機能強化は、温度が特定のしきい値の間にある場合に異なる画像を表示することです。 他のAPIを使用して、Angularでさまざまなアプリケーションを作成することもできます。
Angular用に構築された特別なタイプのブートストラップであるNgBootstrapを使用することもできます。 これにより、すべての標準Bootstrap JavaScriptウィジェットと、Angularに特に適合した標準インストールに含まれていない特別なウィジェットを使用できます。
このチュートリアルの完全なコードは、GitHubで入手できます。