質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

1447閲覧

WEBアプリでスプレッドシートのデータを表示とカスタマイズについて

sdgs

総合スコア1

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2022/07/27 07:48

前提

この記事を参考にし、スプレッドシートのでまとめているデータをWEBアプリにてデータ表示を実装しています。
下記2点について教えていただきたいです。

実現したいこと

①右側のフィルタのフリーテキスト以外に、プルダウンでの選択したい
例)「性別」カラムにあらかじめ「男」「女」をプルダウンで表示 など

②右側の一覧表示に出ている項目=フィルタ項目となっているが、フィルタを限定したい
例)「生年月日」は右の一覧には表示するが、左のフィルタには不要 など

該当のソースコード

const ss = SpreadsheetApp.getActiveSpreadsheet(); function doGet() { const htmlTemplate = HtmlService.createTemplateFromFile('index'); const title = ss.getName(); htmlTemplate.title = title; return htmlTemplate.evaluate().setTitle(title); } function getSheetData() { const sh = ss.getSheetByName("data"); const response = JSON.stringify(sh.getDataRange().getValues()); return response }
<!DOCTYPE html> <html style="overflow-y:hidden"> <head> <base target="_top"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <style> ::-webkit-scrollbar { background: transparent; height: 10px; width: 8px; } ::-webkit-scrollbar-thumb { border: none; background: #bbb; -webkit-border-radius: 8px; border-radius: 8px; min-height: 40px; } thead th { position: -webkit-sticky; position: sticky; top: -1px; background-color: #ddd; } .btn { position: fixed; width: 50px; height: 50px; color: white; border-radius: 50px; display: flex; justify-content: center; align-items: center; opacity: 0.4; box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); transition: 200ms; user-select: none; } .btn:hover { opacity: 0.9; } .btn:active { opacity: 1; } </style> </head> <body> <div id="app"> <div style="display: flex;"> <div style=" width: 300px; height: 100vh; background-color: #fafafa; padding: 0 30px; overflow: auto; "> <h1 class="title is-4" style="margin-top: 50px;"> <span class="material-icons">filter_list</span> フィルタ </h1> <template v-for="(key, index) in keys"> <div style="margin-bottom: 1em;"> <label class="label is-small">{{ key }}</label> <input v-model="conditions[index]" type="text" class="input is-small"> </div> </template> <div @click="clearConditions()" class="btn" style="bottom: 30px; left: 220px; background-color: #e85a5a;" > <span class="material-icons">clear</span> </div> </div> <div style=" max-width: calc(100% - 300px); height: 100vh; padding: 0 50px; overflow: auto; "> <h1 class="title is-4" style="margin-top: 50px;"> <span class="material-icons">description</span> <?= title ?> </h1> <table class="table is-striped is-hoverable" style="white-space: nowrap; position: relative;"> <thead> <tr> <th v-for="key in keys">{{ key }}</th> </tr> </thead> <tbody> <template v-for="record in records"> <tr v-if="checkCondition(record)"> <td v-for="item in record">{{ item }}</td> </tr> </template> </tbody> </table> <div @click="downloadCSV()" class="btn" style="bottom: 30px; right: 30px; background-color: #3a93e8;" > <span class="material-icons">file_download</span> </div> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <script> var app = new Vue({ el: '#app', data: { keys: [], records: [], conditions: [] }, mounted: function(){ google.script.run.withSuccessHandler(function(text) { const response = JSON.parse(text) app.keys = response[0]; app.records = response.slice(1); app.records.splice(); }).getSheetData(); }, methods: { checkCondition: function(record){ for (let i = 0; i < this.keys.length; i++){ if ( this.conditions[i] && !record[i].includes(this.conditions[i]) ) return false; } return true; }, clearConditions: function(){ this.conditions.splice(0); }, downloadCSV: function(){ const filename = "data.csv"; let data = '\"' + this.keys.join('\",\"') + '\"\r\n'; for (const record of this.records){ if ( this.checkCondition(record) ){ data += '\"' + record.join('\",\"') + '\"\r\n'; } } const bom = new Uint8Array([0xef, 0xbb, 0xbf]); const blob = new Blob([bom, data], { type: "text/csv" }); const url = (window.URL || window.webkitURL).createObjectURL(blob); const download = document.createElement("a"); download.href = url; download.download = filename; download.click(); (window.URL || window.webkitURL).revokeObjectURL(url); } } }) </script> </body> </html>

以上、お手数をおかけしますが、よろしくお願い申し上げます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/07/27 14:10

そもそも、このコード(修正前の、サイトのコードそのままの状態)を実際にデプロイしてみて、動作を確認されていらっしゃるでしょうか? 正しく期待する動作になっていますか?
sdgs

2022/07/27 14:16

ご質問いただきありがとうございます。 はい、実際にスプレッドシートのマスタデータを作成し、動作の正常性確認済です。 (色々試行錯誤したところ、セルが数値だと動かなく、文字列(書式なしテキスト)にしたら動くなどはありましたが、、)
guest

回答1

0

ベストアンサー

※ 質問文のコードは正しく動きません。正確に言うと、スプレッドシートからデータが表示されて一見正しく動いているように見えますが、フィルタが機能しません。
エラーの原因はここです。

if ( this.conditions[i] && !record[i].includes(this.conditions[i]) ) return false;

record は1次元の配列なので、record[i].includes とすると、includes 関数がないというエラーになり、フィルタがうまく機能しません。
ここは

if ( this.conditions[i] && record[i] !== this.conditions[i]) return false;

とします。


①右側のフィルタのフリーテキスト以外に、プルダウンでの選択したい
例)「性別」カラムにあらかじめ「男」「女」をプルダウンで表示 など

