🌱
b-tableでソートすると選択行がクリアされてしまう
モチベ
- テーブルリストからユーザーが選択する場面などで困った。
- ググると「仕様です」みたいな内容が。解決方法は示されていない。
- 愚直にではあるが、解決できたので誰かの役に立てばと、記事にしてみる。
結論
問題再現
- こんな風にソートすると選択が解除されてしまう。
<template>
<div id="app">
<b-table
:items="items"
:fields="fields"
selectable
@row-selected="onSelected"
>
</b-table>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {
selected: [],
items: [
{ id: 1, age: 40, first_name: "Dickerson", last_name: "Macdonald" },
{ id: 2, age: 21, first_name: "Larsen", last_name: "Shaw" },
{ id: 3, age: 89, first_name: "Geneva", last_name: "Wilson" },
{ id: 4, age: 38, first_name: "Jami", last_name: "Carney" },
],
fields: [
{ key: "id", sortable: true },
{ key: "age", sortable: true },
{ key: "first_name", sortable: true },
{ key: "last_name", sortable: true },
],
};
},
methods: {
onSelected(rows) {
this.selected = rows;
},
},
};
</script>
問題解決
- ソート時に選択行を
backupSelected
に待避しておく - ソート直後の行活性は
activateRow
で行う
<template>
<div id="app">
<b-table
:items="items"
:fields="fields"
selectable
@row-selected="onSelected"
@sort-changed="onSortChanged"
>
<template v-slot:cell()="{ value, item, selectRow }">
{{ value }}
{{ activateRow(item, selectRow) }}
</template>
</b-table>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {
selected: [],
backupSelected: [],
items: [
{ id: 1, age: 40, first_name: "Dickerson", last_name: "Macdonald" },
{ id: 2, age: 21, first_name: "Larsen", last_name: "Shaw" },
{ id: 3, age: 89, first_name: "Geneva", last_name: "Wilson" },
{ id: 4, age: 38, first_name: "Jami", last_name: "Carney" },
],
fields: [
{ key: "id", sortable: true },
{ key: "age", sortable: true },
{ key: "first_name", sortable: true },
{ key: "last_name", sortable: true },
],
};
},
methods: {
onSelected(rows) {
if (rows.length === 0) {
this.selected = this.backupSelected;
this.backupSelected = [];
} else {
this.selected = rows;
}
},
onSortChanged() {
this.backupSelected = this.selected;
},
activateRow(row, activateRowFunc) {
if (this.selected.find((item) => row.id === item.id)) {
activateRowFunc();
}
},
},
};
</script>
プラスα
- ページ読み込み時に既に選択行がある場合は、あらかじめ行を活性化しておく
<template>
<div id="app">
<b-table
:items="items"
:fields="fields"
selectable
@row-selected="onSelected"
@sort-changed="onSortChanged"
>
<template v-slot:cell()="{ value, item, selectRow }">
{{ value }}
{{ activateRow(item, selectRow) }}
</template>
</b-table>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {
selected: [],
backupSelected: [],
alreadySelected: [
{ id: 1, age: 40, first_name: "Dickerson", last_name: "Macdonald" },
{ id: 3, age: 89, first_name: "Geneva", last_name: "Wilson" },
],
items: [
{ id: 1, age: 40, first_name: "Dickerson", last_name: "Macdonald" },
{ id: 2, age: 21, first_name: "Larsen", last_name: "Shaw" },
{ id: 3, age: 89, first_name: "Geneva", last_name: "Wilson" },
{ id: 4, age: 38, first_name: "Jami", last_name: "Carney" },
],
fields: [
{ key: "id", sortable: true },
{ key: "age", sortable: true },
{ key: "first_name", sortable: true },
{ key: "last_name", sortable: true },
],
};
},
methods: {
onSelected(rows) {
if (rows.length === 0) {
this.selected = this.backupSelected;
this.backupSelected = [];
} else {
this.selected = rows;
}
},
onSortChanged() {
this.backupSelected = this.selected;
},
activateRow(row, activateRowFunc) {
if (this.selected.find((item) => row.id === item.id)) {
activateRowFunc();
}
},
},
mounted() {
this.selected = this.alreadySelected;
},
};
</script>
感想
- slotについては本家のドキュメントが一番しっかりしてる。今まで何となくでやり過ごしていたけど、今回ちゃんと理解できてすっきりした。
- slotにしろb-tableにしろ、ドキュメントを読めば何の問題もないが、なかなか読まない人へ。お役に立てましたら。
- はじめて記事書きました。何かお気づきであればFBいただけると嬉しいです。
Discussion