LoginSignup
2
0

More than 3 years have passed since last update.

スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版 その2~~

Last updated at Posted at 2020-05-19

スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版 その1~~からの続きです。

ハマったところはこちら↓
スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版、ハマったところinputの再描画編~~

スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版、ハマったところcheckboxの再描画編~~

前回は初期表示まででした。
今回は一覧表示されたデータから詳細データをモーダルで表示し更新させます。
以下のように一覧の右にある「詳細表示」ボタンをクリックするところからです。

image.png

クリックされるとこんな感じで詳細画面を表示します。

image.png

この「詳細ボタン」はクリックしたときに「v-on:click」で「ref_item( idx )」が呼び出されます。
「idx」はfor文のインデックスです。

vue_index.html
<td><button v-on:click="ref_item( idx )" class='btn-radius-blue'>詳細表示</button></td>

「ref_item」の説明の前に、詳細画面がモーダルで表示されるので、そのお話を少し。
モーダルで表示する箇所の冒頭を以下に記します。

vue_index.html
    <div id="modal" v-show="showContent" class="overlay">
    <div id="modal_content" v-if="dispDetails" class="content">

divタグを2つ用意しました。そして1つ目には「v-show」を、2つ目には「v-if」を設定しています。
「v-show」は表示するかしないかの設定です。設定されたプロパティがtrueなら表示するし、falseなら表示しない。となります。
「v-if」は、設定されたプロパティがtrueなら内側のタグの処理をします。falseなら処理しない、ふっとばすことになります。
モーダル表示自体は1つ目のタグのclassで指定しています。
なんでそうなるはわかっていませんが、以下のようにCSSを設定しています。

css.html
/* #overlay{ */
.overlay{
  /* 要素を重ねた時の順番 */
  z-index:1;

  /* 画面全体を覆う設定 */
  position:fixed;
  top:0;
  left:0;
  width:100%;
  height:100%;
  background-color:rgba(0,0,0,0.5);

  /* 画面の中央に要素を表示させる設定 */
  display: flex;
  align-items: center;
  justify-content: center;

}

「ref_item」の話に戻りまして、vue_index.htmlの中で以下のように記載されています。
はじめに上記のプロパティ2つをtrueにしています。
こうすることで「v-show」で表示するようになり、
「v-if」は内側のタグを表示するようになります。
(※閉じる処理の時は2つともfalseにしています。)
ここで「v-show」だけでもいいんじゃないの?と思われるかもしれませんが、試行錯誤の結果、「v-if」も記載し、明示的に「v-if」のtrue、falseを切り替えることで「v-if」を記載したよりも内側のタグの表示が正しく表示されるようになりました。詳しくはハマったところを見てやってください。

vue_js.html
// モーダル画面を表示し、データ取得(上記メソッドの呼び出し、引数になる)
ref_item: function(_idx){
      this.dispDetails = true;
      this.showContent = true;
      // マスターデータ取得
      google.script.run.withSuccessHandler(this.initOption)
                       .withFailureHandler(function(arg){
                           alert("リスト項目名の取得に失敗しました。");
                      }).getItemMasterData();
      // 詳細データ取得
      google.script.run.withSuccessHandler(this.refData)
                       .withFailureHandler(function(arg){
                           alert("データの取得に失敗しました。");
                      }).getItemNameAndData(-1, this.listitems[_idx][0], -1);
                  },

もう少し↑の説明を。
ここでもやはり「コード.gs」のfunctionを実行するにあたり「google.script.run」を使用しています。
取得に失敗したら、「.withFailureHandler」に入りアラートで「失敗しました」の旨が表示されます。
成功したら、「.withSuccessHandler」に入り、パラメータ指定されたメソッドが呼び出されます。
「メソッドが呼び出される」のであって、ここには戻り値は書かれていません。
それぞれ「initOption」「refData」メソッドが呼び出され、それぞれのパラメータに「コード.gs」のfunction「getItemMasterData」や「getItemNameAndData」の戻り値が入ります。
そのメソッドは下記になります。
そして、メソッド内で各パラメータに設定しています。

