【初学者向け】JSONの内容をJavaScriptでHTMLに反映させる

つい数ヶ月前まで簡単なjQueryしか書いてなかった超初心者な私の備忘録です。
まだまだ勉強中の身なので、遠回りなコードかもしれませんが多目に見てください。。

## 実現したいこと
- JSONの内容が更新されたら、それをHTMLに自動的に反映されるようにしたい
- 生成・出力されたHTMLにあるボタンをクリックすると、モーダルで詳細が表示される場合とアンカーリンクで別ページに遷移させる２パターンがある

今回の場合は、テキストや画像パスをJSONに記述し、そこからHTMLとして出力します。
このJSONの内容が追加・修正された場合、JSONの更新のみでHTMLへ自動で反映されるような処理を組む必要がありました。


## HTML
```html:index.html
<div id="container"></div>
<div id="modal"></div>
```
必要なHTMLはこれだけ。
JavaScriptで生成したHTMLを入れる箱だけ作った状態です。
`<div id="container"></div>`の中にはJSONから出力されたHTMLを、
`<div id="modal"></div>`の中には、モーダル表示される場合の中身となるHTMLを出力します。

CSSは適宜記述してください、、こちらでは省略します。

## JSONの内容
例としてJSONの中身を記載します。

```json:output.json
[
  {
    "display": "link",
    "url": "リンク先のURL",
    "image": "画像パス",
    "title": "タイトル2",
    "text": ""
  },
   {
    "display": "popup",
    "url": "リンク先のURL",
    "image": "画像パス",
    "title": "タイトル1",
    "text": "テストテキスト"
  }
]
```

`display`の中身で、アンカーリンクかモーダルかを判別します。
また、`title`や`text`の中身にはHTMLタグの使用が可能です。

## JavaScript
本題のJSです。コードに関する細かい説明はコメントアウトで記述します。

```javascript:script.js
function jsonOutput() {
  // XMLHttpRequestインスタンスを作成
  let request = new XMLHttpRequest();

  // JSONファイルが置いてあるパスを記述
  request.open('GET', './assets/json/output.json');
  request.send();

  // JSON読み込み時の処理
  request.onreadystatechange = () => {
    // 全てのデータを受信・正常に処理された場合
    if (request.readyState == 4 && request.status == 200) {
      // JSONデータを変換
      let json = JSON.parse(request.responseText);

      // 生成したHTMLを入れておく変数
      let html = '';
      // 生成したモーダル用のHTMLを入れておく変数
      let modal = '';

      // JSONにあるオブジェクト数の分だけfor文で処理
      for (let i = 0; i < json.length; i++) {
        // ポップアップ表示の場合
        if (json[i].display === 'popup') {
          let htmlParts =
            '<div class="p-parts js-modalOpen" aria-expanded="false" aria-controls="modal_' +
            // 配列のインデックスは0から始まるため、分かりやすく+1して正の整数にしている
            (i + 1) +
            '">' +
            '<figure><img src="' +
            json[i].image +
            '" alt=""></figure>' +
            '<p class="p-parts__title">' +
            json[i].title +
            '</p>' +
            '<div>';

          // 先述の変数の中に、出来上がったHTMLを格納
          html += htmlParts;

          // モーダル生成
          let modalParts =
            '<div class="p-modal" id="modal_' +
            (i + 1) +
            '" aria-hidden="true">' +
            '<div class="p-modal__wrap">' +
            '<button class="js-modalClose" aria-controls="modal_' +
            (i + 1) +
            '"></button>' +
            '<h3 class="p-modal__title">' +
            json[i].title +
            '</h3>' +
            '<figure class="p-modal__image"><img src="' +
            json[i].image +
            '" alt="' +
            json[i].title +
            '"></figure>' +
            '<div class="p-modal__text">' +
            '<p>' +
            json[i].text +
            '</p>' +
            '<a class="link" href="' +
            json[i].url +
            '" target="_blank">リンク先へ飛ぶ' +
            '</a>' +
            '</div>' +
            '</div>' +
            '</div>';

          // 先述の変数の中に、出来上がったモーダル用HTMLを格納
          modal += modalParts;
        } else {
          // アンカーリンクの場合
          let htmlParts =
            '<div class="p-parts">' +
            '<a href="' +
            json[i].url +
            '" target="_blank">' +
            '<figure><img src="' +
            json[i].image +
            '" alt=""></figure>' +
            '<p class="p-parts__title">' +
            json[i].title +
            '</p>' +
            '</a>' +
            '</div>';

          // 先述の変数の中に、出来上がったHTMLを格納
          html += htmlParts;
        }
      }

      // 変数に格納したHTMLを出力
      document.getElementById('container').innerHTML = html;
      document.getElementById('modal').innerHTML = modal;
    }
  };
}
```

上記のJavaScript内で使用しているWAI-ARIAを利用したモーダルウィンドウに関しては、[こちら](https://qiita.com/RinuxJapan69/items/46c610086383a604c142)で記事化しています。
良ければご覧ください！

## さいごに
JSONすらまともに触ったことなく、更にそれをゴニョゴニョして…というのは初めての経験でしたが無事に動くものが作れました。
これを使えば、いちいちHTMLを書き換えなくてもJSONだけ更新すれば済むので、同じパーツを定期的に増やしたいときには有用かなと思います。

読んでいただきありがとうございました！