Is it possible to set actions call a function at default pagination of v-data-table? - datatable

I would like to call a function when I click the previous button, next button and the rowsPerPage numbers are changed.
Is it possible to use default v-data-table pagination when I use actions-prepend slot?
I tried but it seems not working.
<template>
<v-data-table
:headers="headers"
:items="alertList"
:pagination.sync="pagination"
:rows-per-page-items="pagination.rowsPerPageItems"
:total-items="pagination.totalCount"
:loading="paginationLoading"
class="elevation-1 block_display"
>
<template v-slot:items="props">
<td class="text-xs-left">{{ props.item.id }}</td>
...
</template>
<template v-slot:actions-prepend> // add another button before the default pagination
<v-btn #click='goPrev'> < </btn>
</template>
</v-data-table>
</template>
<script>
export default {
data() {
....
},
methods: {
goPrev() {
// want to call vuex actions
}
}
}
</script>

I got an answer which would be better or not.
<template>
<v-data-table
:headers="headers"
:items="alertList"
:pagination.sync="cstPagination"
:rows-per-page-items="pagination.rowsPerPageItems"
:total-items="pagination.totalCount"
:loading="paginationLoading"
class="elevation-1 block_display"
>
<template v-slot:items="props">
<td class="text-xs-left">{{ props.item.id }}</td>
...
</template>
</v-data-table>
</template>
<script>
export default {
data() {
....
},
computed: {
get() {
return this.pagination // props
},
set(val) {
// val: changed pagination value
}
}
}
</script>

Related

what am I doing wrong by passing a prop from the parent to the child in vue if it only works in the template side?

So i am trying to do a basic WebSocket notification system. I am passing the user as a prop from App.vue to the navbar component. it Can be shown in the template but when I try to call it in the script section. it says undefined.You can take a look at this picture, it shows the id shown in the navbar and when I try to console.log it, it says undefined.
Here is my App.vue "The parent"
<template lang="">
<div>
<v-app>
<template v-if="isLoggedIn">
<AdminMenu></AdminMenu>
</template>
<template v-else-if="!isUserLoggedIn">
<Nav></Nav>
</template>
<template v-if="isUserLoggedIn">
<Navbar :user='user.id'></Navbar>
</template>
<v-main app>
<router-view></router-view>
</v-main>
</v-app>
</div>
</template>
<script>
import 'vuetify/dist/vuetify.min.css' // Ensure you are using css-loader
import axios from 'axios';
import AdminMenu from './layouts/AdminMenu.vue'
import Navbar from './layouts/user/Navbar.vue'
import Nav from './layouts/user/Nav.vue'
export default {
name:'app',
components:{ 'AdminMenu': AdminMenu, 'Navbar':Navbar, 'Nav':Nav},
data(){
return{
user:[],
isLoggedIn: false,
isUserLoggedIn: false,
}
},
created() {
if (window.Laravel.isLoggedin) {
this.isLoggedIn = true
}
if (window.Laravel.isUserLoggedin) {
this.isUserLoggedIn = true
}
},
mounted(){
this.axios.get('/api/user').then(response=>{
this.user = response.data
}).catch(error=>{
console.log(error)
})
},
}
</script>
Here is the child
<template lang="">
<div>
<v-toolbar app dark>
<span class="hidden-sm-and-up">
<v-toolbar-side-icon #click="sidebar = !sidebar">
</v-toolbar-side-icon>
</span>
<v-toolbar-title>
<router-link to="/" tag="span" style="cursor: pointer">
{{ appTitle }}
</router-link>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items class="hidden-xs-only">
<v-btn
text
v-for="item in menuItems"
:key="item.title"
:to="item.path">
{{ item.title }}
</v-btn>
<v-btn flat icon color="primary" disabled>
<v-icon></v-icon>{{user}}
</v-btn>
<v-btn #click="logout">Logout</v-btn>
</v-toolbar-items>
</v-toolbar>
</div>
</template>
<script>
export default {
name: "nav",
props:['user'],
data(){
return {
appTitle: 'My template',
sidebar: false,
menuItems: [
{ title: 'Home', path: '/home', icon: 'home' },
{ title: 'Profile', path: '/profile', icon: 'face' },
]
}
},
created(){
console.log(this.user)
},
methods: {
logout(e) {
console.log('ss')
e.preventDefault()
this.axios.get('/sanctum/csrf-cookie').then(response => {
this.axios.post('/api/logout')
.then(response => {
if (response.data.success) {
window.location.href = "/"
} else {
console.log(response)
}
})
.catch(function (error) {
console.error(error);
});
})
},
},
};
</script>
<style lang="">
</style>
First of all define your user in data() with default values so you should not recieve undefined error Moreover there is no async/await when you are calling api in the mounted state
App.vue
<template>
<div>
<v-app>
<template v-if="isLoggedIn">
<AdminMenu></AdminMenu>
</template>
<template v-else-if="!isUserLoggedIn">
<Nav></Nav>
</template>
<template v-if="isUserLoggedIn">
<Navbar :user='user.id'></Navbar>
</template>
<v-main app>
<router-view></router-view>
</v-main>
</v-app>
</div>
</template>
<script>
import 'vuetify/dist/vuetify.min.css' // Ensure you are using css-loader
import axios from 'axios';
import AdminMenu from './layouts/AdminMenu.vue'
import Navbar from './layouts/user/Navbar.vue'
import Nav from './layouts/user/Nav.vue'
export default {
name:'app',
components:{ 'AdminMenu': AdminMenu, 'Navbar':Navbar, 'Nav':Nav},
data(){
return{
user:[],
isLoggedIn: false,
isUserLoggedIn: false,
}
},
created() {
if (window.Laravel.isLoggedin) {
this.isLoggedIn = true
}
if (window.Laravel.isUserLoggedin) {
this.isUserLoggedIn = true
}
},
async mounted(){
await this.axios.get('/api/user').then(response=>{
this.user = response.data
}).catch(error=>{
console.log(error)
})
},
}
</script>