プルダウンで表示するには、select タグを使用します。
質問のコードで使われている CSS フレームワークの bulma には「select」クラスが用意されているので、これを使えばデザインを統一できそうです。
https://bulma.io/documentation/form/select/

内容によるタグの切り替えには、v-if を使ってみましょう。
https://jp.vuejs.org/v2/guide/conditional.html
たとえば「性別」のときにプルダウンにしたいのであれば、key が「性別」の時に select、それ以外の時は text にすればよいでしょう。

html

1 <div v-if="key==='性別'"> 2 <div class="select"> 3 <select v-model="conditions[index]"> 4 <option></option> 5 <option></option> 6 <option></option> 7 </select> 8 </div> 9 </div> 10 <div v-else> 11 <input v-model="conditions[index]" type="text" class="input is-small"> 12 </div>

②右側の一覧表示に出ている項目=フィルタ項目となっているが、フィルタを限定したい
例)「生年月日」は右の一覧には表示するが、左のフィルタには不要 など

単純に、左のフィルタ項目を表示するところを操作して、元データを限定すればよいでしょう。
フィルタ項目は keys という配列で管理されています。
keys 配列の中身を、HTMLで表示しているのはここの部分です

html

1 <template v-for="(key, index) in keys"> 2 <div style="margin-bottom: 1em;"> 3 <label class="label is-small">{{ key }}</label> 4 <input v-model="conditions[index]" type="text" class="input is-small"> 5 </div> 6 </template>

したがって、たとえば、非表示にしたい項目が来たときは、タグをスキップするようにすればよいでしょう。
たとえば名前フリガナを除外するのであれば、下記のようになります。

html

1 <template v-for="(key, index) in keys"> 2 <div v-if="key !== '名前フリガナ'"> 3 <div style="margin-bottom: 1em;"> 4 <label class="label is-small">{{ key }}</label> 5 <input v-model="conditions[index]" type="text" class="input is-small"> 6 </div> 7 </div> 8 </template>

①と合わせると下記のようになります。

html

1 <template v-for="(key, index) in keys"> 2 <div v-if="key!=='名前フリガナ'"> 3 <div style="margin-bottom: 1em;"> 4 <label class="label is-small">{{ key }}</label> 5 <div v-if="key==='性別'"> 6 <div class="select"> 7 <select v-model="conditions[index]"> 8 <option></option> 9 <option></option> 10 <option></option> 11 </select> 12 </div> 13 </div> 14 <div v-else> 15 <input v-model="conditions[index]" type="text" class="input is-small"> 16 </div> 17 </div> 18 </div> 19 </template>

複数の条件でselectとtextを使い分ける方法として v-else-if を使って下記のようにするやり方があります。

たとえば、「性別」に加えて、「会員タイプ」という項目をプルダウンにしたいときは、下記のようになります。

html

1 <template v-for="(key, index) in keys"> 2 <div v-if="key!=='名前フリガナ'"> 3 <div style="margin-bottom: 1em;"> 4 <label class="label is-small">{{ key }}</label> 5 <div v-if="key==='性別'"> 6 <div class="select"> 7 <select v-model="conditions[index]"> 8 <option></option> 9 <option></option> 10 <option></option> 11 </select> 12 </div> 13 </div> 14 <div v-else-if="key === '会員タイプ'"> 15 <div class="select"> 16 <select v-model="conditions[index]"> 17 <option></option> 18 <option>A</option> 19 <option>B</option> 20 <option>C</option> 21 </select> 22 </div> 23 </div> 24 <div v-else> 25 <input v-model="conditions[index]" type="text" class="input is-small"> 26 </div> 27 </div> 28 </div> 29 </template>

投稿2022/07/27 14:36

編集2022/07/29 22:34
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sdgs

2022/07/28 13:17 編集

ご丁寧に回答ありがとうございます!とても助かりました、、! いただいた内容を元に修正色々試してみた結果、理想に近く改修できました! 一部、<div v-if="key==='性別'">以外に複数のフィルタにプルダウンを反映しようとしたときに、 <div v-else> <input v-model="conditions[index]" type="text" class="input is-small"> </div> の影響で、性別以外の項目に対し、テキストとプルダウンの両方が表示されてしまう事象が発生してしまいました、、 複数のフィルタにプルダウンを反映するにはどのようにすればよろしいでしょうか?
退会済みユーザー

退会済みユーザー

2022/07/28 14:16

追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問