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?

Quasarのテーブルでセルにボタンを配置する

Posted at

Quasarのテーブルでセルにボタンを配置する

Quasarのテーブルでセルにボタンを配置する書き方を確認しました。

qtable_button.png

背景

Quasarのテーブル(QTable)は機能が豊富ですが、公式マニュアルがそれほど親切ではありません。テーブルのセルにボタンを表示する方法をマニュアルから読み解けなかったので、実験してみた結果です。

ポイント

1. v-slot:bodyスロットを使う

v-slot:bodyスロットを使って自力でq-trエレメントとq-tdエレメントをレンダリングします。

2. q-tdエレメントでレンダリングする

q-tdエレメントの中にボタンを配置します。

3. formatを呼び出す

QTableProp.columnsのformat属性を定義している場合は呼び出す必要があります。

4. alignmentを反映する

QTableProp.columnsのalgign属性も無視されるのでstyleに設定します。

5. 値を計算する場合にも使える

エレメント内で簡単な計算もできます。

Vueコンポーネントの全コード

表の中から製品名をクリックして、絞り込み検索するサンプルです。

<script setup lang="ts">
import { ref } from 'vue';

// テーブルの元データ
const rows1 = [
    { name1: 'Eclair', name2: 'Baked goods', price: 2.50, qty: 16},
    { name1: 'Froyo', name2: 'Yogurt', price: 1.80, qty: 12},
    { name1: 'Ice Cream Sandwich', name2: 'Ice Cream', price: 2.00, qty: 10},
    { name1: 'Doughnut', name2: 'Baked goods', price: 2.00, qty: 7},
    { name1: 'Jelly Bean', name2: 'Jelly', price: 1.50, qty: 12},
    { name1: 'Honeycomb', name2: 'Honey', price: 8.00, qty: 10},
    { name1: 'Cupcake', name2: 'Baked goods', price: 3.00, qty: 17},
    { name1: 'Eclair', name2: 'Baked goods', price: 2.50, qty: 12},
    { name1: 'Ice Cream Sandwich', name2: 'Ice Cream', price: 2.00, qty: 3},
    { name1: 'Honeycomb', name2: 'Honey', price: 8.00, qty: 12},
    { name1: 'Cupcake', name2: 'Baked goods', price: 3.00, qty: 5},
    { name1: 'Froyo', name2: 'Yogurt', price: 1.80, qty: 15},
    { name1: 'Ice Cream Sandwich', name2: 'Ice Cream', price: 2.00, qty: 12},
    { name1: 'Jelly Bean', name2: 'Jelly', price: 1.50, qty: 1},
    { name1: 'Eclair', name2: 'Baked goods', price: 2.50, qty: 12},
    { name1: 'Jelly Bean', name2: 'Jelly', price: 1.50, qty: 4},
    { name1: 'KitKat', name2: 'Chocolate', price: 1.00, qty: 11},
    { name1: 'KitKat', name2: 'Chocolate', price: 1.00, qty: 1},
    { name1: 'Gingerbread', name2: 'Baked goods', price: 1.80, qty: 12},
    { name1: 'Gingerbread', name2: 'Baked goods', price: 1.80, qty: 15},
    { name1: 'Cupcake', name2: 'Baked goods', price: 3.00, qty: 11},
    { name1: 'Honeycomb', name2: 'Honey', price: 8.00, qty: 7},
    { name1: 'Cupcake', name2: 'Baked goods', price: 3.00, qty: 13},
    { name1: 'Eclair', name2: 'Baked goods', price: 2.50, qty: 14},
    { name1: 'Doughnut', name2: 'Baked goods', price: 2.00, qty: 6},
    { name1: 'Honeycomb', name2: 'Honey', price: 8.00, qty: 18},
    { name1: 'Doughnut', name2: 'Baked goods', price: 2.00, qty: 3},
    { name1: 'Lolipop', name2: 'Candy', price: 1.00, qty: 7},
    { name1: 'KitKat', name2: 'Chocolate', price: 1.00, qty: 10},
    { name1: 'Gingerbread', name2: 'Baked goods', price: 1.80, qty: 5},
];

// テーブルの列定義
const columns1 = [
    { name: 'name1', field: 'name1', label: 'Name', sortable: true, align: 'left' },
    { name: 'name2', field: 'name2', label: 'Type', sortable: true, align: 'left' },
    { name: 'price', field: 'price', label: 'Price', sortable: true, format: (val: any) => val.toFixed(2) },
    { name: 'qty', field: 'qty', label: 'Qty' },
    { name: 'subtotal', field: 'subtotal', label: 'Subtotal' },
] as any[];

// 検索結果の行データ
const searchedRows1 = ref(rows1);

// 検索フィールド値
const searchField = ref('');

// 検索処理
const onKeydownSearch = (e: KeyboardEvent) => {
    if (e.key === 'Enter') {
        onClickSearch();
    }
};

// 検索ボタンクリック処理
const onClickSearch = () => {
    if (!searchField.value) {
        searchedRows1.value = rows1;
    } else {
        searchedRows1.value = rows1.filter((row) => row.name1.includes(searchField.value) || row.name2.includes(searchField.value));
    }
}

// セルのボタンクリック処理
const onClickCell = (name: string) => {
    searchField.value = name;
    onClickSearch();
};

</script>

<template>
    <div style="max-width: 40rem;">
        <div class="row q-ma-sm">
            <!-- 検索フィールドとボタン -->
            <q-input outlined v-model="searchField" label="Search" clearable @keydown="onKeydownSearch" />
            <q-btn class="q-ma-sm" size="small" icon="search" round @click="onClickSearch"/>
            <q-space/>
            <div style="display: flex; align-items: last baseline;" class="q-ma-sm">
                Total: <b>{{ searchedRows1.reduce((acc, row) => acc + row.price * row.qty, 0).toFixed(2) }}</b>
            </div>
        </div>
        <!-- テーブル -->
        <q-table :rows="searchedRows1" :columns="columns1" :pagination="{ rowsPerPage: 10}">
            <!--ポイント1. v-slot:bodyスロットを使う-->
            <template v-slot:body="props">
                <q-tr>
                    <!-- ポイント2. q-tdエレメントでレンダリングする / ポイント4. alignmentを反映する -->
                    <q-td v-for="c of props.cols" :key="c.field" :style="{ textAlign: c.align }">
                        <template v-if="c.field === 'name1' || c.field === 'name2'">
                            <q-btn @click="onClickCell(props.row[c.field])">
                                {{ props.row[c.field] }}
                            </q-btn>
                        </template>
                        <template v-else-if="c.field === 'subtotal'">
                            <!-- ポイント5. 値を計算する場合にも使える -->
                            {{ (props.row.price * props.row.qty).toFixed(2) }}
                        </template>
                        <template v-else-if="c.format">
                            <!-- ポイント3. formatを呼び出す -->
                            {{ c.format(props.row[c.field]) }}
                        </template>
                        <template v-else>
                            <!-- 何もしない列をレンダリング -->
                            {{ props.row[c.field] }}
                        </template>
                    </q-td>
                </q-tr>
            </template>
        </q-table>
    </div>
</template>

確認したバージョン

  • vue: 3.5.13
  • quasar: 2.17.7
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?