見出し画像

『JavaScriptを極める3ヶ月 アプリ開発に使える知識を徹底的に学ぶ』という勉強会の3日目をまとめる②

X-HACK様の主催する勉強会の『JavaScriptを極める3ヶ月 アプリ開発に使える知識を徹底的に学ぶ』という勉強会の学んだことについて備忘録&復習としてまとめてみようと思います。


※この記事を見る前提知識としてJavaScriptの基本文法とオブジェクト指向&プロパティの概念、簡単なchromeデベロッパー・ツールの使い方を覚えておくと読みやすいと思います。


※第三回からの内容となるので1、2回目も内容も書いていければ良いですが長くなりますので省略したいと思います。機会があれば書こうと思います。


※まとめると長くなりますので①、②と分けております。

前回はこちら

こちらも見てくださるとうれしいです。

1、今回のゴール

・canvas APIを使いアートを作る
・ぐるなびAPIを使い店の情報を取得し検索機能を作る+
 お気に入り機能を作る


今回は2番目の「ぐるなびAPIを使い店の情報を取得し検索機能を作る
+お気に入り機能を作る」についてまとめていきたいと思います。

完成品はこちら

「焼肉」「新宿」と検索して店名を出して、★マークをクリックして
お気に入り機能も付いていますね!
これらを作っていくことがゴールとなります。

がその前に前提知識として「API・Web API」「JSONコード
Ajax通信」という3つの知識を簡単に説明します。

2、API・Web APIって何?

まずはAPIについてお話します。そもそもAPIというのは

API (Application Programming Interface) とは、あるソフトウェアが、他のソフトウェアやハードウェア等、外部とやりとりをするために備えている機能や規則の集まりです。
Web開発においては、API と言えば一般的にはコーディング上の取り決めです (例えば メソッド 、プロパティ 、 events、URL) が挙げられます。
ブラウザーのコンポーネントやユーザーのコンピュータ上にあるソフトやハード、第3者のウェブサイトやサービスとやり取りするアプリケーションを開発するには API を使います。
(引用:MDN Web Docs 用語集: ウェブ関連用語の定義API>API)

ざっくり言ってしまうと、Web APIというのは「インターネット上にある、
ほにゃららAPIという関数を使ってその機能を組み込んでいくよ!

というイメージを持ってもらえるといいでしょう。

しかし、その機能を使いこなすにはhttpプロトコル等ネットワーク知識などが必要となりますのでこちらの記事を見られた方がいいでしょう。

またWeb技術を体系的に学ぶならこちらの本がおすすめです。

「それじゃあJavaScriptはどのようにしてWeb APIを引っ張って機能に組み込んでいくの?」という疑問を持つでしょう。
今回の取得方法をざっというと「使いたいWebサービスのAPIサーバーに
問い合わせをするコードを組み込む
」ということです

では今回使うぐるなびAPIを例にとり説明しましょう。

ここのページで新規アカウントを発行してもらいAPIキー
を取得しましょう。
その後、トップページに戻り「API一覧」に行き
レストラン検索APIのテストツールをクリックしましょう

画像1

