担当していた案件でJSでスプレッドシートからデータを取得し、動的要素を作成することになりました。
しかし、調べてみると意外にその方法を一から詳しく紹介している記事が見つかりませんでした。
そこで今回はJSでスプレッドシートからデータを取得し、動的要素を作成する方法について一から詳しく紹介します。
静的コーディング
ということで今回はJSでスプレッドシートからデータを取得し、動的要素を作成するのですが、
スプレッドシートからデータ取得する前に、まずは静的コーディングを行います。
ということでHTMLは下記のように作りました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | <section class="product"> <div class="inner-block"> <ul class="product-list"> <li class="product-item"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="https://placehold.jp/300x200.png" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color"></div> <div class="color"></div> <div class="color"></div> <div class="color"></div> </div> <p class="name">商品名商品名</p> <p class="price">¥1,2345</p> </div> </a> </li> <li class="product-item"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="https://placehold.jp/300x200.png" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color"></div> <div class="color"></div> <div class="color"></div> <div class="color"></div> </div> <p class="name">商品名商品名</p> <p class="price">¥1,2345</p> </div> </a> </li> <li class="product-item"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="https://placehold.jp/300x200.png" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color"></div> <div class="color"></div> <div class="color"></div> <div class="color"></div> </div> <p class="name">商品名商品名</p> <p class="price">¥1,2345</p> </div> </a> </li> <li class="product-item"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="https://placehold.jp/300x200.png" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color"></div> <div class="color"></div> <div class="color"></div> <div class="color"></div> </div> <p class="name">商品名商品名</p> <p class="price">¥1,2345</p> </div> </a> </li> <li class="product-item"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="https://placehold.jp/300x200.png" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color"></div> <div class="color"></div> <div class="color"></div> <div class="color"></div> </div> <p class="name">商品名商品名</p> <p class="price">¥1,2345</p> </div> </a> </li> <li class="product-item"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="https://placehold.jp/300x200.png" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color"></div> <div class="color"></div> <div class="color"></div> <div class="color"></div> </div> <p class="name">商品名商品名</p> <p class="price">¥1,2345</p> </div> </a> </li> </ul> </div> </section> |
ここからCSSでいい感じにスタイルを整えます。
整いました。
今は商品の画像等は設定せず、同じ中身を繰り返しているだけなのでイメージが掴みづらいですがデータが入ればいい感じになるでしょう。
300×200のところには商品の画像、ドットの部分には商品のカラーバリエーション一覧、そして商品名、商品価格それぞれが動的部分になります。
それではここから本題のJSを使用してスプレッドシートからデータを取得し、表示する部分を作っていきましょう。
スプレッドシートの作成
まず、スプレッドシートでデータ一覧を作成しましょう。
下記のようになりました。
A列ではメインとなる画像、B列では商品名、C列では価格、D列以降はカラーバリエーションの画像を設定しています。
なお、今回使用する画像はGoogle Driveにアップしたものを使用します。
続いて、このスプレッドシートに入力したデータをAPIとして公開します。
画像のように「拡張機能」のタブから「Apps Script」を選択し、新しいスクリプトを作成します。
すると、コードエディタが開きますのでそこに下記のコードをコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | function readData() { const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); const sheet1 = spreadsheet.getSheetByName('シート1'); const data_range = sheet1.getRange('A2:H4'); const data_values = data_range.getValues(); const return_data = data_values.map(data_row => { //data_rangeで設定した範囲内の行数を回す var colors = []; for( var i = 0; i < 5; i++) { colors.push( data_row[3+i] ); //D列からH列までの値を順に配列に追加 } return { image: data_row[0], //スプレッドシートのA列の値を追加 name: data_row[1], //スプレッドシートのB列の値を追加 price: data_row[2], //スプレッドシートのC列の値を追加 colors: colors //colorsという変数を追加 } }); return return_data; } function doGet() { const data = readData(); const response = ContentService.createTextOutput(); response.setMimeType(MimeType.JSON); response.setContent(JSON.stringify(data)); return response; } |
4行目では読み取る対象となるシート、5行目では読み取るセルの範囲を指定しています。
なお、読み取るセルの範囲の指定をするときは上記のコードの5行目のように、始まりのセル(左上のセル)と終わりのセル(右下のセル)でコロン(:)を挟むように指定してください。
8行目から23行目でスプレッドシートの行を1行ごとに回し処理しています。
data_rowにはその行の全ての値が配列で設定されています。
例えば、data_row[0]だと、作成したスプレッドシートではA列を意味しています。
13行目から15行目ではカラーバリエーション(スプレッドシートのD列以降)の値をcolorsという配列に入れ、
17行目から22行目でキーとキーに応じたセルを設定した配列オブジェクトを作成しています。
これでJSONを出力するコードができました。
「プロジェクトの保存」を行い、画像のように初めに実行される関数を指定します。
そして、デプロイボタンから「新しいデプロイ」を選択してください。
種類の選択より「ウェブアプリ」を選択し、アクセスできるユーザーには「全員」を設定してください。
アクセスできるユーザーを「全員」に設定しないとAPIにアクセスできず、JSでデータを取得することができません。
作成を押し少し待つとアクセスの承認画面が表示されるかと思いますので承認を行ってください。
承認が完了するとウェブアプリのURLが生成されたかと思います。
一旦、正しくJSONが出力されているかを確認するためにリンク先に飛んでみましょう。
下記のようにJSON形式のデータが出力されていればAPIの作成は完了です。
APIを取得
続いて、JSでJSONを取得し、HTMLに出力する部分です。
まず、先ほどの公開したAPIからJSONを取得します。
スプレッドシートから取得したデータはスプレッドシートで入力した内容1行ごとからなる多次元配列になっています。
そのため、HTML要素に出力する際にはfor()等のループを使用して中身を取り出す必要があります。
正しくデータが取得できているかを確認するため、コンソールに商品名を出力してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var api_url = '****'; //生成したAPIのURLを指定 fetch(api_url) .then(function (fetch_data) { return fetch_data.json(); }) .then(function (json) { for (var i in json) { console.log(json[i].name); } }); |
2行目には「Apps Script」で作成したウェブアプリのURLを指定してください。
こちらのコードを簡単に説明すると、
6行目でJSONデータを取得し、9行目から11行目でスプレッドシートに入力した行数回処理が回るようになっています。
画像のようにスプレッドシートに入力した内容が表示されていたら正しくデータが取得できています。
ここまできたらあとは最初の静的コーディングしたHTMLに出力すれば完成です。
ただ、最初に書いたHTMLコードは確認用にli要素を複数作っていましたが、JSのほうで商品の数だけ複製するのでli要素はベースとなる1つだけで十分です。
また、ベースとなるli要素はフロントでは表示する必要はないため、「js-based」というクラスを指定し、CSSでそのクラスには「display: none;」を指定しておきます。
なお、カラーバリエーションの要素にも「js-based」というクラスを指定し、色の数に応じて要素を増減できるようにしています。
最終的なHTMLコードがこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <section class="product"> <div class="inner-block"> <ul class="product-list"> <li class="product-item js-based"> <a href="#" class="product-link"> <div class="img-wrap"> <img src="/" alt=""> </div> <div class="product-data"> <div class="colors"> <div class="color js-based"> <img src="/" alt=""> </div> </div> <p class="name"></p> <p class="price"></p> </div> </a> </li> </ul> </div> </section> |
そして、下記のJSコードで取得したデータをこのHTMLに出力していきます!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | var api_url = '****'; //生成したAPIのURLを指定 fetch(api_url) .then(function (fetch_data) { return fetch_data.json(); }) .then(function (json) { for (var i in json) { // jsonの要素数だけ回す var base_element = document.getElementsByClassName('product-item js-based'); //元となるHTMLの要素を指定 var clone_element = base_element[0].cloneNode(true); //元となるHTMLの要素を複製 clone_element.classList.remove('js-based'); //複製した要素からクラス削除 clone_element.querySelector('img').setAttribute( 'src', json[i].image ); //src属性に取得した画像を設定 clone_element.querySelector('img').setAttribute( 'alt', json[i].name ); //alt属性に取得した商品名を設定 clone_element.querySelector('.name').textContent = json[i].name; //テキストに取得した商品名を設定 var price = new Intl.NumberFormat( 'ja-JP', {style: 'currency', currency: 'JPY'} ).format(json[i].price); //日本円と解釈し、3桁ごとのカンマ区切りにする clone_element.querySelector('.price').textContent = price; //テキストに取得し、フォーマットした価格を設定 json[i].colors.forEach(color => { if( color ) { //値が指定されているとき var base_color_element = clone_element.querySelector('.colors .js-based'); //元となるHTMLの要素を指定 var color_clone_element = base_color_element.cloneNode(true); //元となるHTMLの要素を複製 color_clone_element.classList.remove('js-based'); //複製した要素からクラス削除 color_clone_element.querySelector('img').setAttribute( 'src', color ); //src属性を設定 base_color_element.parentNode.appendChild(color_clone_element); //元となるHTMLの要素の後ろに複製した要素を追加 } }); base_element[0].parentNode.appendChild(clone_element); //元となるHTMLの要素の後ろに複製した要素を追加 } }); |
2行目には先ほど同様、「Apps Script」で作成したウェブアプリのURLを指定してください。
こちらのコードを簡単に説明すると、
12行目でベースとなるli要素を指定し、13行目で複製、14行目で複製したli要素から「js-based」というクラスを外しています。
16行目から18行目でメイン画像と商品名を設定し、20行目から21行目で取得した価格を3桁区切りの日本円にしたうえで出力しています。
23行目から34行目では配列にした「colors」を回し、存在する色の数だけ複製しています。
そして、取得したデータを設定したら、最後に複製した要素を36行目でliの末尾に追加します。
では、実際に動いているか確認してみましょう。
スプレッドシートで入力した通りに出力されていますね!
ということでこれで完成です。
jQueryを使用したコードも併せて載せておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | let api_url = '****'; //生成したAPIのURLを指定 $.getJSON(api_url, function(json_data) { for (var i in json_data) { // jsonの要素数だけ回す var clone = $('.product-item.js-based').clone();//元となるHTMLの要素を複製 clone.find('.img-wrap img').attr( 'src', json_data[i].image ); //src属性に取得した画像を設定 clone.find('img').attr( 'alt', json_data[i].name ); //alt属性に取得した商品名を設定 clone.find('.product-data .name').text(json_data[i].name); //テキストに取得した商品名を設定 clone.removeClass('js-based'); //複製した要素からクラス削除 var price = new Intl.NumberFormat( 'ja-JP', {style: 'currency', currency: 'JPY'} ).format(json_data[i].price); //日本円と解釈し、3桁ごとのカンマ区切りにする clone.find('.product-data .price').text( price ); //テキストに取得し、フォーマットした価格を設定 json_data[i].colors.forEach(color => { if( color ) { //値が指定されているとき var clone_color = clone.find('.colors .js-based').clone(); //元となるHTMLの要素を複製 clone_color.find('img').attr( 'src', color ); //src属性を設定 clone_color.removeClass('js-based'); //複製した要素からクラス削除 clone.find('.colors').append(clone_color); //指定した要素の中の最後に追加 } }); $('.product-list').append(clone); //指定した要素の中の最後に追加 } }); |
まとめ
ということで今回はJSを使用してJSでスプレッドシートからデータを取得し、動的要素を作成する方法を紹介しました。
いかがだったでしょうか。
配列の扱いが分かれば、内容的にはそこまで難しいという内容ではないかと思います。
JSでスプレッドシートからデータを取得し、動的要素を作成することがあれば参考にしてもらえたら幸いです。
以上、最後までご覧いただきありがとうございました。