0
votes

In a vuejs application there are 3 components - TopClicks.vue, TopImpressions.vue, TopCtr.vue. Each one of these is using vue-good-table (the component itself is not important, it can be any) to render almost the same table, but sorted differently:

../components/TopClicked.vue (almost 200 lines)

<template>
  <div class="top-clicked">
    <vue-good-table
      mode="remote"
      @on-page-change="onPageChange"
      @on-sort-change="onSortChange"
      :sort-options="{
        enabled: true,
        initialSortBy: {field: 'clicks', type: 'desc'}
      }"
      ... 
    >
      <template slot="table-row" slot-scope="props">
        <template v-if="props.column.field === 'keyword'">
          ...
        </template>
        <template v-else-if="props.column.field === 'clicks'">
          ...
        </template>
        <template v-else-if="props.column.field === 'impressions'">
          ...
        </template>
         ...
      </template>
      <template slot="loadingContent">
        <span class="vgt-loading__content">
          ...
        </span>
      </template>
      <template slot="emptystate">
          ...
      </template>
    </vue-good-table>
  </div>
</template>

<script>

import { VueGoodTable } from 'vue-good-table';

export default {
  name: 'TopClicked',
  components: { VueGoodTable},
  data() {
    return {
      columns: [
        {
          label: this.$t('keyword'),
          field: 'keyword',
        },
        {
          label: this.$t('clicks'),
          field: 'clicks',
        },
        ... more columns
      ],
    };
  },
};
</script>

The other two components - TopImpressions.vue and TopCtr.vue are almost the same, but with different :sort-options param.

My question is: How to organise my code to avoid making the same change multiple times in the passed to vue-good-table' component props or slot templates? How should a component look like, which passes default props and slots to another component, but these can be overwritten when needed?

It would be great if instead of copying the 200 lines of code from above, a child component (with base pros and slot templates) can be created and used like this

<vue-good-table-child
  // this should overwrite default :sort-options in vue-good-table-child
  :sort-options="{
    enabled: true,
    initialSortBy: {field: 'impressions', type: 'desc'}
  }"
>
  // this should overwrite default named slot "loadingContent" in vue-good-table-child
  <template slot="loadingContent">
    ...
  </template>
</vue-good-table-child>

This way all common code will be in a base component, and only the different props (or slot templates) should be passed to the child component.

1

1 Answers

0
votes

I'd try merging the 3 nearly identical components into 1 component that receives the custom sortOptions it needs as a prop:

// This is the merged component, TopThings.vue, it replaces the instances 
// of TopClicks.vue, TopImpressions.vue, and TopCtr.vue in the parent component

<template>
<div class="top-clicked">
    <vue-good-table
        ...
        :sort-options="sortOptions"
        ...
    />
    ...
</template>

<script>
    ...
    props: {
        sortOptions: {
            type: Object,
            required: true,
        },
    },
    ...
</script>

In your parent component, import the TopThings component and call it in place of each of your 3 previous components, where each implementation is passed its respective sortOptions:

// This is the parent component where the 3 tables are implemented as 
// separate instances of <TopThings />

<template>
    ...
    <TopThings // this is the TopClicks implementation
        :sort-options="sortOptions.topClicks"
    />
    ...
    <TopThings // this is the TopImpressions implementation
        :sort-options="sortOptions.topImpressions"
    />
    ...
    <TopThings // this is the TopCTR implementation
        :sort-options="sortOptions.topCTR"
    />
    ...
</template>

<script>

components: {
    TopThings.vue,
},
data() {
    return {
        sortOptions: {
            topClicks: {
                enabled: true,
                initialSortBy: {field: 'clicks', type: 'desc'}
            },
            topImpressions: {
                ...
            },
            topCTR: {
                ...
            },
        },
    };
},