そして、keyidに取得したAPIキーと、下タブのaddress(住所を選び新宿と入力し「クエリを送信」をクリックしましょう。

画像2

下につらつらーっとコードが出てきましたね!
これは後述するJSONというデータフォーマットなのですが
新宿にある飲食店のデータが出ています!
そして真ん中にあるURLをコードに組み込んでAPIを取得していくという
わけなのです

ちなみに下タブなのですがaddressのほかにname(店の名前)tel(電話番号)など様々なデータ情報を絞れる検索できます。

飲食店の住所をつかうアプリを作るときに検索指定として使えそうですね!

※ちなみに上の図のようにAPIキーを隠しているのと
後述するコードに「gitにapikeyを上げないように!!」と書いてありますが
もし、APIキーをGitやnoteなど誰でも見えるところに置いてしまったら
不正利用等に利用される恐れがあります。

また別の勉強会の方(インフラエンジニアの方)からお聞きしたのですが
AWS(アマゾンのクラウドコンピューティングサービス)
のAPIキー(アクセスキー)をGitに挙げてしまったら高額な請求額が来てしまったということがあったらしいです。

GitHub などの公開リポジトリにキーが公開されないか監視している BOT がたくさんいます。 GitHub に「 AWS キーペアを上げると抜かれるってほんと??? – Qiita」 によると、GitHub にパブリックリポジトリを作成し、権限が何もない AWS アクセスキー・シークレットアクセスキーを公開すると、なんと13分で不正アクセスがあったとのこと。
(引用:クラウド破産について)

AWSにアクセスキーをGitに乗せた結果・・・

・・・マジでAPIキーの取り扱いには気を付けましょう!!!

3、JSONコードって?

前述したJSONですが、これはデータフォーマットの形式の一つです。他にも「XML」「CSV」がありますが「JSON」がよく使われているそうですね。

データフォーマットについてはX-Hack様とよももさんの記事が超わかりやすいです!

他の解説も分かりやすいので是非!

次にtryit Editorを使いJSONを記述していきましょう!

<!DOCTYPE html>
<html>

<body>
The content of the body element is displayed in your browser.
</body>

</html>

とあるので<body>の中に<script>を入れ、そこにコードを入れていきます。
その中で{}波括弧を作り変数、配列などのデータを入れいていきましょう。

書き方はこちら


<!DOCTYPE html>
<html>

<body>
The content of the body element is displayed in your browser.
</body>
<script>
{
   "name":"りょう",
   "age":25,
   "like_music":"hip-hop",
   "like_artist": ["Chris_Brown","migos","Drake","Kendrick_Lamar"]
}
</script>
</html>

変数にも「”」入れたり「=」の代わりに「:」入れたりとしていますがJavaScriptの書き方に似ていますね!

さて、このJSONコードあっているか確かめましょう!

このツールを使って確かめましょう!

画像3

「JSON is valid! (JSONは完璧です。)」とでましたね!下に読み込まれた
データも書いてあります!

ちなみにJSONでオブジェクトも作ることもできます。

<!DOCTYPE html>
<html>

<body>
The content of the body element is displayed in your browser.
</body>
<script>
{
   "name":"りょう",
   "age":25,
   "music":{
   "like_music":"hip-hop",
   "like_artist": ["Chris_Brown","migos","Drake","Kendrick_Lamar"]
    }
}
</script>
</html>

「music」というオブジェクトを作り、変数like_musicと配列like_artistを
まとめてますね!

4、Ajax通信って?

さて次はAjax通信というものに行きましょう。

Ajaxとは「Asynchronous JavaScript + XML」の略
Asynchronousとは、非同時性の、非同期のつまり、「JavaScriptとXMLを使って非同期にサーバとの間の通信を行うこと。」
(引用:初心者目線でAjaxの説明- Qiita)

こちらの記事の説明通りです!以上!

といってしまったら元も子もないので今回の勉強会で学んだ
「XMLHttpRequest」のプロパティである「xhttp.onreadystatechange」
をコードの一部分を見ながら教えていきます。

        xhttp.onreadystatechange = function() {
         if (this.readyState == 4 && this.status == 200) {
           let res = JSON.parse(xhttp.responseText);
           for (let i = 0; i < res.rest.length; i++) {
             addCardItem(res.rest[i]);
           }
         }
       };
       xhttp.open("GET", _url, true);
       xhttp.send();

始めに「xhttp.onreadystatechang」とあります。
これは通信状態が変化した時にイベントハンドラとなります。
後述する「readyState」の値が更新されるたびに呼び出されます。

次に関数の中にif (this.readyState == 4 && this.status == 200)...とあります
「readyState」これは通信の状態を表す値を示しています。
これをデベロッパーツールを使いリアルタイムで見てみましょう。

watchタブを使いthis.readyStateの部分の値が変化したことが
分かりましたでしょうか。ちなみに数値が何を表しているかといいますと。

0 UNSENT XHRオブジェクトの作成直後
1 OPENED open()メソッドの呼び出し後
2 HEADERS_RECEIVED レスポンスヘッダの受信後
3 LOADING レスポンスボディを受信中(繰り返し実行される)
4 DONE XHR通信の完了後

というふうに1つ1つのプロセスを表しているのです。
ということは、この分岐は「readyState」が4になれば
「let res = JSON.parse(xhttp.responseText);」へ
行けるよという風になります。
(「let res = JSON.parse(xhttp.responseText);」は後述)

しかし、このコードの書き方は古いらしく最近ではこのような書き方が多いらしいです。

    function sendRequest(request_url) {
     let xhttp = new XMLHttpRequest();
     xhttp.onload = function () {
       let res = JSON.parse(xhttp.responseText);
       for (let i = 0; i < res.rest.length; i++) {
         addCardItem(res.rest[i]);
       }
     };
     xhttp.open("GET", request_url, true);
     xhttp.send();
   }

「xhttp.onload」と変化してますね。これは受信が成功、終了した時
に呼び出されるプロパティです。

通信状況を気にしなければ、「xhttp.onload」でもよいというわけですね!

5、コードを見てみよう!

今回書いたコードはこちらとなります!

<!doctype html>
<html lang="ja">

<head>
 <meta charset="utf-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>X-HACK ぐるなび検索</title>
 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
 <link rel="stylesheet" href="https://dhbhdrzi4tiry.cloudfront.net/cdn/sites/foundation.min.css">
</head>

<body>

 <!-- ヘッダー -->
 <div class="title-bar" data-responsive-toggle="realEstateMenu" data-hide-for="small">
   <button class="menu-icon" type="button" data-toggle></button>
   <div class="title-bar-title">Menu</div>
 </div>
 <div class="top-bar" id="realEstateMenu">
   <div class="top-bar-right">
     <ul class="menu">
       <li><a href="#">My Account</a></li>
       <li><a class="button">Login</a></li>
     </ul>
   </div>
 </div>

 <!-- 検索フォーム -->
 <div class="row">
   <div class="small-2 large-2 columns">検索ワード</div>
   <div class="small-4 large-4 columns">
     <input id="search-id" class="" type="text" placeholder="検索ワードを入力してください" />
   </div>
   <div class="small-6 large-4 columns">
     <a class="button" onclick="loadUrl()">検索</a>
     <a class="button" onclick="favoriteList()">お気に入りリスト</a>
   </div>
 </div>

 <!-- リスト -->
 <div id="main-block" class="row small-up-1 medium-up-2 large-up-3">
 </div>

 <!-- フッター -->
 <footer>
   <div class="row">
     <div class="medium-6 columns">
       <ul class="menu float-right">
         <li class="menu-text">X-HACK</li>
       </ul>
     </div>
   </div>
 </footer>


 <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
 <script src="https://dhbhdrzi4tiry.cloudfront.net/cdn/sites/foundation.js"></script>
 <script>
   $(document).foundation();
   // 本来はサーバー側で処理してユーザーからは見えないようにする
   const API_KEY = "//省略//"; // apikeyを入力 注意:gitにapikeyを上げないように!!
   const mainBlock = document.getElementById("main-block");
   const FAVORITE_SHOP_KEY = "favorite_shop"

   function deleteAllChildNodes() {
     // 全ての子要素を削除する
     while (mainBlock.firstChild) mainBlock.removeChild(mainBlock.firstChild);
   }

   function favoriteList() {
     deleteAllChildNodes();
     list = localStorage.getItem(FAVORITE_SHOP_KEY);
     let url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&id=${list}`;
     sendRequest(url);
   }

   function loadUrl() {
     deleteAllChildNodes();
     // 検索ワードを取得する
     let searchData = document.getElementById("search-id").value;
     let url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&freeword=${searchData}`;
     sendRequest(url);
   }

   function sendRequest(request_url) {
     let xhttp = new XMLHttpRequest();
     // 通信が終わった時の処理
     xhttp.onload = function () {
       let res = JSON.parse(xhttp.responseText);
       for (let i = 0; i < res.rest.length; i++) {
         addCardItem(res.rest[i]);
       }
     };
     // データ取得開始
     xhttp.open("GET", request_url, true);
     xhttp.send();
   }

   // DOMを動的に生成している
   function addCardItem(item) {
     let node = document.createElement("div");
     let p_node = document.createElement("p");

     let div = document.createElement("div");
     let img_node = document.createElement("img");
     let icon_node = generateIcon(item.id);

     img_node.src = item.image_url.shop_image1;
     div.append(img_node);
     p_node.append(icon_node);
     node.setAttribute("class", "column");
     node.append(p_node);
     node.append(div);
     mainBlock.appendChild(node);
   }

   function generateIcon(shop_id) {
     let icon_node = document.createElement("i");
     icon_node.shop_id = shop_id;
     icon_node.classList.add("fa");
     icon_node.classList.add("fa-star");
     icon_node.classList.add("fa-3x");
     icon_node.style.color = "black";

     icon_node.onclick = function () {
       if (icon_node.style.color == "black") {
         this.style.color = "pink";
         addFavoriteList(this.shop_id);
       } else {
         this.style.color = "black";
       }
     }

     return icon_node;
   }

   function addFavoriteList(shop_id) {
     let favorite_shop = localStorage.getItem(FAVORITE_SHOP_KEY);
     // 一番最初はundefinedなので、配列として初期化する
     if (favorite_shop == undefined || favorite_shop == "") {
       favorite_shop = [];
     }
     // 配列の中身が0の場合は、パースしない
     if (favorite_shop.length > 0) {
       favorite_shop = favorite_shop.split(",");
     }
     // クリックした要素のIDを追加する
     favorite_shop.push(shop_id);
     // ストレージに保存する
     localStorage.setItem(FAVORITE_SHOP_KEY, favorite_shop);
   }

 </script>
</body>

</html>

長いですね笑
少しづつ紐解いていきましょう!

6、HTMLを見てみる

まずはHTMLをざっと見ていきましょう。

<!doctype html>
<html lang="ja">

<head>
 <meta charset="utf-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>X-HACK ぐるなびAPI</title>
 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
 <link rel="stylesheet" href="https://dhbhdrzi4tiry.cloudfront.net/cdn/sites/foundation.min.css">
</head>

<body>

 <!-- ヘッダー -->
 <div class="title-bar" data-responsive-toggle="realEstateMenu" data-hide-for="small">
   <button class="menu-icon" type="button" data-toggle></button>
   <div class="title-bar-title">Menu</div>
 </div>
 <div class="top-bar" id="realEstateMenu">
   <div class="top-bar-right">
     <ul class="menu">
       <li><a href="#">My Account</a></li>
       <li><a class="button">Login</a></li>
     </ul>
   </div>
 </div>

 <!-- 検索フォーム -->
 <div class="row">
   <div class="small-2 large-2 columns">検索ワード</div>
   <div class="small-4 large-4 columns">
     <input id="search-id" class="" type="text" placeholder="検索ワードを入力してください" />
   </div>
   <div class="small-6 large-4 columns">
     <a class="button" onclick="loadUrl()">検索</a>
     <a class="button" onclick="favoriteList()">お気に入りリスト</a>
   </div>
 </div>

 <!-- リスト -->
 <div id="main-block" class="row small-up-1 medium-up-2 large-up-3">
 </div>

 <!-- フッター -->
 <footer>
   <div class="row">
     <div class="medium-6 columns">
       <ul class="menu float-right">
         <li class="menu-text">X-HACK</li>
       </ul>
     </div>
   </div>
 </footer>

<title>の次にbootstrap、foundationというCSSフレームワークを
使用すると書いてますね!

 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
 <link rel="stylesheet" href="https://dhbhdrzi4tiry.cloudfront.net/cdn/sites/foundation.min.css">

これらはHTMLの見た目を整えたり、レスポンシブデザインを作るのに便利なツールです!

ここでいえば

  <!-- ヘッダー -->
 <div class="title-bar" data-responsive-toggle="realEstateMenu" data-hide-for="small">
   <button class="menu-icon" type="button" data-toggle></button>
   <div class="title-bar-title">Menu</div>
 </div>
 <div class="top-bar" id="realEstateMenu">
   <div class="top-bar-right">
     <ul class="menu">
       <li><a href="#">My Account</a></li>
       <li><a class="button">Login</a></li>
     </ul>
   </div>
 </div>

の部分ですね。動画で見てみましょう。

デベロッパー・ツールを使用し、スマートフォンの画面の場合はどのように表示されているか、またどのようなコードを使っているのか確認しました。PCとは表示が違いますね!

このようなCSSフレームワークを使いこなせればいいですね!

※ちなみにフロントエンドサイトはデザインを担当することはあまりないようです(Webデザイナーの領域になるので)。
なので、デザインに時間かけたくないけどある程度の体裁整えたい、、、
という方はこれらのツールを使えばいいよ!
と松田さんがおっしゃってました。
なるほど!

あとはidとclass名をざっと見ていただけるといいでしょう。

7、scriptコードを見る

本題であるscriptを見ていきましょう。

 <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
 <script src="https://dhbhdrzi4tiry.cloudfront.net/cdn/sites/foundation.js"></script>
 <script>
   $(document).foundation();
   // 本来はサーバー側で処理してユーザーからは見えないようにする
  // apikeyを入力 注意:gitにapikeyを上げないように!!
   const API_KEY = "//省略";
   const mainBlock = document.getElementById("main-block");
   const FAVORITE_SHOP_KEY = "favorite_shop"

   function deleteAllChildNodes() {
     // 全ての子要素を削除する
     while (mainBlock.firstChild) mainBlock.removeChild(mainBlock.firstChild);
   }

   function favoriteList() {
     deleteAllChildNodes();
     list = localStorage.getItem(FAVORITE_SHOP_KEY);
     let url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&id=${list}`;
     sendRequest(url);
   }

   function loadUrl() {
     deleteAllChildNodes();
     // 検索ワードを取得する
     let searchData = document.getElementById("search-id").value;
     let url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&freeword=${searchData}`;
     sendRequest(url);
   }

   function sendRequest(request_url) {
     let xhttp = new XMLHttpRequest();
     // 通信が終わった時の処理
     xhttp.onload = function () {
       let res = JSON.parse(xhttp.responseText);
       for (let i = 0; i < res.rest.length; i++) {
         addCardItem(res.rest[i]);
       }
     };
     // データ取得開始
     xhttp.open("GET", request_url, true);
     xhttp.send();
   }

   // DOMを動的に生成している
   function addCardItem(item) {
     var node = document.createElement("div");
     let p_node = document.createElement("p");

     let div = document.createElement("div");
     let img_node = document.createElement("img");
     let icon_node = generateIcon(item.id);

     img_node.src = item.image_url.shop_image1;
     div.append(img_node);
     p_node.append(icon_node);
     node.setAttribute("class", "column");
     node.append(p_node);
     node.append(div);
     mainBlock.appendChild(node);
   }

   function generateIcon(shop_id) {
     let icon_node = document.createElement("i");
     icon_node.shop_id = shop_id;
     icon_node.classList.add("fa");
     icon_node.classList.add("fa-star");
     icon_node.classList.add("fa-3x");
     icon_node.style.color = "black";

     icon_node.onclick = function () {
       if (icon_node.style.color == "black") {
         this.style.color = "pink";
         addFavoriteList(this.shop_id);
       } else {
         this.style.color = "black";
       }
     }

     return icon_node;
   }

   function addFavoriteList(shop_id) {
     let favorite_shop = localStorage.getItem(FAVORITE_SHOP_KEY);
     // 一番最初はundefinedなので、配列として初期化する
     if (favorite_shop == undefined || favorite_shop == "") {
       favorite_shop = [];
     }
     // 配列の中身が0の場合は、パースしない
     if (favorite_shop.length > 0) {
       favorite_shop = favorite_shop.split(",");
     }
     // クリックした要素のIDを追加する
     favorite_shop.push(shop_id);
     // ストレージに保存する
     localStorage.setItem(FAVORITE_SHOP_KEY, favorite_shop);
   }

 </script>
</body>

</html>

こちらも、foundationを使うよ!とコードが入力されてますね!
それと、jQueryというJavaScriptのライブラリがありますが今回は
省略します。

<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
 <script src="https://dhbhdrzi4tiry.cloudfront.net/cdn/sites/foundation.js"></script>

(Foundation5をJavaScriptとして使うにはjQueryが必要らしいです)

ここで僕なりの<script>コードを見る時のコツなのですが、
VSCode等のテキストエディタでコードを格納する機能が
あるのでそれらを使ってみたらわかりやすいと思います。

また、VSCodeのプラグインで、こちらを導入するのもいいでしょう。

対応するカッコに縦横線のハイライトを表示してくれます。

画像4


このように見方を工夫して見てみるとコードを早く読み取れるように
なるので、いろいろと試してみてください!


最初のコードを見てみましょう

     $(document).foundation();
     // 本来はサーバー側で処理してユーザーからは見えないようにする
    //apikeyを入力 注意:gitにapikeyを上げないように!!
     const API_KEY = "APIKey 省略"; // 
     const mainBlock = document.getElementById("main-block");
     const FAVORITE_SHOP_KEY = "favorite_shop";

「$(document).foundation();」はfoundationを適用させるために配置します。
そして
・定数「API_KEY」にAPIキー
・定数「mainBlock」にdocument.getElementById("main-block");とリスト
 に参照させて、
・定数「 FAVORITE_SHOP_KEY」に"favorite_shop"を取得させます
 (お気に入り機能を作るために必要)
というふうにグローバルスコープとなる定数を入れていきます。


次に関数deleteAllChildNodesを見ていきます。

    function deleteAllChildNodes() {
     // 全ての子要素を削除する
     while (mainBlock.firstChild) mainBlock.removeChild(mainBlock.firstChild);
   }

内容としては定数「mainBlock」にある最初のノード要素があるなら、
それらを取り除くよ!という意味です。

お気に入り機能を表示する「function favoriteList」と
検索ワードを取得し結果を出す「function favoriteList」の
最初に使われます。


お気に入り機能を表示する「function favoriteList」を見てみましょう。

    function favoriteList() {
     ⓵deleteAllChildNodes();
     ⓶let list = localStorage.getItem(FAVORITE_SHOP_KEY);
     ⓷let url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&id=${list}`;
     ⓸sendRequest(url);
   }

⓵deleteAllChildNodes()を実行し前のノードを消す
②関数favoriteListに「localStorage」にあるFAVORITE_SHOP_KEY
を引っ張りだし変数「List」に入れる
③変数「url」にテンプレートリテラルで「API_KEY」と「list」を入れていき
取得
④「url」を関数sendRequestに送ります

という流れです!

localStorageについてはこちら。

後述するようにお気に入りボタンを押すとFAVORITE_SHOP_KEYを
localStorageに保存するようにしているので、ここの関数で
その中身を出しているのですね!


次に検索ワードを取得し結果を出す「function favoriteList」を

    function loadUrl() {
     ⓵deleteAllChildNodes();
     ⓶let searchData = document.getElementById("search-id").value;
     ⓷let url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&freeword=${searchData}`;
     ⓸sendRequest(url);
   }

⓵deleteAllChildNodes()を実行し前のノードを消す
②変数「searchData」にsearch-id(ここでいう検索ワード)
に入力された文字を取得
③変数「url」にテンプレートリテラルで「API_KEY」と「searchData」を入れていき取得
④「url」を関数sendRequestに送る

という流れです!
search-idはどこなのか抑えれば簡単に読めますね!

あと上2の関数はURLを受け取ってますが、このURLは
ぐるなびAPIから受け取ったJSONデータです。それを踏まえて
見てみましょう。

関数「sendRequest」見てみます。上2つの関数から送られたURLは
どのように処理されるのでしょうか。

    function sendRequest(request_url) {
     ⓵let xhttp = new XMLHttpRequest();
     ⓶xhttp.onload = function () {
       let res = JSON.parse(xhttp.responseText);
     ⓷for (let i = 0; i < res.rest.length; i++) {
         addCardItem(res.rest[i]);
       }
     };
   ⓸xhttp.open("GET", request_url, true);
     xhttp.send();
   }

「request_url」を引数としてます。これは「function favoriteList」
「function favoriteList」の「url」をもらっているわけです。

処理の順番に見ていきます
⓵変数「xhttp」で「XMLHttpRequest」をnewで新しく取得
 ※XMLHttpRequestで、ブラウザ上でサーバーとHTTP通信する
②HTTP通信が完了(=onload)されたら受け取ったURLにある
 JSONデータを解析し、記述されている値やオブジェクトをJavaScripに
 構築する。
③受け取ったデータを関数addCardItemに繰り返し渡す。
 ※ぐるなびAPIはJSONデータを1ページにつき10しかパースできない。
④xhttp.openメソッドでURLにリクエスト、
 xhttp.sendメソットでサーバへリクエストを送信

という流れです。ここでAjax通信処理が行われているわけです。
通信プロトコル等の知識がないと難しいですね。

上記で出たメソッドなど

「xhttp.open」のところでGETとありますがPOSTというメソッドもあります。違いが分かりにくいのでこちらの記事を参照してみてください。

次に関数「addCardItem」です。

function addCardItem(item) {
   ⓵let node = document.createElement("div");
     let p_node = document.createElement("p");

     let div = document.createElement("div");
     let img_node = document.createElement("img");
     let icon_node = generateIcon(item.id);

   ⓶img_node.src = item.image_url.shop_image1;
   ⓷div.append(img_node);
     p_node.append(icon_node);
   ⓸node.setAttribute("class", "column");
   ⓹node.append(p_node);
     node.append(div);
   ⓺mainBlock.appendChild(node);
   }

⓵変数「note」「p_note」等をcreateElementでHtml要素を取得
 加えてicon_nodeにgenerateIcon(item.id)を取得
②img_node.srcでJSONデータの「image_url.shop_image1」の
 URLを取得
 ※「image_url.shop_image1」は下の青の部分です

画像5

③変数「div」に「img_node」の画像をappendで追加&
  変数「p_node」にアイコンを追加
⓸変数「node」に「setAttribute」を使いclass column属性を追加

⑤「node」に「p_node」「div」を追加
⑥グローバルスコープ定数「mainBlock」に「node」を追加。

という順番です。1つ1つどこが
参照されているか理解できるといいですね!


次はアイコンの生成と操作に関する関数generateIconです。

    function generateIcon(shop_id) {
    ⓵let icon_node = document.createElement("i");
    ⓶icon_node.shop_id = shop_id;
    ⓷icon_node.classList.add("fa");
     icon_node.classList.add("fa-star");
     icon_node.classList.add("fa-3x");
    ⓸icon_node.style.color = "black";

   icon_node.onclick = function{
   ~~省略~~
  }
  return icon_node;
   }

⓵変数「icon_node」を生成しHtml要素を取得
⓶icon_nodeにshop_idを取得
⓷「classList.add」を使いFont Awesomeのクラス値を取得
 →ここでアイコンが生成される
⓸初期値にカラー”Black”を指定する

Font Awesomeはこちら。アイコンを簡単に生成できます。


つぎはアイコンがクリックされた場合の関数です。

   icon_node.onclick = function () {
       if (icon_node.style.color == "black") {
         this.style.color = "pink";
         addFavoriteList(this.shop_id);
       } else {
         this.style.color = "black";
       }
     }

     return icon_node;

ここでIf分岐してますね。ここでは

もしアイコンのカラーが「black」ならば→アイコンが「pink」に
変化し店のidを関数addFavoriteListへ送る。

そうでないなら(「pink」ならば)→「Black」に変化する

という風になってますね!
フローチャートにするとこのようになります。

画像6

ちなみにここでいう「this」はこちらの二つを指しています。

無題

さて最後の関数であるaddFavoriteListを見てみましょう。
この関数はお気に入り登録した店のIDを「localStorage」を使って
お気に入りリストを表示させます!

function addFavoriteList(shop_id) {
    ⓵let favorite_shop = localStorage.getItem(FAVORITE_SHOP_KEY);
     // 一番最初はundefinedなので、配列として初期化するif (favorite_shop == undefined || favorite_shop == "") {
       favorite_shop = [];
     }
     // 配列の中身が0の場合は、パースしないif (favorite_shop.length > 0) {
       favorite_shop = favorite_shop.split(",");
     }
     // クリックした要素のIDを追加する
    ⓸favorite_shop.push(shop_id);
     // ストレージに保存する
    ⓹localStorage.setItem(FAVORITE_SHOP_KEY, favorite_shop);
   }

