DEV Community

dtechmaster
dtechmaster

Posted on

Dynamic Slot Names Usage

I just wan't to be sure if this is the right way to name and use slots dynamicaly. I'm not having any problem with this, the problem is that despite it works, I can't find anyone or any docs doing this so I decided publish a post here so you guys can judge this code and point eventual problems that I'm not seeing.

My environment

Nuxt 3

d-virtual-table Component

description: The component purpose is a table with slots that I can use named dynamically based on my input values so I can replace default components by a column.field or a column.type based on the need when creating a page/screen.

<template>
    <RecycleScroller class="scroller" :items="rows" :item-size="63" key-field="name" listTag="table"
        listClass="data-table" itemTag="tr" itemClass="" :buffer="200">
        <template #before="{ item: row }">
            <table class="data-table">
                <thead>
                    <tr class="data-table-header">
                        <th v-for="column in columns">
                            <slot :name="`column-${column.field}`" :row="row" :column="column" :value="column.field"
                                >
                                <slot :name="`column-${column.type}`" :row="row" :column="column" :value="column.field"
                                    >
                                    {{ column.field }} ({{ column.type }})
                                </slot>
                            </slot>
                        </th>


                    </tr>
                </thead>
            </table>
        </template>

        <template #default="{ item: row, index }">
            <td v-for="col in columns" :class="getOddEven(index)">
                <slot :name="col.field" :row="row" :column="col" :value="row[col.field]" :index="index">
                    <slot :name="col.type" :row="row" :column="col" :value="row[col.field]" :index="index">
                        {{ row[col.field] }} 
                    </slot>
                </slot>
            </td>


        </template>
    </RecycleScroller>
</template>


<script setup lang="ts">
interface Column {
    label: string
    field: string
    type?: string
    dateOutputFormat?: string
    dateInputFormat?: string
}
interface Row {
    id: number
    name: string
    age: number
    createdAt: string
    score: number
}
defineProps<{
    columns: Column[]
    rows: Row[]
}>()

function getOddEven(index: number) {
    if (typeof index !== 'number') {
        return '';
    }
    return index % 2 === 0 ? 'row-even' : 'row-odd';
}
</script>

<style>
.scroller {
    height: 100%;
}

.user {
    height: 32%;
    padding: 0 12px;
    display: flex;
    align-items: center;
}

.data-table {
    border-collapse: collapse !important;
    width: 100%;
}

.data-table tr {
    width: 100%;
    display: flex;
}

.data-table td,
.data-table th {
    padding: 10px 15px;
    border: 1px solid black;
    flex: 1;
}

.data-table-header th {
    font-weight: 700;
    padding: 10px 15px;
    border: 1px solid black;
}

.row-odd {
    background-color: white;
}

.row-even {
    background-color: rgba(210, 210, 210, 0.507);
}

tbody {
    display: block;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Component usage

<template>
    <div class="page-wrapper">
    <!-- <d-virtual-table :rows="rows" :columns="columns" /> -->
     <d-virtual-table :rows="rows" :columns="columns">
        <template #column-name="{row, column, value}">
            {{ value }} (ABC)
        </template>

        <template #column-age="{row, column, value}">
            {{ value }} (N)
        </template>

        <template #column-date="{row, column, value}">
            {{  value }} yy/mm/dd
        </template>

        <template #column-score="{row, column, value}">
            {{ value }} (%)
        </template>

        <template #string="{row,column,value}">
            <v-text-field density="compact" variant="outlined" hide-details type="text" :label="column.label" v-model="row[column.field]" />
        </template>

        <template #score="{row,column,value}">
            <v-chip class="border" type="text" v-model="row[column.field]" :text="value"/> %
        </template>
     </d-virtual-table>
    </div>
</template>

<script setup lang="ts">
const columns = [
    {
        label: 'Name',
        field: 'name',
        type: 'string'
    },
    {
        label: 'Age',
        field: 'age',
        type: 'number',
    },
    {
        label: 'Created On',
        field: 'createdAt',
        type: 'date',
        dateInputFormat: 'yyyy-MM-dd',
        dateOutputFormat: 'MMM do yy',
    },
    {
        label: 'Percent',
        field: 'score',
        type: 'string',
    },
];

const rows = [
    { id: 1, name: "John", age: 20, createdAt: '', score: 0.03343 },
    { id: 2, name: "Jane", age: 24, createdAt: '2011-10-31', score: 0.03343 },
    { id: 3, name: "Susan", age: 16, createdAt: '2011-10-30', score: 0.03343 },
    { id: 4, name: "Chris", age: 55, createdAt: '2011-10-11', score: 0.03343 },
    { id: 5, name: "Dan", age: 40, createdAt: '2011-10-21', score: 0.03343 },
    { id: 6, name: "John", age: 20, createdAt: '2011-10-31', score: 0.03343 },
];
</script>

<style scoped>
.page-wrapper {
    height: 100dvh;
    max-height: 100dvh;
    overflow: hidden;
}
</style>
Enter fullscreen mode Exit fullscreen mode

The only thing I found about this is the bellow vue 3 docs which seems wrong or incomplete? looks like just the usage part is here or am I just not getting this?

https://vuejs.org/guide/components/slots.html#dynamic-slot-names
https://vuejs.org/guide/components/slots.html#dynamic-slot-names

Well, that's it. anything wrong with this? Thank very much for you guys time.

Top comments (0)