天気アプリを作ってみる

今回はapi/ajaxを使って天気アプリを作ってみる。
参考サイトは[こちら](https://torutsume.net/openweathermap/)

あらすじとシナリオは

![weatherApp-Page-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481470/0d9148f9-d4cb-96fc-ce62-0a20008deab6.png)



![weatherApp-Page-2 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481470/7f2f0b2e-aee6-ff3e-de2d-268d072c93b5.png)



今回はOpenWeatherMapのapiを使う。
>OpenWeatherMapは、Webやモバイルアプリケーションの開発者に、現在の天候や予測履歴を含む各種気象データの無料APIを提供するオンラインサービスである。(Wikipediaより)

まずアカウントを作る
https://home.openweathermap.org/users/sign_up
そしたら登録したメールアドレスにメールが来るはずなのでそこのリンクを踏んだら完了
自分のapiは右上で確認できる。
(取得してから10分から60分ほどかかるらしいです)

この間に[Advanced REST client](https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo?hl=JA)を入れといた。
apiでどんな情報が取れているかを確認出来る物だ。


けど、そもそもどうやってopenweathermapのapiを導入するのか？w

調べていくと、```ajax```と```XMLHttpRequest```が関わっているそうだ。

>ajax
https://developer.mozilla.org/ja/docs/Web/Guide/AJAX

>XHMHttpsRequestについて
https://ja.javascript.info/xmlhttprequest


```https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude={part}&appid={API key}```

apiの取り方をそもそもわからないので[他のサイトさん](https://qiita.com/mikan3rd/items/a5bc87a2242e67cf17a4)を参考に実際に叩いてみたい。
記事の通りにやってみたが叩けなかった。

今回はコマンドラインでディレクトリを作ってその中でやっていたが、エクスプローラーで開いたらなぜか起動した。

突き詰めたいが現状の時間的にも能力的にもコスパが悪いので次回にしたいと思う。

まずapiを叩けないとお話にならないので参考記事からそのまま使わせてもらう。
そこから分解しながら今回のアプリの使用に落とし込んでいく。
[こちらの記事](https://hiyo-code.com/openweathermap-api/)から引っ張らせてもらった
なんとかconsoleで出力することが出来た。

まずは単純にページを開いたら表示できるようにしたい。

##スタート画面作成
htmlで書いて数値や画像だけdomで書き換えていく。
都市はラジオボタンを使う。

>ラジオボタンについて
https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/radio

```html
<body>
    <main>      
            <div class="weather">
                <div>
                    <div>
                        <h1>各地のお天気は？</h1>
                    </div>
                    <div>
                        <h2>都市の選択</h2>
                    </div>
                    <div>
                        <input type="radio" name="weather" value="選択肢1" checked>tokyo
                        <input type="radio" name="weather" value="選択肢2">選択肢2
                        <input type="radio" name="weather" value="選択肢3">選択肢3
                        <input type="submit" value="送信する">
                    </div>
                    <div>
                        <h3>現在の天気は</h3>
                        <p>気温<span id="tem"></span>℃</p>
                        <p>湿度<span id="hum"></span>%</p>
                    </div>
                </div>
            </div>
    </main>
    <script src="main.js"></script>
</body>
```
とりあえずhtmlはこんな感じ
(labelとか書いたほうがいいが余裕があったら取り組む)


##立ち上げたページに表示させる
domで```tem```と```hum```を取得してこちらに東京の天気を入れたい。


```js
    const Tem = document.getElementById("tem");
    Tem.innerHTML = temp
```
で入れる事が出来た。

しかし湿度は上記のサイトでは取得してないため自分で取ってくる必要がある。

[公式サイト](https://openweathermap.org/current#list)でパラメーターについて調べ、湿度は```humidity```らしいので、気温と同じようにとってきたら完了した。

次にアイコン画像を引っ張りたい。
アイコンも同じように探すと```weather.icon```としてあった。
これの属性はどうするか。
imgタグでやってみる。
表示されなかった。デベロッパーツールで確認したらwidth/heightが0になってたのでcssを設定する。

そしたら枠だけ出来た。
恐らくアイコンを取得できてないと考えられる。
しかしエラーなども出ていない。

[公式](https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2)によると天気それぞれのidを取得し、それを使ってsrc属性を書かないといけないことが分かった。そしてそれは天気によって変更出来るようにしないといけない。
だからjsからsrc属性を書きたい。
天気のデータをconsoleに出力させると```undifined```になっている。

調べていくと原因がわかった。
通常ではあればテキストで取得するので```let weather = obj.weather[0].description;```を使いまわすことが出来るがアイコンは画像のため使えないらしい。
だから```let icon = obj.weather[0].icon;```とするとconsoleに出力させることが出来た。

それを使ってdomでsrc属性を変更する。
```Icon.setAttribute('src','http://openweathermap.org/img/w/'+icon+'.png')```
で無事にアイコンを表示させることが出来た。
>domによるsrc属性の変更
http://sarchitect.net/10364


###ここまでのコード
```js
let targetCityName = 'tokyo'
let appId = '~~~~~~~~~~~~~~~~~~~~~~~~'
const requestUrl = "https://api.openweathermap.org/data/2.5/weather?APPID=" + appId + "&lang=ja&units=metric&q=" + targetCityName + ",jp;"

let xhr = new XMLHttpRequest();

xhr.open('GET', requestUrl);

xhr.send();

xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        ShowTodayWeather(xhr.responseText);
    }
}

function ShowTodayWeather(response) {
    let obj = JSON.parse(response)
    let weather = obj.weather[0].description;
    let city = obj.name;
    let temp = obj.main.temp;
    let humi = obj.main.humidity;
    let icon = obj.weather[0].icon;

    console.log("現在" + city + "の天気は" + weather);
    console.log(`気温は ${temp} 度です`);
    console.log(icon)

    const Tem = document.getElementById("tem");
    const Hum = document.getElementById("hum");
    const Icon = document.getElementById("icon")

    Tem.innerHTML = temp
    Hum.innerHTML = humi
    Icon.setAttribute('src','http://openweathermap.org/img/w/'+icon+'.png')
}
```

これで基本的なものを表示させることが出来た。
後は都市ごとに見れるようにする。

##都市ごとに見れるようにする。
現状は東京を示しているのは一番最初の```let targetCityName = 'tokyo'```で定義しているからである。
だからここを変数にしたい。
（本当は座標で指定したいのだが、いっぺんにやるとキャパオーバーになるのでとりあえずと指名でやる）
今回は東京・京都・沖縄の3都市を扱う。

```js
const selectCityName = ['tokyo','sapporo','okinawa']
let targetCityName = selectCityName[num]
```
としてラジオボタンでnumを指定してその都市の天気を表示させる。

まずどの都市にチェックが入ってるかをalertで表示させたい。

```js

function clickbtn(weather) {
    var elements = document.getElementsByName("weather")
    var result;
    for (var i = 0; i < elements.length; i++){
        if (elements[i].checked) {
            result = elements[i].value;
            check()
            break;
        })
    }
    alert(result)
}
```

[ここの記事](https://javascript.programmer-reference.com/js-radio-value/)を参考にして組んでみたが```undefinede```が返ってきた。



```clickbtn``` の引数を空欄したら0が返ってきた。

しかし404エラー not foundと出てきた。
で、今まで最初に書いたものをcheck関数に入れてたが、そのままコピペしたら反映させることが出来た。
なぜ？

##これでとりあえず完成である。

しかし都市を指定する前にアイコンを表示するところに灰色の線が出てきてしまう。
cssでどうにか消そうとしたが厳しそうなので、都市を指定してからimgタグを追加するようにする。

domで追加しようとした所
```Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.```
が返ってきた。コイツ嫌い、、、、
けど、前も見た気がするかちゃんと理解したい。

恐らくうっかりミスの
```iconimg.appendChild("Icon")```となっていたのが原因であると考えらえられる。

これを関数の中に入れると東京の後に京都を表示させると2つ目のアイコンが表れてしまうので、関数のそとに置く。

とりあえずこれで一通り完成である。


##場所を都市名ではなく座標指定にする
恐らく2次元配列で可能だと考える。

```js
             const selectCityName2 = [
                  ["kandamyouzin", "35.7020186", "139.7657056"],
                  ["kyoutoUzi", 35.2926336, 136.633759]
             ];
            var targetCityName2 = selectCityName2[result][1]
            var targetCityName3 = selectCityName2[result][2]
const requestUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${targetCityName2}&lon=${targetCityName3}&appid=${appId}&units=metric
```
座標でのapiの叩き方は[公式参照](https://openweathermap.org/current#name)
最後に```&units=metric```を足した。
これを足さないと華氏になる。

これで問題ない
(けどqiitaテンプレートリテラルはダメなんですかね、、、)