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

[スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版 その１～～](https://qiita.com/yamamow/items/6be4fa99cd3cb45ecffa)からの続きです。

ハマったところはこちら↓
[スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版、ハマったところinputの再描画編~~](https://qiita.com/yamamow/items/ad967a1dbfda6f9e4aa8)

[スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版、ハマったところcheckboxの再描画編~~](https://qiita.com/yamamow/items/d5c353e6d52861007278)


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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207568/bf1c80de-66ba-b938-695c-1f814a0cc4ef.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207568/54a9d8cb-35ec-fb19-f265-2639b75fecab.png)


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

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

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

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

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

```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の中で以下のように記載されています。
はじめに上記のプロパティ２つをtrueにしています。
こうすることで「v-show」で表示するようになり、
「v-if」は内側のタグを表示するようになります。
（※閉じる処理の時は２つともfalseにしています。）
ここで「v-show」だけでもいいんじゃないの？と思われるかもしれませんが、試行錯誤の結果、「v-if」も記載し、明示的に「v-if」のtrue、falseを切り替えることで「v-if」を記載したよりも内側のタグの表示が正しく表示されるようになりました。詳しくはハマったところを見てやってください。

```javascript: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」の戻り値が入ります。
そのメソッドは下記になります。
そして、メソッド内で各パラメータに設定しています。

```javascript: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()で強制的に更新をかけることもしました。
きっと、そういうこともあるのではないかと残しておきます。
これでようやくマスターデータと詳細データの取得ができたので表示に取り掛かりましょう

こちら↓になります。

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

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

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

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

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

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

```html: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」と異なるプロパティを設定することにより
期待する動きを得ています。

```html: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ボタンとあまり変わりはありません。異なる点は
その１：データは配列で持つこと。
　　　　そうしないとデータが取れずに、true、falseでしか更新できなくなってしまいます。
その２：radioボタンと違って、複数の項目にチェックができますので、
　　　　「:checked」を「refits[4].indexOf(items.item) > -1」で判定しています。

```html: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に設定され、モーダルが閉じます。


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

ではまた。


追記：：
[スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版 その３～～](https://qiita.com/yamamow/items/c7c2c50cd26eed48988a)で更新してみました。