vue_js.html
    methods:{
        // データプロパティ  ↓ここに戻り値がくる
        initData: function(ary){ 
                        this.listitems = ary; 
                  },
        // 詳細データの更新 ↓ここに戻り値がくる
        refData:  function(ary){ 
                        this.refitem = [];
                        this.refitem = ary;
                        this.refitem.push('dummy');
                        this.refitem.pop();
                        //データ更新
                        vue_example.$forceUpdate();
                        this.$nextTick();
                        Vue.nextTick();
                  },

「refData」では、再描画がうまくいかなかったときのナゴリがありますw
配列データは、pushやpopを使わないとVueが気付いてくれないというので"dummy"を入れて削除しました。
forceUpdate()やnextTick()で強制的に更新をかけることもしました。
きっと、そういうこともあるのではないかと残しておきます。
これでようやくマスターデータと詳細データの取得ができたので表示に取り掛かりましょう

こちら↓になります。

vue_index.html
    <table class="modal_table">
      <tr v-for="(refits,edit_Number) in refitem">
        <th>{{ refits[0] }}</th>
        <td v-if="refits[2] == 'read'">{{ refits[4] }}</td>
        <td v-if="refits[2] == 'text'"><input :id="refits[1]" :name="refits[1]" type=text v-model="refits[4]" size=”refits[3]” maxlength=”refits[3]” /></td>

リスト表示では1データを1行で左から右に表示してました。
詳細画面では、1データは上から下に表示するようになりますので、配列の並び(データの持ち方)は、リスト表示の時とは、タテ、ヨコを入れ替えた形で保持させています。
(※コツというほどでもないですが、その方がtableのfor文で回す時 楽なので。)

「refitem」を回して、取得した「refits」も配列になっています。
「refits」の要素番号2がどのような表示をさせたいのかを保持しています。
そしてそれを「v-if」で場合分けしていきます。
今はとりあえず、「read」と「text」を見ていきましょう。
「read」と「text」の設定はデータシートの3行目のものになります。

「read」は読ませるだけなので、特にタグもなく表示しています。

「text」はinputタグを使用し、
「:id」で「refits[1]」を、これはデータシートの2行目で設定している値になります。
「:name」でも同様です。 「:」はバインドの省略形になります。
typeはtextですね。ここには「:」はありません。
「v-model」として「refits[4]」を指定します。これによりデータが画面に表示されます。
「size」、「maxlength」共に「refits[3]」を指定しています。これはデータシートの4行目の値ですね。

次はtextarea です。
設定はほぼ変わりませんが、「rows」「cols」の設定として、やはりデータシートの4行目の値を持ってくるのですが、設定値を「5,30」としています。5行30文字の設定を表しています。
「コード.gs」に「getSplit」関数を用意し、指定した要素番号の数値を返すようにしています。
こんな風に関数を呼べるんですね。

vue_index.html
        <td v-if="refits[2] == 'textarea'">
            <textarea :id="refits[1]" v-model="refits[4]" rows=getSplit(refits[5],0) cols=getSplit(refits[5],1) placeholder="入力して下さい">
            </textarea>
        </td>

続きましてselectです。
selectやradio,checkboxは選んでもらう項目が必要ですので、マスターデータシートに記載します。
データシートの4行目は、この3タイプに限りマスターデータシート列番号を記載します。
このような形でデータとマスターデータをリンク付けしてみました。
selectタグは変わりありませんが、
optionタグをマスターデータが入っている「initOptions」で回します。
この時、マスターデータのデータは連想配列になっていることに注意してくださいね。
「initOptions」で回して「items」となったデータを「v-bind:value」で「items.item」を指定しています。

vue_index.html
        <td v-if="refits[2] == 'select'">
            <select :id="refits[1]" :name="refits[1]" v-model="refits[4]" >
                <option v-for="(items,idx) in initOptions[refits[3]-1]" v-bind:value="items.item">{{ items.item }}</option>
            </select>
        </td>

もう少しです。がんばりましょう。
radioです。
「v-for」をdivタグ内で記述していますがtemplateタグでもいいかと思います。
見栄えの関係でdivを選びました。
今までと異なる点は「:key」です。「items.id」を指定しています。「id」です。
また、初期表示で入っているデータにはチェックをつけたいので「:checked」で「refits[4] == items.item」を入れて判定させています。マスターデータと詳細データが合致していればtrueとなりチェックが入ります。
「v-model」を指定すると、「v-bind:value」にも設定されるそうなのですが、
「v-model」は「refits[4]」
「v-bind:value」は「items.item」と異なるプロパティを設定することにより
期待する動きを得ています。

vue_index.html
        <td v-if="refits[2] == 'radio'">
            <div v-for="(items,idx) in initOptions[refits[3]-1]" >
                <input :id="refits[1]" 
                       :name="refits[1]"                                        
                       :key="items.id" 
                       type=radio 
                       v-model="refits[4]"
                       v-bind:value="items.item"
                       :checked="refits[4] == items.item"
                       />{{ items.item }}<br>
                       <!-- 初期のチェックがないらないので、v-modelとv-bind:valueを併記する -->
            </div>
        </td>

次のcheckboxで詳細表示はいったん終わります。ガンバ!
radioボタンとあまり変わりはありません。異なる点は
その1:データは配列で持つこと。
    そうしないとデータが取れずに、true、falseでしか更新できなくなってしまいます。
その2:radioボタンと違って、複数の項目にチェックができますので、
    「:checked」を「refits[4].indexOf(items.item) > -1」で判定しています。

vue_index.html
        <td v-if="refits[2] == 'checkbox'">
          <div v-for="(items,idx) in initOptions[refits[3]-1]">
                <input :id="refits[1]" 
                       :name="refits[1]" 
                       :key="items.id" 
                       type=checkbox
                       v-model="refits[4]"
                       v-bind:value="items.item"
                       :checked="refits[4].indexOf(items.item) > -1" />{{ items.item }}<br>
                       <!-- 初期のチェックがないらないので、v-modelとv-bind:valueを併記する -->
          </div>
        </td>

後は、更新ボタンと閉じるボタンだけですね。
更新はまた次回にします。
閉じるボタンは、「v-on:click」で「closeModal」が呼ばれてプロパティがfalseに設定され、モーダルが閉じます。

vue_index.html
        <td><button v-on:click="upd_item" class='btn-radius-orange'> 更新 </button>&nbsp;&nbsp;&nbsp;
            <button v-on:click="closeModal" class='btn-radius-blue'>閉じる</button></td>
      </tr>
    </table>

    </div>
    </div>
    <!-- モーダル表示終了 ----------------------------------------------------->
vue_js.html
        // モーダル表示のプロパティ変更
        closeModal: function(){
                        this.dispDetails = false;
                        this.showContent = false; 
        },

ではまた。

追記::
スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版 その3~~で更新してみました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0