VueDraggable and Laravel

I'm confused as how to correctly use vueDraggable together with Laravel.
I can drag and sort the elements in the browser but the array is not changing (when I check in the console)/ it seems to me the changes aren't reflected in the array. Shouldn't the array index numbers change after moving items?
In the overview.blade.php I have the component:
<qm-draggable :list="{{ $mylaravelarray }}"></qm-draggable>
In the qm-draggable.vue I have:
<template>
<draggable group="fragenblatt" #start="drag=true" #end="endDrag" handle=".handle">
<li v-for="(item, index) in draggablearray" :key="item.index">
// list items here
</li>
</draggable>
</template>
<script>
data() {
return {
draggablearray:{},
};
},
props: {
list: Array,
},
mounted: function(){
this.draggablearray = this.list; // create a new array so I don't alter the prop directly.
},
[..]
</script>
In the documentation it says, one way to pass the array is:
value
Type: Array
Required: false
Default: null
Input array to draggable component. Typically same array as referenced by inner element v-for directive.
This is the preferred way to use Vue.draggable as it is compatible with Vuex.
It should not be used directly but only though the v-model directive:
<draggable v-model="myArray">
But where do I do that? in overview.blade.php or in the component (.vue), or both?
Try setting v-model on your draggable as that's what will update draggablearray.
Also if draggablearray is supposed to be an array, initialise it as one, so draggablearray:{} should be draggablearray:[].
new Vue({
el: '#app',
data: () => {
return {
drag: false,
draggablearray: [{
id: 1,
name: "1"
}, {
id: 2,
name: "2"
}, {
id: 3,
name: "3"
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">
</script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs#1.7.0/Sortable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.16.0/vuedraggable.min.js"></script>
<div class="container">
<div id="app">
<draggable v-model="draggablearray" group="fragenblatt">
<li v-for="(item, index) in draggablearray">
{{item.name}}
</li>
</draggable>
{{draggablearray}}
</div>
</div>
<script type="text/x-template" id="tree-menu">
<div class="tree-menu">
<div class="label-wrapper">
<div :style="indent" :class="labelClasses" #click.stop="toggleChildren">
<i v-if="nodes" class="fa" :class="iconClasses"></i>
<input type="checkbox" :checked="selected" #input="tickChildren" #click.stop /> {{label}}
</div>
</div>
<draggable v-model="nodes" :options="{group:{ name:'g1'}}">
<tree-menu v-if="showChildren" v-for="node in nodes" :nodes="node.nodes" :label="node.label" :depth="depth + 1" :selected="node.selected" :key="node">
</tree-menu>
</draggable>
</div>
</script>
Ah, I solved it, now I get the altered array back, I achieved it with this:
Had to add v-model="draggablearray" in the component .vue file
Needed to change my 'draggablearray' in data to an Array, instead of
object.
It looks like this now:
In the overview.blade.php I have the component:
<qm-draggable :list="{{ $mylaravelarray }}"></qm-draggable>
In the qm-draggable.vue I have:
<template>
<draggable v-model="draggablearray" group="fragenblatt" #start="drag=true" #end="endDrag" handle=".handle">
<li v-for="(item, index) in draggablearray" :key="item.index">
// list items here
</li>
</draggable>
</template>
<script>
data() {
return {
draggablearray:[], //has to be an Array, was '{}' before
};
},
props: {
list: Array,
},
mounted: function(){
this.draggablearray = this.list; // create a new array so I don't alter the prop directly.
},
[..]
</script>

Vuetify Snackbar leave event

I manage to implement a global Vuetify Snackbar.
My problem is to detect when the snackbar close. I read that this component support Vue transition event since 1.2. But it work only on the enter event not the leave ones.
here a fiddle for comprehension.
<transition #before-enter="beforeEnter" #before-leave="beforeLeave" #after-enter="afterEnter" #after-leave="afterLeave" #leave="leave">
<v-snackbar v-model="snackbar" top right>
Hello
<v-btn #click="snackbar = false" dark>Close</v-btn>
</v-snackbar>
</transition>
I faced the same problem and solved this way:
export default {
data: () => ({
errorMessage: '',
snackTimeout: 6000,
}),
watch: {
errorMessage() {
setTimeout(() => {
this.clearErrorMessage();
}, this.snackTimeout);
},
},
methods: {
setErrorMessage(message) {
this.snackMessage = message;
},
clearErrorMessage() {
this.snackMessage = '';
},
},
};
<template>
<v-snackbar
:value="errorMessage"
:timeout="snackTimeout"
top
>
{{ errorMessage }}
<v-btn
color="error"
flat
#click.stop="clearErrorMessage"
>
{{ 'close' }}
</v-btn>
</v-snackbar>
</template>
Define an attribute with the timeout and another with the message to show by the snackBar.
Define a function to set the message and another to clear it.
Define a watch for the message text and set a timer with the same timeout of the snackBar to clear it.
The snackBar appears only when the message is not empty.
You can use get and set methods to handle reading and updating the bound model separately.
I made a generic snackbar component that can be triggered from any other component. I'm using Vuex, vue-property-decorator and typescript here, so adjust accordingly.
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<template>
<v-snackbar v-model="snackbar" max-width="100%">
<template v-slot:action="{ attrs }">
{{ text }}
<v-btn color="primary" text fab v-bind="attrs">
<v-icon dark #click="close()"> mdi-close-circle-outline </v-icon>
</v-btn>
</template>
</v-snackbar>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
#Component({})
export default class Snackbar extends Vue {
get snackbar() {
return this.$store.state.snackbar.show
}
set snackbar(show: boolean) {
this.$store.dispatch('updateSnackbar', { show, text: '' })
}
get text() {
return this.$store.state.snackbar.text
}
public close() {
this.$store.dispatch('updateSnackbar', { show: false, text: '' })
}
}
</script>

Expand all data table entries at once in VuetifyJS/VueJS

How to expand all entries of this VuetifyJS/VueJS data table example at once and not only one at the time?
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
hide-actions
item-key="name"
expand
>
<template slot="items" slot-scope="props">
<tr #click="props.expanded = !props.expanded">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.calories }}</td>
<td class="text-xs-right">{{ props.item.fat }}</td>
</tr>
</template>
<template slot="expand" slot-scope="props">
<v-card flat>
<v-card-text>Peek-a-boo!</v-card-text>
</v-card>
</template>
</v-data-table>
</v-app>
</div>
Here is an example for a single expand:
https://codepen.io/anon/pen/yEWNxE?&editors=101#
There is an open-issue with regards to this feature, make sure to follow it and get notified when it's resolved.
Temporary solution by #zikeji follows:
Add reference to the table:
<v-data-table ref="dTable">
Expand rows manually when component loads:
mounted() {
for (let i = 0; i < this.desserts.length; i += 1) {
const item = this.desserts[i];
this.$set(this.$refs.dTable.expanded, item.name, true);
}
},
Codepen
in Veutify v2.1.13
Just copied data to expanded from dessertson click.
methods: {
expandAll: function() {
console.log("All expanded.");
this.$data.expanded = this.$data.desserts;
},
collapseAll: function() {
console.log("All collapsed.");
this.$data.expanded = [];
}
},
codepen
You should extend the component instead and set the values as such.
MyVDataTable.vue
<script>
import VDataTable from 'vuetify/src/components/VDataTable'
export default {
extends: VDataTable,
props: ['deserts'],
mounted () {
for (let i = 0; i < this.desserts.length; i += 1) {
const item = this.desserts[i];
this.$set(this.expanded, item.name, true);
}
}
}
Then you would replace your VDataTable with this one.
For me the above and other solutions found on google were not working. So i created another approach.
To the row where you usually add your #click expand function you have to add a custom directive.
for example v-open
and pass your props.
<tr #click="props.expanded = !props.expanded" v-open="props">
then inside your component
directives: {
open: {
// directive definition
bind: function (el,binding) {
//only the first row
if( binding.value.index === 0){
binding.value.expanded = true
}
//or all rows
//binding.value.expanded = true
}
}
},

Vue Multiselect not displaying

I am trying to use Vue Multiselect V2 in my Laravel 5.3 project. I am using this example, http://monterail.github.io/vue-multiselect/#sub-single-select
I have the following setup, in my app.js file:
Vue.component('multiselect', require('./components/Multiselect.vue'));
var vm = new Vue({
el: '#app'
});
In the Multiselect.vue file
<script>
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
data () {
return {
value: '',
options: ['Select option', 'options', 'selected', 'mulitple', 'label', 'searchable', 'clearOnSelect', 'hideSelected', 'maxHeight', 'allowEmpty', 'showLabels', 'onChange', 'touched']
}
}
}
</script>
And I am calling it in the blade as below:
<div id="app">
<label class="typo__label">Single select</label>
<multiselect v-model="value" :options="options" :searchable="false" :close-on-select="false" :show-labels="false" placeholder="Pick a value"></multiselect>
<pre class="language-json"><code>#{{ value }}</code></pre>
</div>
This is how it displays in the DOM
<div id="app">
<label class="typo__label">Single select</label>
<!---->
<pre class="language-json"><code></code></pre>
</div>
Currently the dropdown does not display, and I don't see any errors in the console. I would have expected to add a template in somewhere but I couldn't find any mention of that in the Vue Multiselect docs.
For anyone having these issues, do not follow the examples on the official documentation. They do not work, rather use this from their Github page. https://github.com/monterail/vue-multiselect/tree/2.0#install--basic-usage
Basic example
<template>
<div>
<multiselect
v-model="selected"
:options="options">
</multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: { Multiselect },
data () {
return {
selected: null,
options: ['list', 'of', 'options']
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
For updating the array from vue multiselect use #select and #remove events
Example: <multiselect #select="selectionChange" #remove="removeElement"> </multiselect>
Into methods add the next functions
methods: {
removeElement() {
this.$forceUpdate();
},
selectionChange() {
this.$forceUpdate();
},
}
this.$forceUpdate(); will update the state.

Resources