Google Apps Scriptは、HTML ServiceでウェブアプリケーションやスプレッドシートのダイアログのUIを構築可能です。しかし、標準ではUIを構築する為のライブラリやフレームワークを備えていないので、ユーザ自身が好きなフレームワークを導入して、HTML上に構築する必要があります。

自分は過去に、Google Apps Scriptのアプリをスマフォ向けとしては、framework7を使ってUIを構築しました。いずれ、framework7のまとめも作ってみたいと思います。今回はPC向けサイトとしてVuetifyを使って構築してみたいと思います。随時、自分がパーツを使うシーンがあれば、ここに追記していきたい。

図:現在作成中のElectronアプリでも使ってます

難易度:

目次

今回使用するライブラリ等

VuetifyはVue.jsのUIフレームワークになるので(ちょうど、jQueryとjQuery UIの関係になる)、Vue.jsも利用する必要があります。

Google Apps ScriptでVue.jsを使ってみる

事前準備

ウェブ上で公開されてる事前準備では、vueファイルの作成であったり、vue-cliを使うためにnpmでインストールといったような説明書きをよく見かけますが、そもそもjQuery同様にvue.jsやvuetifyは単独で利用出来るようになっているので、あの手順にしたがってプロジェクトを作る必要性はありません。また、Google Apps Scriptでは当然vueファイルやらnpmでインストールなんてできません

Google Apps ScriptではいくつかのCDNで公開されてるライブラリをロードすることで、コード内で利用できるようになります。こちらのページUsage with CDNがそれに該当します。

Headerタグ内でCSSをロード

  • Header部分ではCSSを読み込みます。
  • 他にもGoogle FontsやViewportの設定も指定が必要になります。

Bodyタグ内の一番下でJSをロード

  • Vue.jsやVuetify.jsといったライブラリのJSファイルは、Header内で読み込ませても、エラーになります
  • Bodyの一番最後で読み込ませ、また初期化の為のスクリプトも同じ場所で記述する必要があります。
  • new Vue内にて初期化する際に、vuetifyを指定し、そこでnew Vuetifyを呼び出すことで、Vuetifyを初期化しています

viewportの指定

今回はPC向けということなのですが、モバイル向けとしてviewportの指定が必要な場合があります。しかし、通常通りHTML内に記述しても、Google Apps Scriptの場合それらのタグは無視されてしまいます。これらは、HTML Serviceの引数として、addMetaTagでの指定が必要です。faviconなども同様です。

