フロントエンドマスターへの道 その3 Angularでお天気アプリ

- [2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ](https://qiita.com/rana_kualu/items/915345b8f3f870cfe2aa)

上記記事の第3回。

Angularは1系以来なので、流石にわからないことが多く一気にやるのではなくすこし刻みながら作業を進めた。認証については下記に別途書いてます

- [Angular + @angular/fire でサインイン/サインアップ/ログアウトできるページを作る](https://qiita.com/hbsnow/items/41c1925d0a1bf293ba39)

また今回SSRはしていません。そのうちまた機会があればやるかもしれない。完成リポジトリは以下

- https://github.com/hbsnow-sandbox/angular-firebase-auth

## チュートリアルのサイト

- https://medium.com/@hamedbaatour/build-a-real-world-beautiful-web-app-with-angular-6-a-to-z-ultimate-guide-2018-part-i-e121dd1d55e
- https://medium.com/@hamedbaatour/build-a-real-world-beautiful-web-app-with-angular-8-the-ultimate-guide-2019-part-ii-fe70852b2d6d

今回のチュートリアルのサイト、結構そのまま進めていってもエラーになっていることが多くて結構きつくて、途中から同じものをつくるというよりも、お天気アプリっぽい気圧のチェックアプリを作る方針に変更

![Screenshot from 2019-12-28 18-25-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17669/23feee52-e164-61ea-aad5-40987c30e80f.png)

背景のグラデーションは天気によって変わります

![Screenshot from 2019-12-27 23-54-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17669/8e6c5213-69c8-992a-f196-93e96884eadc.png)

![Screenshot from 2019-12-27 23-55-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17669/2bae7bd8-72fe-4945-96fa-29012e2e01a8.png)

UIにはAngular Materialを採用して、ダークモードには対応しなかった。チュートリアルでは各コンポーネントにダークモードの判定を持たせていて、それによって切り分けるみたいな実装だったんだけど、さすがにそこまでやる気力まではわかなかった

写真には [find47](https://find47.jp/) を、気圧取得のためのAPIには [OpenWeatherMap](https://openweathermap.org/) 使っています

## Angular CLI

Angularで何かをするときには `ng` コマンドを使う。今回わりと使ったコマンドは

- `ng g c path/foo` コンポーネントの作成
- `ng g s path/bar` サービスの作成
- `ng add package` npm packageの追加

上記の3つ。上記2つについては削除するコマンドは用意されていないので、間違って作った場合には手動で削除する必要があります

こういったものが用意されているので、今回は用意されたものをそのまま使ったんだけど、TSLintのみでPrettierが入っておらず、HTMLやCSSのフォーマッタがないのが結構つらい……

あとはデフォルトの設定だとメンバ変数に `_` から始まる命名でTSLintに怒られるので、あまり初期設定を変更はしたくなかったんだけども、`"variable-name": false` だけは追加しています

## 状態管理

[NgRx](https://ngrx.io/) は単語だけは知っていたので使おうかとも思ったんだけど、Serviceに状態を持たせることができて、それで困ることは一人でこの規模だと特に問題が起こることもなさそうなので、NgRxは使わなかった


```weather.service.ts
import { Injectable } from '@angular/core';
import { environment } from './../../environments/environment';
import { HttpClient } from '@angular/common/http';
import { Weather, City } from 'src/types/weather';

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

  private _cities: City[] = [
    { value: '2128295', viewValue: '札幌', image: 'https://find47.jp/ja/i/RhnEE/image_file' },
    { value: '1850147', viewValue: '東京', image: 'https://find47.jp/ja/i/cVikh/image_file' },
    { value: '1853908', viewValue: '大阪', image: 'https://find47.jp/ja/i/plmNy/image_file' },
    { value: '1863958', viewValue: '福岡', image: 'https://find47.jp/ja/i/xewpq/image_file' }
  ];

  private _weather: Weather;
  private _city: City;

  constructor(private http: HttpClient) { }

  set weather(weather: Weather) {
    this._weather = weather;
  }

  get weather() {
    return this._weather;
  }

  get cities() {
    return this._cities;
  }

  set city(city: City) {
    this._city = city;
  }

  get city() {
    return this._city;
  }

  setCityByValue(cityValue: string) {
    this._city = this._cities.find(city => city.value === cityValue);
  }

  fetch() {
    return this.http.get(`https://api.openweathermap.org/data/2.5/weather?id=${this._city.value}&appid=${environment.openWeatherMapApi}`);
  }
}
```

WeatherServiceでは setter/getter が単純に面倒くさくて、もうpublicでもよさそうな気がした。コンポーネント側ではHTMLで使うものについてだけsetter/getterを作りました

## RxJS/Promise

このアプリでRxJSを使ったのはAPIをfetchしてくるところと、routingのところだけなので特に深く理解していなくても実装ができてしまった。

[angularfire](https://github.com/angular/angularfire) が使いやすくて、今回のアプリ程度の簡単なものであれば、ほとんど何も考えることなくいい感じの認証ができる。

- [Route users with AngularFire guards](https://github.com/angular/angularfire/blob/master/docs/auth/router-guards.md)

## HTML/CSS

HTMLが慣れてないことに加えてFormatterが特に設定していないと入ってなくてすごい辛かった

チュートリアルを本当にさらっとだけ斜め読みして書いていると、classだけはおもった動作をしなくてts側で `bar = "bar"` になっているときにhtml側で以下のようにすると

```
<div class="foo" [class]="bar"></div>
// => <div class="bar"></div>

<div class="foo" [ngClass]="bar"></div>
// => <div class="foo bar"></div>
```

こうなる。一応出力はできるけど `[class]` は既存のクラスを上書きしてしまう（プロパティバインディングというらしい）ので基本的に `ngClass` を使ったほうが良さそう。

- [ngClass](https://angular.jp/api/common/NgClass)

## 感想

Angular1系を触っていて、2で梯子を外された経験をしたせいか本当に嫌いだったAngularだったんだけど、実際に今のAngularを触ってみると普通に良かった。ただ敷かれているレールから外れるのが嫌で、TSのバージョンの低さとかLintがTSLintだったりPrettierがはいってなかったりとそのあたりを変えたときにバージョンアップが面倒になったりしないのかな、とかそういうのは気になった

学習コストについてはAngularだけ特別高いのかといわれると、Reactと比べて特別高いということはないような気がする。やりたいことは公式がほぼ用意してくれているので、技術選定でも考えることは少なそう。ただReactに比べてマニュアルを確認する機会は多くなりそうな気はする