vue b-table customize pagination to show all rows - vue.js

I am using bootstrap-vue. For pagination of a b-table, I used b-pagination component with the following code for the template:
<div class="description perpage">Per page</div>
<b-form-select class="numPerPage" v-model="perPage" :options="pageOptions"></b-form-select>
<b-col sm="7" md="6" class="pagination">
<b-pagination
:total-rows="totalRows"
v-model="currentPage"
:per-page="perPage"
align="fill"
class="my-0"
aria-controls="my-table"
last-number
></b-pagination>
</b-col>
<div class="description found">Found: {{this.totalRows}}</div>
</div>
<b-table
id="my-table"
show-empty
striped
hover
sticky-header="true"
:items="filteredItems"
:fields="fields"
:per-page="perPage"
:current-page="currentPage"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc">
and the following for the script part:
data() {
return {
totalRows: 1,
perPage: 10,
currentPage: 1,
sortBy: "name",
sortDesc: false,
pageOptions: [5, 10, 20, 50, "show all"],
fields: [..myfields]
};
}
And if I use "show all" in the options field it will show all rows, but it will not properly set the pagination to only one available page.
current display
I want to achieve showing the correct pagination option (only one page) or be able to hide the whole pagination when the "show all" option was made.
How can I get this done?

The easiest way would be to set your show all option to a REALLY high number. To do this you could use the constant Number.MAX_SAFE_INTEGER which contains the number of 9007199254740991.
Which i would safely guess you wont reach in rows.
If you want to hide the pagination completely when the show all option is selected, you could instead set the value to 0. This will show all rows too.
Then you add a v-if to your pagination <b-pagination v-if="perPage !== 0">, which will hide it when that option is selected.
new Vue({
el: '#app',
created() {
for (let i = 0; i < 1000; i++) {
this.items.push({
id: i + 1
});
}
},
computed: {
totalRows() {
return this.items.length
}
},
data() {
return {
perPage: 10,
currentPage: 1,
sortBy: "name",
sortDesc: false,
/* Number.MAX_SAFE_INTEGER = 9007199254740991 */
pageOptions: [5, 10, 20, 50, {
value: Number.MAX_SAFE_INTEGER,
text: "show all"
}],
items: []
}
}
})
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.13.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.13.0/dist/bootstrap-vue.js"></script>
<div id="app">
<div class="description perpage">Per page</div>
<b-form-select class="numPerPage" v-model="perPage" :options="pageOptions"></b-form-select>
<b-pagination
:total-rows="totalRows"
v-model="currentPage"
:per-page="perPage"
align="fill"
class="my-0"
aria-controls="my-table"
></b-pagination>
<div class="description found">Found: {{ this.totalRows }}</div>
<b-table
id="my-table"
show-empty
striped
hover
sticky-header="true"
:items="items"
:per-page="perPage"
:current-page="currentPage"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc">
</b-table>
</div>

Related

V-select issue in Vuetify 3

