Quasar: How to give props in q-table to parent component?

Viewed 2980

I have created TableTop5 component using q-table, so that I can reuse it in VisitorSummary.vue, but I have no clue how to get props which should be written in v-slot:header and v-slot:body.

VisitorSummary.vue

    ...
    <div class="row card-wrap row-sec">
      <table-top-5 title="검색어 TOP5" titleWord="검색어 TOP5"
        :data="data" :columns="columns" :rowFirst="rank" // <-- it gives me errors..
        :rowSec="keyword" :rowThird="visitor" :props="props" // <-- i can feel it isn't right..
      >
      </table-top-5>
    </div>
    ...

<script lang="ts">
import Vue from 'vue';
import axios from 'axios';
import VueApexCharts from 'vue-apexcharts'

import NumberCount from 'components/card/NumberCount.vue'
import NumberCountSet from 'components/card/NumberCountSet.vue';
import TitleWithTooltip from 'components/card/TitleWithTooltip.vue'
import TableTop5 from 'components/table/TableTop5'

Vue.use(VueApexCharts)
Vue.component('apexchart', VueApexCharts)

export default Vue.extend({
  components: {
    NumberCountSet,
    NumberCount,
    TitleWithTooltip,
    TableTop5,
  },
  data() {
    return {
      
      columns: [
        {
          name: 'rank',
          required: true,
          label: '순위',
          align: 'center',
          field: row => row.rank,
          format: val => `${val}`,
          sortable: true,
          style: 'width: 10%;'
        },
        { name: 'keyword', align: 'left', label: '검색어', field: 'keyword', sortable: true,
        style: 'width: 70%; background:RGBA(0,178,45,0.05) '  },
        { name: 'visitor', align: 'center', label: '방문자수', field: 'visitor', sortable: true, style: 'width: 20%' },
      ],
      data: [
        {
          rank: 1,
          keyword: 'slimplanet',
          visitor: 25,
        },
        {
          rank: 2,
          keyword: 'test',
          visitor: 58,
        },
        {
          rank: 3,
          keyword: 'test',
          visitor: 64,
        },
        {
          rank: 4,
          keyword: 'Slimplanet',
          visitor: 72,
        },
        {
          rank: 5,
          keyword: 'test',
          visitor: 18,
        },
      ],
    };
  },
  
});
</script>

TableTop5.vue

<template>
  <q-card class="card-item">
    <q-card-section class="q-pa-none">
      <div>
        <q-table
          :data="data"
          :columns="columns"
          row-key="name"
          class="no-shadow q-pb-md q-px-md"
          :hide-pagination="true"
        >
          <template v-slot:header="props">
            <q-tr :props="props">
              <q-th
                v-for="col in props.cols"
                :key="col.name"
                :props="props"
                style="font-weight: bold"
              >
                {{ col.label }}
              </q-th>
            </q-tr>
          </template>
          <template v-slot:body="props">
            <q-tr :props="props">
              <q-td key="rowFirst" :props="props">
                {{ rowFirst }}
              </q-td>
              <q-td key="rowSec" :props="props">
                {{ props.row.rowSec }}
              </q-td>
              <q-td key="rowThird" :props="props">
                <q-badge color="black" outline>
                  {{ props.row.rowThird }}
                </q-badge>
              </q-td>
            </q-tr>
          </template>
        </q-table>
      </div>
    </q-card-section>
  </q-card>
</template>

<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
  name: 'TableTop5',
  props: {
    title: {
      type: String
    },
    titleWord: {
      type: String
    },
    data: {
      type: Array
    },
    columns: {
      type: Array
    },
    rowFirst: {
      type: String
    },
    rowSec: {
      type: String
    },
    rowThird: {
      type: String
    },
    props: {
      type: Object
    }
  }
});
</script>

Or should i just not reuse and write q-table whenever I need it in a row?

1 Answers

This can be done in multiple ways. You can define it like this where the parent component takes care of rendering rows and columns. You can also define some columns that every table needs to have and have a slot for extra columns.

You could also iterate over the columns so you render them dynamically.

Either way, the advantage to this approach, is consistency and reusability, in case you have some complex logic inside the table for filtering and other stuff.

TableTop5

<template>
  <q-table :data="data" :columns="columns">
    <template #body="props">
      <slot v-bind="props" name="columns"></slot>
    </template>
  </q-table>
</template>

<script>
export default {
  name: 'TableTop5',
  props: {
    data: {
      type: Array,
    },
    columns: {
      type: Array,
    },
  },
};
</script>

VisitorSummary

<template>
  <div>
    ...
    <table-top5 :data="data" :columns="columns">
      <template #columns="props">
        <q-tr>
          <q-td key="c1">
            {{ props.row.c1 }}
          </q-td>
          <q-td key="c2">
            {{ props.row.c2 }}
          </q-td>
        </q-tr>
      </template>
    </table-top5>
    ...
  </div>
</template>

<script>
import TableTop5 from '@/TableTop5.vue';

export default {
  name: 'VisitorSummary',
  components: {
    TableTop5,
  },
  data() {
    return {
      columns: [
        {
          name: 'c1',
          label: 'Col 1',
          field: 'c1',
          align: 'left',
        },
        {
          name: 'c1',
          label: 'Col 2',
          field: 'c2',
          align: 'left',
        },
      ],
      data: [
        {
          c1: 'C1 data - row 1',
          c2: 'C2 data - row 1',
        },
        {
          c1: 'C1 data - row 2',
          c2: 'C2 data - row 2',
        },
      ],
    };
  },
};
</script>
Related