※faviconを指定するとウェブアプリのアイコンが指定のアイコンになります(サンプル

色々なコントロールを使ってみる

Vuetifyのサイトには様々なUIコントロールのサンプルが掲載されています。しかし、これらのコードをそのままGoogle Apps ScriptのHTML Serviceで動かそうとした場合、動かないケースがままあります。今回はいくつかのコントロールをテストしてみて、実際にこれなら動くという形で、ちょっとだけ変えてあります。

非常に沢山のコントロールと、それぞれにオプションやテクニック、APIが用意されているので、表現力豊かなアプリケーションが構築可能です。

以下のコードはHeaderやBody下部の共通部分については省略しています。

selectbox

UIパーツの中でももっとも基本的なパーツがv-selectタグを使ったコンボボックス or ドロップダウンリストです。このリストは表示する値とは別に反映する値を別に設定出来ますし、複数列を持つJSONの値をセットして運用することもできるのですが、Vuetifyのバージョンによるものなのか、不可解な動きをすることもあるので注意です。

ソースコード

HTML側コード

  • v-modelで入力先の変数を指定しています(今回は取得レコードのfuninsakiという値に入れています)
  • 選択時にv-on:changeにてfuninchg関数を実行するようにしています。後述のJSONの他の値を自動的に別のv-text-fieldに入れるようにしています。
  • 表示するのはJSON値のfunin列を指定するために、item-textにfuninを指定しています。
  • 格納する値はJSON値のID列を指定する為に、item-valueにIDを指定しています。
  • 上記のtextとvalueの指定がない場合、JSONのtextとvalueの項目がデフォルトで選択されるようになっています。
  • :itemsのkaigaiがJSONデータを格納してる先。Vue初期化時のdataの中に予めkaigaiと次項のJSONを格納しておく必要があります。
今回割当てたメニュー用JSON

非常に単純な、ID列とfunin列の2つのカラムで構成されています。funinchg関数では、セレクトされるとfunin列の値を別のtext fieldに入れるようにしています。

JS側コード

  • vueのmethodsにfuninchg関数を用意。
  • eでは選択した項目のJSON値が全部入ってるので、ここからfuninの値を取り出します。
  • 取り出した値は直接選択レコードのJSONに格納すれば、v-modelで連結してるv-text-fieldに表示されます。
  • この手法は、HTML側でreturn-objectを指定しておく必要があります(そうでないと、選択した項目のJSON値が取得できない)

注意点

Vuetifyのv2で遭遇したのですが、このreturn-objectを指定してる場合、またそのv-selectが既存の変数にv-modelで連結してるケースで、item-valueやitem-textで列指定しているにも関わらず、v-selectのv-modelで連結してる項目にitem-valueの値ではなく、選択した項目のJSON値が[object,object]として入ってきてしまうケースがありました。

return-objectを外せばこのような問題は起きない反面、funinchg関数で選択したJSON値を取得できなくなってしまい、連動して他のtext-fieldに値を入れ込むことができなくなりました。なぜこのような事象が発生したのかは不明ですが、連動をさせないケースではreturn-objectは外しておきましょう。この問題は解決策が無いので、変数名変えたりv-modelでselectには連結しないで非連結とし、2つのtext-fieldに入れるようにするなどの迂回策が必要です。

Appbar

アプリケーションの顔とも言える、アプリ上部にあるヘッダに該当するナビゲーションバーです。この他にもファイルやヘルプなどのツールバーなどもあったりします(もちろん、モバイル向けの下部ナビゲーションも)。ただし、サンプルのままで動作しようとすると、このナビゲーションバーにコンテンツ部分が被ったりと色々と面倒な部分もありましたが、以下のコードで動作させることが可能です。

ソースコード

  • v-app-barにおいて、absoluteの指定があると下のコンテンツ部分に被ってしまうので省略
  • shrink-on-scrollの指定がある場合、スクロールするとバーが自動的に半分くらいのサイズにミニマムになる
  • scroll-targetの指定がある場合、スクロールするエリアは指定したID(今回だとmain_content を持つv-sheet)が対象
  • v-btnがナビゲーションのボタンの部分を担当する
  • v-app-bar-nav-iconは左サイドのハンバーガーメニューです

サンプル表示

Bottom Sheet

スマフォなどではおなじみのボタンをクリックすると、下からメッセージがせり上がってくるアレです。アプリで使うシーンとなると、普通のalertの代わりという、承認時のメッセージであったりといったダイアログよりも目立たせたいのが、使うポイントになるかと思います。

ソースコード

JS側コード

  • dataの中のsheetをフラグとし、falseで閉じます
  • 承認と却下用のコマンドをmethodsに加えて起きます。
HTML側コード

  • ボトムを開くをクリックすると、ボトムシートが開かれます
  • 承認、却下はそれぞれがmethodsに規定したコマンドを@Clickにて実行し、this.sheet=falseで閉じるようになっています。

サンプル表示

Dialog

アプリケーションで非常によく使う要素の1つがダイアログでしょう。jQueryなどを使わずにオシャレなダイアログを構築する事が可能です。その表現の数も非常に充実しており、よくあるYES/NO、フルサイズの設定用ダイアログ、ダイアログのネスト、プログレス表示用などなど、ユーザの要求を適切に受け取ることが可能です。

ソースコード

JS側コード

  • コード自体はBottom Sheetとほとんど同じものになります。
  • dataの中のdialogをフラグにして、falseの時に閉じます。
HTML側コード 

  • 承認実行ボタンを押すとダイアログが表示されます。
  • ダイアログの2つのボタンにそれぞれ@Clickで実行するmethodを指定しておきます。

サンプル表示

注意点

ElectronでVuetifyを使い、ダイアログを使っていた際に遭遇したトラブルなのですが、保存ボタンを押しthis.dialog = falseをした後に、confirmにて選択のメッセージを出した場合以下のトラブルが生じました。

  • 保存は実行され、再度ダイアログも開けるが、テキストボックスをクリックしてもフォーカスされず、入力ができなくなる
  • ただし、カレンダーやセレクトボックスは正常に動作する
  • 一度デスクトップをクリックして、再度Windowをクリックするとフォーカスして入力ができるようになる
  • しかし、一時的に治ってるだけで、再度Dialogを閉じると同様の症状が発生する

回避策としては、Electronであるならば、メインプロセス側でdialog.messageにて表示して分岐処理をさせるようにする。Google Apps Scriptの場合は、confirmを使わず別の確認メッセージを表示する手段を利用するようにしましょう。

Carousel

ブログパーツであったり、スマフォのアプリであったり、最近は様々なシーンで使われるようになったUIコントロールが「カルーセルスライダー」。主に写真であったり、プレゼンのスライドのようなものであったりに使われていますが、いざ自前で実装すると、結構大変です。このカルーセルをVuetifyは簡単に実装できるだけでなく、配列に値をpushするだけで自動で追加項目が反映するVue.jsのBindの特性が活かせるコントロールでもあります。

ソースコード

JS側コード

  • calitemという配列を格納してる変数に、連想配列でsrcを指定したデータを格納しておく
  • Vue.jsにてdataのitemsにcalitemを指定するとカルーセルスライダー用のデータとして利用される
  • addPictureメソッドにて、この配列に新たな画像データを動的に1個追加する
HTML側コード

  • v-carouselにて、itemsの中身をv-forでループ、バインドされたデータをカルーセルで表示するようになっています。
  • 画像が追加されると自動的にVue.jsにてそれらは動的に取り込まれすぐ反映してくれる。jQueryのようにリロードといったコードは不要となる。
  • サンプルでは、クリックすると、一番最後にハイビスカスの画像がカルーセルに追加されます。

サンプル表示

Navigation drawers

いわゆる、サイドバーのこと。例えば、ハンバーガーメニューをクリックすると左側から選択用のメニューが出てくるようなアレです。現代のアプリケーションを構築し、ナビゲーションをするには必須の項目ですね。MenusListsTreeViewを組み合わせてれば、リッチなUIを実現出来ます。

ソースコード

JS側

  • Drawerの開閉フラグは変数drawerが担当しています。
  • サイドバーの中身用のリストは、itemsの値から生成しています。
  • リストをクリックしたら発火する関数として、onListChangeを定義していて、そのタグ内のIDの値をalertで表示
  • onListChangeで引数で受けるIDはitemsで生成時にv-bindで動的に割り当てたものを利用しています。
HTML側

  • v-navigation-drawerにbottomを指定すると、サイドバーではなくアンダーバーになります。
  • v-list-itemではv-forにてitemsから値を取得し、v-list-itemを生成しています。
  • v-on:clickにてリストアイテムクリック時にonListChangeを実行しています。引数に$eventを指定すると、他の属性値(例えばidなど)を関数側で取得できます。
  • v-bindにて、itemsのargsをIDとして割り当ててます。
  • itemsのiconはMaterial iconの文字列を指定、textはリストのタイトル。それぞれをVue.jsで割当

サンプル表示

Autocomplete

少ない選択肢ならば、コンボボックスなどのv-selectを使って表現をすれば良いのですが、非常に多くの選択肢がある場合には選択肢が逆に利便性を損ねてしまいます。そこで利用するのが、オートコンプリート。ユーザの入力ワードでGoogleのサジェストのように機能するものです。

しかし、公式サイトにあるサンプルコードだと、単純な一次元配列の選択肢を表示するだけで、業務の現場で必要とされる

  • 選択肢の項目に複数の関連情報を表示する(社員番号と社員名など)
  • 選択したら、そのデータの塊を取得して、他の入力項目に流し込みたい(選択したレコードの取得)
  • 選択肢データはMySQLやSQLiteに格納済みデータをそのまま利用したい(JSONデータで選択肢にそのまま利用する)
  • 検索時は社員IDのみだけでなく、全レコードの列項目も検索対象にしたい。

といったものが満たせません。これらの要求を満たすようにAutoCompleteを実装してみたいと思います。1000以上ある選択肢でもユーザが絞り込んで選択できるスグレモノです。

ソースコード

HTML側コード

  • AutocompleteのChangeイベントにはseleresult関数を指定。引数には$eventを指定してあると選択したJSONレコードがまるまる取得出来ます。
  • 選択肢の項目はitemsという変数を指定しています(初期値は空っぽです)
  • slotのselectionには、選択したレコードのうち、今回はIDの値を残すようにしています。
  • slotのscopeには、絞り込み結果を表示するテンプレートを割り当ててます。v-cardで括らないと選択できないリストになってしまうので、注意。
  • 今回は検索結果には、社員番号と社員名、会社名の3項目を1つのCardとして表示するようにしてます。
  • $eventで取得したJSONデータの塊はそのまま、変数selerecに流し込みます。
  • autocomplete以外のテキストボックスなどは、selerecのJSONにv-modalで連結しておきます。selerecにデータが入ってきた時点で自動的にテキストボックスに値が反映します。
JS側コード

  • loading変数がAutocompleteの表示フラグを担当する変数です。
  • common変数はJSON形式での社員マスタの全データが入ってくる検索先の塊になります。
  • items変数がautocompleteと連結してるフィルタしたデータを格納する先になります。
  • watchにて文字が入力されたことを感知し、searchメソッドを実行します。
  • searchメソッドでは、querySelectionsメソッドに入力値を投げ入れます。
  • querySelectionsメソッドでは、変数commonの値に対してフィルタを掛けます。eにはcommonの1レコードが入ってきてループのように処理が連続で行われます
  • eの値をJSON.stringifyで加工する事で、indexOfをしたときにレコードの全列を検索対象にする事が出来ます。
  • indexOfで検索値が存在した場合には、0以上の値が返ってくるので、それをもってtrueとすると、そのレコードは選択肢に表示されます。
  • 選択後にloadingをfalseにすることで、選択肢を非表示にしています。
  • seleresultメソッドでは選択後に、選択した対象のレコードのJSONをまるごとselerecに入れています。こうすることで、他のテキストボックスなどに自動的に値が反映されます。

図:こんな感じで選択肢の表示をフルカスタマイズ出来る

Table

jQuery系で自分がよく使ってるものに、「jQuery DataTables」という非常に優れたプラグインがあるのですが、これをVuetifyのTableコンポーネントで実現する事が可能です。また、Vue.jsであるので、データの入れ替え等にまつわる動作がとっても楽ちんで、jQueryのように更新だのなんだので独特のコードを書かずとも変数入れ替えるだけでOKなので、とっても便利です。

ソースコード

JS側コード

  • headersでは、列名やソートの有無、フィルタ可能かどうかを追加できます。filterableでfalseを指定した列は、検索対象外になります。また、valueは連結するデータ(今回で言えば、dessertsがそれになる)のどの値を繋げるかを指定します。
  • 初期化後にvm.dessertsに対して、JSON形式のデータを投げ込めば、値の入れ替えや追加が可能です。
HTML側コード

  • Table本体は、v-data-tableのタグの部分のみ。そこへ検索用のテキストフィールドを追加しているだけです。
  • 標準だと日本語化されていない場所(items-per-page-textなどの部分)は、footer-propsの中で定義して置き換えることが可能です。Rows Per Pageを1ページ毎のレコード数に今回置き換えています。
  • 移動用のアイコンも同様に標準のものから、マテリアルアイコンを指定して置き換える事が可能です。
  • マルチソート、グルーピング、行選択などなど、幅広いオプションが用意されているので、気にいる形式に仕立て上げる事が可能です。社員マスタなどのマスタ系を弄るのに向いていると思います。

図:ダミーデータを10件ずつ表示してみた

Validation

フォームの入力内容がきちんとボックスの内容に適合してるものなのかチェックする為の機能がvalidation。例えば数値しか受け付けたくない場所に文字や、メールアドレス欄なのにRFCの規則に従っていないメアドとか、半角全角、入力必須などがValidationの対象です。この機能を使わないとなると、サーバに送信時などで全部の入力欄について自分で一個ずつJavaScriptで検査してNGなら止めるみたいなコードを書かなければなりません

少数ならそれでも良いのですが、業務用アプリケーションのように入力欄の多い場合、非常にメンテナンス性が落ちます。これを簡単にしてくれるのがValidation機能です。Vuetify標準で搭載されてるものの他に、Vue.jsのプラグインとして、VeeValidateVueValidateといったValidation専用のプラグインもリリースされています。

ソースコード

HTML側コード

  • 保存ボタンにはsaverecord()を呼び出すように割り当てて起きます。(保存時に一括Validationチェックもやらせる為)
  • 各入力欄のv-text-field等やv-select等には、:rules=[rules.required]などを割り当てます。これがValidationチェックの項目で、JS側で定義しておく必要があります。複数割り当てる場合は、配列内でカンマ区切りで、[rules.required, rules.numchk]といた具合に割り当てることが可能
  • rulesが定義されていない入力欄はValidationの対象外になります。
  • 全入力欄は必ずv-formでくくりref=”formman”のように名前をつける事が必要です
JS側コード

  • vuetifyの初期化のdataの中にrulesは定義します
  • rulesの中に複数タイプのValidationルールを定義し、HTML側はrules.numchkといった形で呼び出します。
  • required: value => { ここに処理 }といった形で構文を定義し、valueに対してチェックを掛けます。最後にreturnで返すのですが、trueもしくはfalseのどちらかの値を返すようにします(falseでValidationはNGとなる)
  • Validationはほとんどの場合で正規表現を使って検証します。
  • 業務用だと必須項目、メアド、日付の形式、カタカナ、ローマ字、数値で概ねValidationのチェックは可能(数値の場合は文字数カウントなんてのもありますね)
  • 保存ボタンに割り当てたsaverecord()はmethodsに定義する。Validationは入力中でも働くのですが、送信時に一括でチェックも可能
  • this.$refs.formman.validateにて一括チェックします。formmanがformに割り当てた名前になります。
  • validateのチェック結果、全部が適合してると判断されるとtrueが帰ってくるので、これをもとにGAS側へデータを送って書き込ませるようにします。

図:入力欄チェックはデータの整合性を保つのに必要

組み合わせの妙技

テキストボックスとカレンダー連動+α

非常に便利でリッチなUIを提供してくれるVuetifyですが、公式ドキュメントだけでは実務では困るケースが結構あります。特に今回社内向けアプリを作ってて困ったのが、テキストボックスとカレンダーの連携。困った点は以下の通り

  • テキストボックスクリックでカレンダー表示だと手修正時に面倒(ボタンを別途用意する必要性)
  • カレンダーを要するものが1個ならばVue.js内に用意した変数と連動で良いが、たくさんある場合にはこの手は非常に面倒(カレンダーの数だけ用意が必要)
  • Vuetifyのカレンダーは、yyyy-mm-ddの形式でなければならないが、テキストボックス内に表示されるのはyyyy/mm/dd(このまま渡すとエラーになる)
  • 値を読み書きする対象は、単一の値ではなくJSONの塊であるため、ロジックが必要(テキストボックスへの連結はv-modelで連結で良いのだが・・・)

これらを解消するにはちょっと複雑な仕組みが必要です。

ソースコード

HTML側コード

  • 入社日付テキストボックスとはv-modelにてJSONデータであるselerecのjsondateに連結
  • テキストボックス、ボタン、カレンダーであるv-date-pickerはv-menuで囲っておく(これ全体が一つの塊になる)
  • ボタンクリック時には、カレンダーを呼び出すonBindName関数をイベントとして割り当てておく(v-on=’on’も必要です)
  • v-date-pickerはv-modelにてpickerという後述のComputedのget, setの変数を割り当てておく(これが日付データの受け渡しを担当)
  • v-date-pickerはlocale=”ja-jp”で日本語化。しかし、日がくっついてくるので、:day-format=”date => new Date(date).getDate()”にて、綺麗にフォーマットする
  • CSSにてカレンダーの土日の文字色は変更可能です。
  • onBindName関数の引数には対象となるJSONのkey名を入れておき、読み書き対象の場所を特定できるように指定しておく。
JS側コード

  • グローバル変数binderにはonBindNameが取得した引数を格納。読み書き先のJSONのkey名を格納しておく(これにより、たくさんのカレンダー用の変数を用意する必要がなくなる)
  • onBindNameにエラートラップをしてる理由は、値が空である場合にエラーとなるので、これを回避する為。
  • onBindName関数にて、特定のJSONの日付データを取得。ただし、replaceを使って正規表現にて「スラッシュ」を「ハイフン」に変更して、dateに格納しておく
  • v-onにてカレンダーが開かれると、v-date-pickerが表示される。すると、v-modelで連結してるcomputedのPickerにあるgetが発火。dateに格納されてる日付データを取得し、カレンダーに反映する
  • カレンダー側で日付を選択すると、computedのpickerにあるsetが発火。日付データはvalに入ってるので、これを今度は「ハイフン」を「スラッシュ」に変更して、dateおよびJSONの対象のkeyの値に直接格納する
  • カレンダー外をクリックすると、カレンダーは自動的に閉じる。カレンダーの表示非表示用の変数もこれで省略しているので、たくさんの変数を用意する必要がない

ちなみに、selerecには、1レコード分の様々なデータがkeyと値のペアでたくさん格納されている。

図:この手は非常によく使うテクニック

タブとツールバーの連携技

自分のアプリでは、レコードをクリックすると、その詳細な内容を編集するダイアログを表示させ、その中ではジャンル毎に「タブ」でわけています。このタブをツールバーの中に配置しており、保存ボタンを別途用意しており、編集後に保存ボタンを押すことで、MySQL側へとデータを投げる仕組みになっています。

タブをクリックする事でジャンル毎の中身を切り替えて表示するのですが、各コンテンツ内容がダイアログの大きさよりも大きい場合、スクロールバーが表示されますが、ツールバーまでスクロールしてしまい、具合が悪いです。コンテンツ部分だけをスクロール出来るように細工が必要です。

ソースコード

ツールバーを固定化する為のCSS

HTML側コード

  • v-toolbarの中v-tabsや各種ボタンを配置する
  • v-tab-sliderにてタブ下部のスライダーの色を指定する事が可能です。
  • 各タブのhrefには下部のコンテンツ部分のv-tab-itemの各valueの項目に切り替わる仕組みです。
  • v-toolbarにはCSSで固定化するためにclass=”fixed-bar”を指定しています。
  • <v-app-bar app dense fixed>をtoolbarにくくり、コンテンツ部分をv-contentでくくることで、似たようがことが実現はできますが、レイアウトが崩れたりするので、自分はCSSでの調整を利用しています。こちらのほうがスッキリ決まります。

図:標準のタグよりもCSS調整のほうが綺麗に決まることもある

Vue.jsのプラグイン

v-tootip

Vueitfyにもtooltipの項目があるのですが、ややこしい上に動かないケースがあったりで困っていたのですが、v-tooltipというプラグインを利用することで簡単に実装できました。ツールチップの場所や細かい挙動などオプションもあったりして、地味な機能ながらアプリを華やかに演出してくれます。

ソースコード

HTML側コード

  • CSSはツールチップのデザインを担当しています
  • ツールチップを表示したい項目にv-tooltip.bottom=でコメントを入れればOK。bottomの他にもtopとすれば上部に表示されます。今回のケースではアイコンの下に表示がなされます。
JS側コード

  • CDNでライブラリは提供されているので、vuetifyやvue.jsのJSファイルとともに追加すればOK
  • 追加したら、Vue.use(VTooltip)を実行すればそのHTML内でツールチップが有効になります。

図:アイコンにマウスカーソルで表示されます

Cheetah Grid

業務用アプリケーションを構築する上で、特にPC向けで構築する場合にほぼ必須になるコンポーネントが「Grid」。VuetifyにもGridはあるのですが、欲しいのはこういうものじゃない・・・これまでは、w2ui-gridSlickGridなどを使ってましたが、前者は以前は高速だったのですが、現在は重く切り替えも非常にもたつく、後者は高速なのですが既にメンテされていないし、構築が結構面倒。

ということで見つけたのが、Cheetah Grid。Vuetifyじゃなく、Vue.jsのプラグインとして実装されているものになりますが、マテリアルデザインで表現されます。

列の固定やマルチプルカラム(複数列にまたがるカラムタイトルを作れる)などが可能で、非常に高速に表示が出来るというので、手を出してみました。デモページはこちらになります。Vue.jsとの相性も良いみたいです。表示する為のGridのデータの仕様はこちらになります。Vue.jsで使う場合のドキュメントはこちら

ソースコード

Vue.jsの拡張プラグインとして、CDN配布されているので、vue.jsの読み込み後に以下のコードで追加で読み込むようにします。

GAS側コード

  • スプレッドシートのデータをタイトル列をkeyに、連想配列データにして返す関数です
  • このデータをCheetah Gridのrecordsにそのまま、当て込みます
JS側コード

  • Vue.useで今回の拡張プラグインを読み込まないとエラーになります
  • google.script.run.withSuccessHandlerにてGAS側からデータを受け取る
  • 受け取ったデータを元にnew Vueでrecordsに当て込みます。
  • 今回はボタンをクリックするとレコード内容をalertで表示するメソッドを追加
HTML側コード

  • frozen-col-countにて固定する列の列数を指定します。2で初めの2列を固定化
  • データと連結するにはfieldプロパティを使ってrecordsのkeyと一致させる。personidならrecordsデータのpersonidのkeyの値がここに入ってきます。
  • 2段表示のタイトル列を作る場合は、c-grid-column-groupにて1段目を定義し、その中に2段目を個別に定義する形になります。
  • onClickRecordにて定義した関数が呼び出されますが、特に引数を指定せずともrecにレコードの全ての値が入ってくるので、これを元にデータを加工します。
Grid用データ

  • カラム名:値という形でのシンプルな連想配列になっています。
  • データ入れ替えを考えるならば、これをJSファイルとして切り出し、動的に入れ替えるようにすれば、あとはVue.jsが良しなにやってくれます。

サンプル表示

サンプル用データは疑似個人情報生成サービスを利用しています

こういうプラグインが豊富にあるのも、Vue.jsの良いところ

ソートできるようにする

Cheetah Gridはちょっとドキュメントが十分に整備されてるとは言えない部分がありますが(Googleもいい加減なドキュメントの部分があったりするのでアレですが)、Vue.jsでソートを利用できるようにするには、以下のように加工するだけでOKです。

HTML側コード

  • c-grid-columnにsort=”true”を追加するだけです。追加したカラムだけクリックで昇順・降順が有効になります
ソート用矢印の色を変更する

ソート用の色は、Theme機能に以下のコードを追加するだけです。

  • vueの初期化のdataの中のuserThemeにて、headerセクションを追加する
  • headerセクション内にsortArrowColorを定義して、16進数もしくはredなどのカラーコードを指定する

図:ソート状態がわかりやすくなりました

特定の列の値に応じてレコードの背景色を変更する

現場でこの手のGridを使ったケースでよく遭遇するのが、「特定の列の値がTrueの場合には、背景色を変更する」といったような事例。自分が現在手掛けてるアプリケーションで言えば、終了済みタスクのフラグが立ってるレコードは背景色を変更し、それが一目で終わってるタスクとわかるようにしてるといった事例です。

この実装をするには、ちょっと複雑な装備をする必要があります。

HTML側コード

  • こちらは、c-gridタグに対して、:theme=”userTheme”を加えておくだけ
  • 今回はタイトル列を2行固定させています。JS側ではこの2行が重要になります。
JS側コード(index.html)

vueを初期化するコードに、Cheetah GridのuserThemeに関するオプションを、dataの中に記述する必要があります。

  • recdataにはGAS側から取得したレコードデータの塊が入っています。ページ表示時に取得してrecordsに入れています。
  • グローバル変数でmaterialDesignThemeに対して、Cheetahgridのthemeを読み込みます。
  • userThemeをdataオプションの中に記述しますが、materialDesignTheme.extendsを利用します。
  • defaltBgColorの関数をこの中に記述します。Cheetah Gridフォーマット時にこれらが自動で読み込まれ、rowは1行ずつ順番にdefaltBgColorが処理していきます。
  • 冒頭2行は固定行なので、処理対象外とします。
  • rowは行番号なのですが、検索する対象であるrecdataは0番目から精査する必要があるため、-2で0からスタートするようにしています。これを行わないと、実際のデータ数と表示するrowの数が一致しなくなり、エラーとなります。
  • recdata[rowの番号].endflgで、recdataの◯番目のendflgの値を引き出せます。この値が-1のものが今回の色を変更する基準となります
  • returnで直接HTML Colorの16進数の値を返せばendflgが-1の値のレコードの背景色だけが変更されます。
  • それ以外のケースでは、何もせずにreturnを返します。

図:endflgが-1のレコードだけ背景色が薄紫になった

検索機能をつける

Vue.jsでCheetah Gridを利用する際に、検索機能がやはり欲しくなります。しかし、APIらしきものが見当たらなかったのですが、よくよく考えればデータの変数と連結してるので、変数内のデータをフィルタして再度変数に格納すれば、それだけで検索絞り込みは実装出来ます。

検索窓ダイアログ用のHTML

  • 検索窓のテキストボックスは、v-modelにてsearch変数にバインドしておく
  • 検索ボタンはonSearchman関数を実行する仕組みになっています
検索窓用ダイアログの初期化

関連リンク

共有してみる: