BootstrapVue table-template inside Vue slot
Solution 1
just build your custom component and pass any custom props you need some thing like this:
<template>
<b-table v-bind="$attrs" v-on="$listeners" custom-prop="any">
<slot v-for="(_, name) in $slots" :name="name" :slot="name" />
<template
v-for="(_, name) in $scopedSlots"
:slot="name"
slot-scope="slotData"
><slot :name="name" v-bind="slotData"
/></template>
</b-table>
</template>
<script>
export default {
name: 'AppTable',
}
</script>
<style scoped></style>
this works like a charm!
Solution 2
You can use a component's render function to pass slots and scopedSlots to another component (like b-table
). But then you don't get to use a template. To let you have a template (with pagination, searching, etc.) you can wrap the rendering component into another component that does have a template. So then you would have a custom-table
component which contains pagination and a table-wrapper
component, and the table-wrapper
component would render a b-table
.
Here's a very specific example..
const constItems = [{
index: 0,
isActive: true,
age: 40,
first_name: 'Dickerson',
last_name: 'Macdonald'
},
{
index: 1,
isActive: false,
age: 21,
first_name: 'Larsen',
last_name: 'Shaw'
},
{
index: 2,
isActive: false,
age: 89,
first_name: 'Geneva',
last_name: 'Wilson'
},
{
index: 3,
isActive: true,
age: 38,
first_name: 'Jami',
last_name: 'Carney'
}
];
const bTableProps = {
items: {
type: [Array, Function],
default: undefined
},
fields: {
type: [Object, Array],
default: undefined
}
};
const constFields = [
'index',
'isActive',
'age',
'first_name',
'last_name'
];
Vue.component('table-wrapper', {
props: Object.assign({}, bTableProps),
render(h) {
return h('b-table', {
props: this.$props,
slots: this.$parent.$slots,
scopedSlots: this.$parent.$scopedSlots,
on: {
'row-clicked': (item, index, event) => alert('clicked ' + index)
}
});
}
});
Vue.component('custom-table', {
template: '<div><h3>hello table</h3><table-wrapper :items="items" :fields="fields"></table-wrapper></div>',
props: Object.assign({}, bTableProps)
});
new Vue({
el: "#app",
data: {
items: constItems,
fields: constFields
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/[email protected]/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>
<div id="app">
<custom-table :items="items" :fields="fields">
<template slot="index" slot-scope="data">
{{ data.index + 1 }}
</template>
</custom-table>
<custom-table :items="items" :fields="fields">
<template slot="index" slot-scope="data">
{{ data.index + 2 }}
</template>
</custom-table>
<custom-table :items="items" :fields="fields">
<template slot="index" slot-scope="data">
{{ data.index + 3 }}
</template>
</custom-table>
</div>
Decay42
Computer science student from Germany. Mostly interested in Web Development (HTML5, CSS, JS, jQuery, PHP).
Updated on June 04, 2022Comments
-
Decay42 almost 2 years
I want to create a parent component for a bootstrap-vue table with custom data rendering (templates).
Right now, this kinda looks like this:
<b-table :items="result" :fields="fields" :current-page="currentPage" :per-page="perPage"> <template slot="Index" slot-scope="data"> {{ data.index + 1 }} </template> <!-- more templates for various columns here --> </b-table> <b-pagination align="center" :total-rows="result.length" v-model="currentPage" :per-page="perPage" />
The reason I want to wrap this in a component is because I use this table layout, including the pagination and all of its attributes (like striped, bordered, etc.) multiple times.
The only thing that changes, are the column-templates.
I know, the Vue way to do that would be to create a slot like
<slot name="x"></slot>
and fill it with<template slot="x">...</template>
. For one thing, that would coincide with the bootstrap-vuetemplate
and on the other hand, bootstrap-vue only seems to render the templates correctly, if they are placed right insideb-table
.Basically, what I want to achieve is a component like this:
<b-table> <slot name="templates"/> </b-table> <b-pagination stuff.../>
And use it in a child component like this:
<TemplateTable> <template slot="templates"> <template slot="Index" slot-scope="data"> {{ data.index + 1 }} </template> <!-- more templates --> </template> </TableTemplate>
Has anyone done something like this and figured out a way to solve it?
-
Stan Smulders over 4 yearsThanks for sharing this! It had me in a complete bind trying to figure it out. I'll post my
.vue
solution as well for future reference :) -
nardnob over 4 yearsGlad it could help. I posted it as much for my own future reference as for everyone else =)