0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Vue】テーブル操作エキスパートへの道。ボタンクリックで行を削除する方法

Last updated at Posted at 2020-11-04

ボタンクリックで表から行を削除する方法について。

これまで、

v-forを使ったテーブルの作成
表で複数選択を可能にする方法
ボタンクリックで行を追加する方法
ボタンクリックで列を追加する方法

について確認したので、次のステップとして行を削除する方法を確認する。

##アウトプットイメージ

image.png

↓ 選択している行のみを削除

image.png

##行削除の考え方
複数選択時は、選択した行をすべて削除する。
考え方は比較的シンプル

  • 選択中の行番号を抽出する(重複削除)
    • Set, mapメソッド
  • 抽出した行番号以外の表を作る
    • filter, hasメソッド

##行削除実例

行削除のメソッド
removeRow(){
      //選択中のセルがある場合のみ処理を実行
      if(this.currentCells.length != 0){

        //削除したいセル番号を抽出(重複削除)
        const rowIndicesToRemove = new Set(
          this.currentCells.map(cell => cell.xxxrowIndex )
        )

        //削除したい列を除外(該当した行番号はスルー)
        this.rows = this.rows.filter((row, rowIndex)=>
          !rowIndicesToRemove.has(rowIndex)
        )

        //選択中のセルを解除
        this.currentCells = []
      }
    }

####・選択中のセルがある場合のみ処理を実行 `if(this.currentCells.length != 0)` 現在選択中のセルがない場合は何もしない。

####・選択中のセルの行番号を抜き出す
Setオブジェクトを使う。

Setオブジェクトとは、重複がない特別なオブジェクト。配列のように並び順もない。袋の中に個々の値が入っているイメージ。

const rowIndicesToRemove = new Set(
          this.currentCells.map(cell => cell.xxxrowIndex )
        )

new Set()でSetオブジェクトを生み出す。

this.currentCells.map(cell => cell.xxxrowIndex)
選択中のセルの行番号を一つづつ取得し配列にする。

この処理を実行することで下記のようなイメージになる。

Setオブジェクトの詳しい使い方はこちら

####・指定した要素以外を抜き出す

        this.rows = this.rows.filter((row, rowIndex)=>
          !rowIndicesToRemove.has(rowIndex)
        )

filterメソッドはtrueになった場合のみ要素を残す。第二引数はインデックス番号になる。

rowIndicesToRemove.has(rowIndex)
現在選択中の行番号が入ったSetオブジェクトrowIndeicesToRemoveに対し、hasメソッドで一致する値があった場合にtrueを返す。

hasメソッドはSet専用のメソッド。指定した値があるとtrue,該当しない場合はfalseを返す。

ArrayオブジェクトのindexOfincludeメソッドと似た役割。

!をつけることで、一致しない場合のみtrueとすることで、残したい列のみを残す。


##フルコード
<template>
  <div>
    <p>〜TmpRemoveRow.vue〜</p>
    <p>currentCells : {{currentCells}}</p>
    

    <p>
      <button
        @click="removeRow"
      >行を削除
      </button>
    </p>

    <table>
      <template v-for="(tr, rowIndex) in rows">
        <tr :key="rowIndex">
          <template v-for="(cell, cellIndex) in tr.table_cells">
            <th :key="cellIndex" 
                v-if="cell.cell_type == 'TH'"
                :class="{'is-active': isActive(rowIndex, cellIndex)}"
                @click="clickCell($event)">
              ( {{rowIndex}} , {{cellIndex}} )
            </th>
          
            <td :key="cellIndex" 
                v-else-if="cell.cell_type == 'TD'"
                :class="{'is-active': isActive(rowIndex, cellIndex)}"
                @click="clickCell($event)">
              ( {{rowIndex}} , {{cellIndex}} )
            </td>
          </template>
        </tr>
      </template>
    </table>

  </div>
</template>

<script>
export default {
  data(){
    return{
      currentCells:[],
      rows: [
        {
          "table_cells": [
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
          ]
        },
        {
          "table_cells": [
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
          ]
        },
                {
          "table_cells": [
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
          ]
        },
        {
          "table_cells": [
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
          ]
        },
        {
          "table_cells": [
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
            {"cell_type": "TD"},
          ]
        },
      ]
    }
  },
  methods:{
    //isActiveの判定
    //currentCellsの中にあればtrueにする
    //指定した行列番号の要素がある=数値が-1以外ならtrueにする。
    isActive(rowIndex, cellIndex){
      return this.currentCells.findIndex((elem) =>
        elem.xxxrowIndex == rowIndex && elem.xxxcellIndex == cellIndex
        ) > -1
    },

    clickCell(event){
      //クリックされたセルの情報
      const cell = event.target
      const tr = event.target.parentNode

      //クリックされたセルが既に選択されている場合は、配列から削除する
      if(this.isActive(tr.rowIndex, cell.cellIndex)){
        
        //選択中の配列の何番目の要素かを求める
        const rmIndex = this.currentCells.findIndex((elem)=>
          elem.xxxrowIndex == tr.rowIndex && elem.xxxcellIndex == cell.cellIndex 
        )

        //選択した要素を選択中の配列から削除する
        this.currentCells = [
          ...this.currentCells.slice(0, rmIndex),
          ...this.currentCells.slice(rmIndex + 1)
        ]

      } else{
        this.currentCells = [
          ...this.currentCells,
          {
            xxxrowIndex: tr.rowIndex,
            xxxcellIndex: cell.cellIndex
          }
        ]
      }
    },
    removeRow(){
      //選択中のセルがある場合のみ処理を実行
      if(this.currentCells.length != 0){

        //削除したいセル番号を抽出(重複削除)
        const rowIndicesToRemove = new Set(
          this.currentCells.map(cell => cell.xxxrowIndex )
        )

        //削除したい列を除外(該当した行番号はスルー)
        this.rows = this.rows.filter((row, rowIndex)=>
          !rowIndicesToRemove.has(rowIndex)
        )

        //選択中のセルを解除
        this.currentCells = []
      }
    }
  }
}
</script>

<style lang="scss" scoped>
table{
  width: 80%;

  th,td{
    border: thin solid rgba(0, 0, 0, 0.12);
    text-align: center;
    color: gray;
  }
  th{
    background: #ccc;
  }
  th, td{
    //選択状態
    &.is-active{
      border: 1px double #0098f7;
    }
  }
}
button{ 
   background: gray;
   padding: 5px 20px;
   color: white;
   border-radius: 50px;
}
input{
  margin: 7px;
  box-sizing: border-box;
}
</style>

コード自体はすごく簡単。Set, has, map, filterを使えるかが鍵となる。

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?