I'm using Vuetify 3.0.0-beta.0 ~ for my project (because it is the only version that supports vue3), and having a bit weird issue
I want to implement the same thing as described there https://codepen.io/reijnemans/pen/vYNadMo?editors=1010 with v-select involved, so I was needed to use Vuetify
copied snippet
<v-select
:items="items"
label="Standard"
>
<template v-slot:selection="{ item, index }">
<img :src="item.image">{{ item.name }}</template>
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}</template>
</v-select>
My Component:
<template>
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
:items="items"
label="Standard">
<template v-slot:selection="{ item }">
<img :src="item.image">{{ item.name }}
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}
</template>
</v-select>
</v-col>
</v-col>
</div>
</template>
<script>
import { mapState } from "vuex";
/* eslint-disable */
export default {
name: "testComponent",
data() {
return {
// hardware Configuration Validation Rules
items: [
{ name: 'Foo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Bar', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Hoo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Coo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'}],
}
}}
When I'm trying to run the above component I always get this weird error Failed setting prop "type" on <select>: value text is invalid. TypeError: Cannot set property type of #<HTMLSelectElement> which has only a getter,
Did anyone faced similar issue before?
In Vuetify 3, you need some workarounds to style the items in v-select, because the item slot resets the entire styling.
You should use the menu-props, with it you can pass props through to the v-menu component. It accepts an object with anything from /api/v-menu. This allows you to close the field on click.
In the item slot, you should use a v-list-item with an #click property to set the model.
I made an example here with a selection of symbols:
<script setup>
const symbols = [
'ab-testing',
'abacus',
'account',
'account-alert',
]
const form = { symbol: '', }
</script>
<template>
<v-select
v-model="form.symbol"
:items="symbols"
label="Symbol"
:prepend-inner-icon="'mdi-'+form.symbol"
:menu-props="{
closeOnClick: true,
closeOnContentClick: true,
}"
>
<template v-slot:selection="{ item, index }">
{{ item.value }}
</template>
<template v-slot:item="{ item, index }">
<v-list-item
:title="item.title"
:prepend-icon="'mdi-'+item.title"
#click="form.symbol = item.title"
>
</v-list-item>
</template>
</v-select>
</template>
I hope it helps you.
I couldn't find correct solution but I just wanted to share what I did about scoped slot. I think we should use item.raw to access name and image. And the next problem is how to make it clickable to trigger select event that I didn't know yet :(
const { createApp } = Vue
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const app = createApp({
data() {
return {
value: null,
items: [
{
name: 'Foo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Bar',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Hoo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Coo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
}
]
}
}
});
app.use(vuetify).mount('#app');
<link href="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.js"></script>
<div id="app">
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
v-model="value"
:items="items"
item-title="name"
item-value="name"
label="Standard">
<template v-slot:item="{item}">
<v-list-item
:prepend-avatar="item.raw.image"
:title="item.raw.name"
/>
</template>
</v-select>
</v-col>
</v-col>
</div>
</div>

Vue bootstrap form tags allowing duplicates

I'm trying to allow duplicates in Vue bootstrap's form tags.
I've tried using :tag-validator (in the example) and #tag-state to externally modify the v-model value. However it seems like it is getting rid of the duplicate somewhere. Is this impossible?
Jsfiddle of the example: https://jsfiddle.net/yts54fpd/.
<div id="app">
<template>
<div>
<b-form-group label="Tagged input using select" label-for="tags-component-select">
<!-- Prop `add-on-change` is needed to enable adding tags vie the `change` event -->
<b-form-tags
:tag-validator="tagValidator"
id="tags-component-select"
v-model="value"
size="lg"
class="mb-2"
add-on-change
no-outer-focus
>
<template v-slot="{ tags, inputAttrs, inputHandlers, disabled, removeTag }">
<ul v-if="tags.length > 0" class="list-inline d-inline-block mb-2">
<li v-for="tag in tags" :key="tag" class="list-inline-item">
<b-form-tag
#remove="removeTag(tag)"
:title="tag"
:disabled="disabled"
variant="info"
>{{ tag }}</b-form-tag>
</li>
</ul>
<b-form-select
v-bind="inputAttrs"
v-on="inputHandlers"
:disabled="disabled"
:options="options"
>
<template #first>
<!-- This is required to prevent bugs with Safari -->
<option disabled value="">Choose a tag...</option>
</template>
</b-form-select>
</template>
</b-form-tags>
</b-form-group>
</div>
</template>
</div>
window.onload = () => {
new Vue({
el: '#app',
data() {
return {
options: ['Apple', 'Orange', 'Banana', 'Lime', 'Peach', 'Chocolate', 'Strawberry'],
value: []
}
},
methods: {
tagValidator(tag) {
this.value.push(tag)
return true
}
}
})
}

Template slot in buefy carousel showing broken image

Hi i am newbie in vuejs and buefy. I wanted to do a carousel. However its already printing in the b-carousel-item but in template slot="indicators" it showing broken image. Can anyone help me i want to show the image also in the template slot
this is the code:
https://codesandbox.io/s/wonderful-gagarin-5wc8d?file=/src/App.vue
App.vue
<template>
<b-carousel :indicator-inside="false">
<b-carousel-item v-for="(item, i) in imgurl" :key="i">
<span class="image">
<img :src="getImgUrl(item)" />
</span>
</b-carousel-item>
<template slot="indicators" slot-scope="props">
<span class="al image">
<img :src="getImgUrl(props.item)" :title="props.item" />
</span>
</template>
</b-carousel>
</template>
<script>
export default {
data() {
return {
thumbs: null,
imgurl: [
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTE7e4ENLA4IRiYClFOOyc418WmdNTuWAAX_A&usqp=CAU",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQrMMLeNArJ-NmM-sRGGGr0ya8y0NSF4HZ8Aw&usqp=CAU",
],
};
},
methods: {
getImgUrl(value) {
this.thumbs = value;
return `${value}`;
},
},
};
</script>

bootstrap-vue : how to recognize hover event over b-tab

I'm trying to change the active tab of a bootstrap-vue b-tabs when the tab title is hovered over, not only when clicked on. I'm having trouble isolating this event.
In the following Codepen example, I can isolate the event when the image is being hovered over, however I want to isolate the event when the title ('Tubes and Vials' for example) is being hovered over.
I'm fairly new to Vue so I apologize if this is a simple answer, but I haven't struggled with this for a while now and haven't been able to figure this out. Thanks!
Component File
<template>
<b-container class="px-3" fluid>
<div>
<h3>Range Of Glass Products We Inspect</h3>
<p>Anything formed from tubular glass</p>
</div>
<div>
<b-tabs content-class="mt-3" align="left" class="vial-types" vertical>
<b-tab
v-for="glassItem in productRange"
v-bind:key="glassItem.type"
v-bind:ref="glassItem"
v-bind:title="glassItem.type"
#mouseover.native="greet()"
#mouseleave.native="greet()"
>
<b-img
v-bind:src="glassItem.image"
alt="Factory Image">
</b-img>
</b-tab>
</b-tabs>
</div>
</b-container>
</template>
<script>
export default {
name: "ProductRange",
data() {
return {
productRange: [
{type: "Screw & Flanged Head", image:"https://picsum.photos/600/400/", hover: false},
{type: "Tubes and Vials", image:"https://picsum.photos/600/400/", hover: false},
{type: "Pipettes, Syringes, Filling Needles", image:"https://picsum.photos/400/400/",hover: false},
{type: "Ampoules", image:"https://picsum.photos/600/400/", hover: false},
{type: "Custom Geometries Per Customer Specification", image:"https://picsum.photos/600/400/", hover: false}
]
}
},
methods: {
greet: function () {
console.log("Hovering");
}
}
}
</script>
<style lang="sass">
</style>
You could also use the b-tab's title slot, and then add a hover/unhover listener in there:
<b-tabs content-class="mt-3" align="left" class="vial-types" vertical>
<b-tab
v-for="glassItem in productRange"
v-bind:key="glassItem.type"
v-bind:ref="glassItem"
>
<template v-slot:title>
<div
#mouseover="hovered"
#mouseleave="unHovered"
>
{{ glassItem.type }}
</div>
</template>
<b-img
v-bind:src="glassItem.image"
alt="Factory Image">
</b-img>
</b-tab>
</b-tabs>
Sadly I don't think there's a built-in way to easily do this.
However, you can still solve this by hiding the standard tabs and instead reconstruct the structure yourself using b-nav and binding to the b-tabs v-model.
You can then add your events the b-nav-item as they'll be working as your tabs.
new Vue({
el: "#app",
data: {
selectedTab: 0,
productRange: [
{
type: "Screw & Flanged Head",
image: "https://picsum.photos/600/400/"
},
{
type: "Tubes and Vials",
mage: "https://picsum.photos/640/400/"
},
{
type: "Pipettes, Syringes, Filling Needles",
image: "https://picsum.photos/400/400/"
},
{
type: "Ampoules",
image: "https://picsum.photos/600/400/"
},
{
type: "Custom Geometries Per Customer Specification",
image: "https://picsum.photos/700/400/"
}
]
},
methods: {
greet: function() {
console.log("hovering");
},
onTabHover(glassItem) {
console.log("Tab hovered", glassItem)
}
}
});
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.4.2/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#2.6.10/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.4.2/dist/bootstrap-vue.min.js"></script>
<b-container id="app" class="px-3"fluid>
<div>
<h3>Range Of Glass Products We Inspect</h3>
<p>Anything formed from tubular glass</p>
</div>
<div>
<b-row>
<b-col cols="auto">
<b-nav pills vertical>
<b-nav-item v-for="(glassItem, index) in productRange"
:active="selectedTab === index"
#click="selectedTab = index"
#mouseenter="onTabHover(glassItem)">
{{ glassItem.type }}
</b-nav-item>
</b-nav>
</b-col>
<b-col>
<b-tabs v-model="selectedTab"
content-class="mt-3"
class="vial-types"
nav-class="d-none">
<b-tab
v-for="glassItem in productRange"
:key="glassItem.type"
:ref="glassItem"
:title="glassItem.type"
#mouseover.native="greet()"
#mouseleave.native="greet()"
>
<b-img
:src="glassItem.image"
alt="Factory Image">
</b-img>
</b-tab>
</b-tabs>
</b-col>
</b-row>
</div>
</b-container>

Transition on class change property

I currently have a vue component that I use to select drinks to be ordered.
You can increment or decrement the amount of drinks per type.
There are 2 buttons (Increment and decrement), the decrement button needs to be hidden when the amount of ordered drinks for that type is equal to 0. This can easily be accomplished by using :class="drink.amount > 0 ? 'visible':'invisible'" using the tailwind classes which sets visibility:hidden css property. When using this method it looks like:
Now I tried to implement css animations (sliding the button underneath the drink block to hide it and later hide from dom). I want to implement this using the vue transition component since this is heavily used throughout the application.
Now I have the problem that the vue transition component only works with a limited amount of vue functions among which v-if and v-show. v-if removes the html from the dom. v-show sets the property display:none both of these functions have the effect of shifting the buttons:
I would like to known how I can use the vue transition component and get the requested aligned buttons as I got without the animation.
<div v-for="drink in drinks" class="w-full flex">
<div class="mx-auto flex">
<transition name="transition-slide-right">
<div class="bg-white w-16 h-16 flex justify-center items-center mt-12"
v-show="drink.amount">
<p>-</p>
</div>
</transition>
<div class="bg-brand w-32 h-24 flex justify-center items-center my-8 z-30">
<p>{{drink.name}} ({{drink.amount}})</p>
</div>
<div class="bg-white w-16 h-16 flex justify-center items-center mt-12">
<p>+</p>
</div>
</div>
</div>
And accompanying script.
<script>
export default {
name: "CreateTransaction",
data: function() {
return {
drinks: [
{name: 'Cola', price: '1.0', amount: 1},
{name: 'Sinas', price: '1.0', amount: 0}
],
}
}
}
</script>
Finally the css:
.transition-slide-right-enter-active, .transition-slide-right-leave-active {
transition: transform .5s;
}
.transition-slide-right-enter, .transition-slide-right-leave-to {
transform: translateX(100%);
}
As a current workaround I removed the transition component, added the transition-slide-right-enter-active class and if the count == 0 I conditionally add the transition-slide-right-enter class. This does not hide the element but hiding it is not required since I is moved underneath the center block.
you can try the following code
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div class="row" id="todo-list-example">
<div v-for="(drink,index) in drinks" class="w-full flex">
<transition name="transition-slide-right"><button v-show="drink.amount" type="button" class="btn btn-danger" v-on:click="click1(index)">-</button></transition>
<a class="btn btn-success" >{{drink.name}} ({{drink.amount}})</a>
<button type="button" class="btn btn-danger" v-on:click="click2(index)">+</button>
</div>
</div>
<style>
.w-full{margin:10px 0px;}
.transition-slide-right-enter-active, .transition-slide-right-leave-active {
transition: transform .5s;
}
.transition-slide-right-enter, .transition-slide-right-leave-to {
transform: translateX(100%);
}
</style>
<script>
new Vue({
el: '#todo-list-example',
data(){
return {
drinks: [
{name: 'Cola', price: '1.0', amount: 1},
{name: 'Sinas', price: '1.0', amount: 1}
],
}
},
methods:{
click1:function(index){
this.drinks[index].amount=this.drinks[index].amount-1;
},
click2:function(index){
this.drinks[index].amount=this.drinks[index].amount+1;
}
}
})
</script>