前述したlocalStorageが出てきてますね!


順番に見ていきましょう。

⓵favorite_shopにlocalStorage.getItem(FAVORITE_SHOP_KEY)を取得。
 
⓶if 分岐で「favorite_shop == undefined」または「 favorite_shop == ""」
 ならばavorite_shopという配列を生成する。
 →お気に入りのない状態では「favorite_shop == undefined || favorite_shop  == ""」であるので配列が生成される

⓷お気に入りの登録がない場合、何も表示されなくする。

⓸クリックしたshop_id要素をfavorite_shopに入れる。

⑤favorite_shopをlocalStorageに格納する。

以上です!お疲れさまでした。

8、まとめと課題

今回は

「API・Web API」「JSONコード」「Ajax通信」

・API機能を使いJSONコードを活用していく

・localStorageでお気に入り機能を作った。

の3つを特に学べました。

ちなみに松田さんいわくこのぐるなびAPIのコードを読めるようになればVue.jsが学びやすくなるそうです!

Twitterで”GET"、”POST”ってわからない、、、という方もよく見かけるのですが今回の勉強会のように使い方を体験したら
「ああ、このようになるんだな!」と理解できると思います!
(と偉そうに言ってる僕もまだ”GET”、”POST”の使い分けがまだまだ理解できない部分もあります笑。)

ちなみに、X-Hack様が過去に行われた「JavaScriptと無料APIを駆使してウェブアプリ開発ハンズオン」勉強会とほぼ同じ内容になります。

以下過去に行われた勉強会の記事です。

こちらも是非おすすめです!どの記事もまとまっていて読みやすいです!

前回と同じく読みにくい文章になりましたが、「ここが違うよ」とか
「ここ誤字じゃない?」というところがありましたらTwitterかnoteで
コメントしてくださるとうれしいです!


ここまで見てくださりありがとうございました。
次回は4日目の勉強会をまとめようと思います!

この記事が気に入ったらサポートをしてみませんか?