Vue 3 cli-service app: "Slot "default" invoked outside of the render function" warning when component with slots is imported from other component - vue.js

MCVE
I have a Tabpane component that takes slots as input. When imported from the template it works as expected.
<Tabpane>
<div caption="I am div 1">Div 1</div>
<div caption="I am div 2">Div 2</div>
</Tabpane>
However when imported from an other component ( Composite in the example ), then it triggers the following warning:
Slot "default" invoked outside of the render function:
this will not track dependencies used in the slot. Invoke the slot function inside the render function instead.
// src/components/Composite.js
import { defineComponent, h } from "vue";
import Tabpane from "./Tabpane.vue";
export default defineComponent({
name: "Composite",
setup() {
const slots = [
h("div", { caption: "I am div 1" }, ["Div 1"]),
h("div", { caption: "I am div 2" }, ["Div 2"])
];
return () => h(Tabpane, {}, () => slots);
}
});

Solved.
The problem was that I called slots.default() from within setup, but not within the returned render function.
Also this component reflected a very beginner approach to reactivity. By now I know better. The old problematic solution is still there in src/components/Tabpane.vue.
The right solution that triggers no warning is:
// src/components/Tabpane2.vue
<script>
import { defineComponent, h, reactive } from "vue";
export default defineComponent({
name: "Tabpane2",
props: {
width: {
type: Number,
default: 400,
},
height: {
type: Number,
default: 200,
},
},
setup(props, { slots }) {
const react = reactive({
selectedTab: 0,
});
return () =>
h("div", { class: ["vertcont"] }, [
h(
"div",
{
class: ["tabs"],
},
slots.default().map((tab, i) =>
h(
"div",
{
class: {
tab: true,
selected: i === react.selectedTab,
},
onClick: () => {
react.selectedTab = i;
},
},
[tab.props.caption]
)
)
),
h(
"div",
{
class: ["slotscont"],
style: {
width: `${props.width}px`,
height: `${props.height}px`,
},
},
slots.default().map((slot, i) =>
h(
"div",
{
class: {
slot: true,
active: react.selectedTab === i,
},
},
[slot]
)
)
),
]);
},
});
</script>
<style>
.tab.selected {
background-color: #efe;
border: solid 2px #afa !important;
border-bottom: transparent !important;
}
.tab {
background-color: #eee;
}
.tabs .tab {
padding: 5px;
margin: 2px;
border: solid 2px #aaa;
border-radius: 8px;
border-bottom: transparent;
cursor: pointer;
user-select: none;
transition: all 0.5s;
color: #007;
}
.tabs {
display: flex;
align-items: center;
margin-left: 5px;
}
.vertcont {
display: flex;
flex-direction: column;
margin: 3px;
}
.slotscont {
position: relative;
overflow: scroll;
padding: 5px;
border: solid 1px #777;
}
.slot {
visibility: hidden;
position: absolute;
}
.slot.active {
visibility: visible;
}
</style>

Slots need to be invoked within the render function and or the <template> box to ensure they keep their reactivity.
A full explanation can be found in this post: https://zelig880.com/how-to-fix-slot-invoked-outside-of-the-render-function-in-vue-3

Related

how to set a trey of letters`style differently in a v-for loop?

It is similar to the question of whose URL I`ll put below but with one difference, I want not one letter or word style conditionally presented but a trey of letters, I wish all the letters to be in
a different color, is there any solution to it?
the tricky thing is the v-for loop based on an array whose length is not constant.
Change the style of a substring in a v-for loop
example:
I want this input tag letters full of different random colored letters
here is the full code:
<template>
<div
class="nice-input"
:class="{'nice-input--shaked': animated, 'nice-input--caret': !caret}"
>
<input
:id="id !== undefined ? id : 'input-'+name"
v-model="value"
type="text"
:name="name"
autocomplete="off"
>
<label :for="id !== undefined ? id : 'input-'+name">
<span v-for="word in arr" :key="word.sa" class="nice-input__animate"
:style="randomColor">{{ word }}</span>
</label>
</div>
</template>
<script>
export default {
name: 'weirdInput',
props: ['name', 'id'],
data () {
return {
animated: false,
caret: true,
value: '',
randomColor: '#000000',
}
},
computed: {
arr: function () {
return this.value.split('')
},
},
watch: {
value: {
handler: function (after, before) {
const self = this
this.caret = false
if (after.length > before.length) {
if (this.value.slice(-1) === ' ') return false
setTimeout(function () {
self.animated = true
setTimeout(function () {
self.animated = false
self.caret = true
}, 300)
}, 750)
}
this.randomColor = 'color: #' + Math.floor(Math.random() * 16777215).toString(16)
},
},
},
}
</script>
<style scoped>
.nice-input {
position: relative;
}
.nice-input input {
border:none;
border-radius:4px;
padding:7px 10px;
font-family: 'Lato', sans-serif;
font-size:14px;
box-shadow: rgba(0,0,0,.05) 0 5px 20px;
letter-spacing:0;
width:1000px;
color: transparent;
font-weight:900;
caret-color: #555;
}
.nice-input input:focus {
outline:none;
box-shadow: rgba(0,0,0,.1) 0 5px 20px;
}
.nice-input label {
position: absolute;
top: 6px;
left: 10px;
letter-spacing:0;
font-size:0;
}
.nice-input span {
font-family: 'Lato', sans-serif;
font-size:14px;
font-weight:900;
}
.nice-input__animate {
animation: print .75s 1 ease-in-out;
}
.nice-input--shaked {
animation: shake .2s 1 ease-in-out;
}
.nice-input--caret {
caret-color: transparent;
}
#keyframes print {
from{
position:absolute;
transform: scale(100);
}
99% {
position:absolute;
}
to {
position:relative;
}
}
#keyframes shake {
from,
to {
}
50% {
transform:scale(0.97);
}
}
</style>

v-if not working for single File template

So I have the following Vue app
App.vue
<template id="main-page">
<v-ons-page>
<l-map
ref="map"
v-if="showMap"
:zoom="zoom"
:center="center"
:options="mapOptions"
style="height: 100%"
#update:center="centerUpdate"
#update:zoom="zoomUpdate"
#update:bounds="boundUpdate"
#move="move"
>
<l-tile-layer
:url="url"
:attribution="attribution"
/>
<l-marker
v-if="addNewMarker"
:lat-lng="liveCenter"
>
<l-icon
:icon-size="dynamicSize"
:icon-anchor="dynamicAnchor"
icon-url="https://cdn3.iconfinder.com/data/icons/metro-explorer/512/my_location-512.png"
/>
</l-marker>
<l-marker
v-for="marker in markers"
:key="marker.id"
:visible="marker.visible"
:draggable="marker.draggable"
:lat-lng.sync="marker.position"
#click="alert(marker)"
>
</l-marker>
<l-control class="example-custom-control"
:position="'bottomright'">
<img
#click="showAddMarkerSetup"
src="https://cdn4.iconfinder.com/data/icons/iconsimple-places/512/pin_plus-512.png"
height="42" width="42"
>
</l-control>
</l-map>
<Cancel v-if="addNewMarker"/>
<Ok v-if="addNewMarker"/>
</v-ons-page>
</template>
<style>
.example-custom-control {
background: #fff;
padding: 0 0.5em;
border: 1px solid #aaa;
border-radius: 0.1em;
}
.ok {
position: absolute;
bottom: 20px;
right: 30%;
width: 100px;
height: 50px;
z-index:999;
background: #000;
color: white;
opacity: 0.5;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<script>
import { latLng } from "leaflet";
import {
LMap,
LTileLayer,
LMarker,
LControl,
LIcon
} from "vue2-leaflet";
import Cancel from './components/add/Cancel'
import Ok from './components/add/Ok'
export default {
name: "Example",
components: {
LMap,
LTileLayer,
LMarker,
LControl,
LIcon,
Cancel,
Ok
},
data() {
return {
zoom: 18,
center: latLng(14.601205, 120.974780),
url: 'https://api.test.goxhere.com/place-geoserver/geoserver/gwc/service/gmaps?layers=postgis:goxhere&zoom={z}&y={y}&x={x}&format=image/png',
attribution:
'© GoXhere',
withPopup: latLng(14.601205, 120.974780),
withTooltip: latLng(14.601205, 120.974980),
currentZoom: 11.5,
currentCenter: latLng(14.5905, 120.9781),
liveCenter: latLng(14.601205, 120.974780),
showParagraph: false,
mapOptions: {
zoomSnap: 0.5,
zoomControl: false
},
showMap: true,
markers: [],
addNewMarker: false,
dynamicSize: [32, 32],
dynamicAnchor: [32, 32]
};
},
methods: {
zoomUpdate(zoom) {
this.currentZoom = zoom;
},
centerUpdate(center) {
this.currentCenter = center;
},
showLongText() {
this.showParagraph = !this.showParagraph;
},
innerClick() {
alert("Click!");
},
showAlert() {
alert("Click!");
},
showAddMarkerSetup() {
console.log('showAddMarkerSetup clicked')
console.log('adding a marker at the center')
this.addNewMarker = !this.addNewMarker
},
boundUpdate() {
console.log('bound update')
// check if
},
move(e) {
console.log('map moving')
if (this.addNewMarker) {
this.liveCenter = e.target.getCenter()
}
}
}
};
</script>
Here is my Cancel.vue component
<template>
<div class="cancel">Cancel</div>
</template>
<style scoped>
.cancel {
position: absolute;
bottom: 20px;
left: 30%;
width: 100px;
height: 50px;
z-index:999;
background: #000;
color: white;
opacity: 0.5;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<script>
export default {
data() {
return {
"a": "sss"
}
},
methods: {
mounted() {
console.log('mounted from cancel')
}
}
}
</script>
If I set the addNewMarker field to true, the Cancel component does not appear in the UI (even though I can see its being added in Vue component console)
However, if I use v-show instead of v-if, I can see the Cancel component showing on and off if I toggle the addNewMarker. Is there anything I should configure so that v-if works correctly for single file templates?
Here is a video demo showing v-if (not working) and v-show (working)

Nuxt / Vuex / Vue Reactivity Issue Increment

Hi everyone I am I having some difficulty when working with Nuxt and Vuex.
I am trying to run through the example Vuex / Nuxt Classic Mode.
https://nuxtjs.org/guide/vuex-store/
After clicking my increment button I dont see the number go up. My page just stays at 0, I can see within the console that the state knows the number is no longer 0 but not on the screen, as if it doesnt know to be reactive.
My assumption is that I have miss configured something somewhere and my 0 is not the actual state, but I created some copy of it somehow.
Here is my button within my template.
<button #click="inc">{{ counter }}</button>
Here is my inc function within my methods.
inc () {
this.$store.commit('increment')
},
Here is my computed
computed: {
counter () {
return this.$store.getters.counter
}
}
Here is my Vuex/index.js file contained within the store folder.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
getters: {
counter: state => state.counter
},
mutations: {
increment (state) {
state.counter++
}
}
})
}
export default createStore
Update: Included more code snippets, and replied to existing comments.
#Boussadjra Brahim #xaviert, thank you both for weighing in, I appreciate the assistance.
#Boussadjra Brahim - Yes, I had tried using an action that called the mutation, that didnt seem to get me there either. I also tried adjusting the state via the action alone, and wasnt able to make any changes, however that seems correct, as I am under the impression that actions call mutations to make state changes and do not themselves do so, please correct me if you know more. I am 100% open to the idea that I did not attempt it correctly. Below is that action that didnt do anything and the one that called the mutation
actions: {
increment (state) {
state.counter++
}
},
And here is the version with the action calling the mutation.
actions: {
incrementCounterUp () {
this.commit('increment')
}
},
#xaviert - I have tried starting the server over, and have also tried to see if an nuxt build followed by a firebase serve, to see if maybe that helped. It did not. My normal server start is 'npm run dev'. In hopes that you/anyone else may be able to find my mistake below is my full _id.vue component and also my nuxt.config.js file as maybe that's it. Its still pretty raw and could use a lot of refactoring so hope you can sort through it well enough.
_.id.vue
<template>
<div class="product">
<div class="product-image">
<div class="product-image-img">
<img v-bind:src="product.image_file" width="450px;"/>
</div>
</div>
<div class="product-details-wrapper">
<div class="product-details">
<h1>
<div v-if="this.$route.query.editPage">
<textarea #input="updateTextArea" ref="textarea2" v-model="product.item_name" type="text" />
</div>
<div v-else>{{product.item_name}}</div>
</h1>
<div class="product-description">
<div class="product-description-text" v-if="this.$route.query.editPage">
<textarea #input="updateTextArea" ref="textarea" v-model="product.description" type="text" />
</div>
<div class="product-description-text" v-else v-html="product.description"></div>
</div>
<p class="product-brand"><strong>Brand - </strong> {{product.brand_name}}</p>
<hr />
<div class="product-price">
<div v-if="this.$route.query.editPage">
<strong>Original Price - </strong>
<input v-model="product.msrp" type="text" />
</div>
<div v-else class="product-msrp">
<strong>Original Price - </strong>
<span class="strike">${{product.msrp}}</span>
</div>
<div v-if="this.$route.query.editPage">
<strong>Sale Price - </strong>
<input v-model="product.price" type="text" />
</div>
<div v-else class="product-sale-price">
<strong>Sale Price - </strong>
<span class="">${{product.price}}</span>
</div>
<div class="product-price">
Quantity x
<input #input="updateQuantity" v-model="quantity" min="1" class="" type="number" value="1" />
</div>
<button #click="inc">{{ counter }}</button>
</div>
</div>
</div>
<div v-if="this.$route.query.editPage" class="update-product"> <button #click="updateProduct(product)">Update</button></div>
<div class="footer">
<router-link to="/privacy-policy" target="_blank">Privacy</router-link> |
<router-link to="/terms" target="_blank">Terms</router-link>
</div>
</div>
</template>
<script>
// # is an alias to /src
import firebase from '#/services/fireinit'
import foo from '#/components/foo'
const db = firebase.firestore()
export default {
name: 'ProductPage',
head () {
return {
title: this.product.item_name
}
},
components: {
foo
},
data: function () {
return {
product: {},
image: '',
name: 'Checkout',
description: '',
currency: 'USD',
amount: '',
msrp: '',
quantity: 1
}
},
methods: {
inc () {
this.$store.dispatch('incrementCounterUp', true)
},
updateProduct: function (product) {
db.collection('products').doc(product.item_id).set(product)
.then(function () {
console.log('Document successfully written!')
})
.catch(function (error) {
console.error('Error writing document: ', error)
})
},
updateQuantity () {
this.product.msrp = (this.quantity * this.product.orgMsrp)
this.product.msrp = Math.round(100 * this.product.msrp) / 100
this.product.price = this.quantity * this.product.orgPrice
this.product.price = Math.round(100 * this.product.price) / 100
},
updateTextArea () {
this.$refs.textarea.style.minHeight = this.$refs.textarea.scrollHeight + 'px'
this.$refs.textarea2.style.minHeight = this.$refs.textarea2.scrollHeight + 'px'
}
},
async asyncData({app, params, error}) {
const ref = db.collection("products").doc(params.id)
let snap
let thisProduct = {}
try {
snap = await ref.get()
thisProduct = snap.data()
thisProduct.orgMsrp = thisProduct.msrp
thisProduct.orgPrice = thisProduct.price
} catch (e) {
// TODO: error handling
console.error(e)
}
return {
product: thisProduct
}
},
mounted () {
if(this.$refs.textarea) {
this.$refs.textarea.style.minHeight = this.$refs.textarea.scrollHeight + 'px'
this.$refs.textarea2.style.minHeight = this.$refs.textarea2.scrollHeight + 'px'
}
},
computed: {
counter () {
return this.$store.getters.counter
}
}
}
</script>
<style lang="less">
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin: 0
}
p{
margin-top: 1em;
margin-bottom: 1em;
}
html, body, #__nuxt, #__layout, .default, .product{
height: 100%;
}
.product {
justify-content: center;
display: flex;
max-width: 1150px;
margin: 0 auto;
flex-wrap: wrap;
align-items: center;
padding: 0 24px;
&-price{
input {
border: 1px solid;
padding: 0 .3em;
text-align: center;
width: 50px;
}
}
}
.product-details{
width: 100%;
textarea {
width: 100%;
font-size: inherit;
color: inherit;
font-family: inherit;
font-weight: inherit;
height: initial;
resize: none;
background-color: transparent;
border: none;
}
h1{
font-size: 1.9rem;
margin: 15px 0 20px;
}
hr{
width: 50%;
margin: .5rem 0px;
}
p{
}
}
.product-description-text{
margin: 10px 0;
}
.product-image, .product-details-wrapper{
align-items: center;
display: flex;
justify-content: center;
}
.product-details-wrapper{
flex: 0 1 535px;
}
.product-image{
flex: 0 1 535px;
img{
width: 100%;
}
}
.product-price{
.strike{
text-decoration: line-through;
}
button{
display: flex;
width: 150px;
height: 50px;
border-radius: 5px;
justify-content: center;
font-size: 24px;
margin-top: 20px;
&:hover{
cursor: pointer;
background-color: #f1f1f1;
box-shadow: 3px 3px 11px -1px rgba(0, 0, 0, 0.48);
}
}
}
.product-sale-price{
color: #f30000;
}
.footer {
flex: 1 1 100%;
text-align: center;
color: #ccc;
margin-top: 25px;
padding: 15px;
a {
color: #ccc;
text-decoration: none;
&:hover{
text-decoration: underline;
}
}
}
.update-product{
position: absolute;
top: 0;
text-align: center;
}
</style>
nuxt.confgs.js
const pkg = require('./package')
const { STRIPE_TOKEN } = process.env;
module.exports = {
vue: {
config: {
productionTip: false,
devtools: true
}
},
buildDir: './functions/nuxt',
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: pkg.name,
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
],
/*
** Plugins to load before mounting the App
*/
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://github.com/nuxt-community/axios-module#usage
'#nuxtjs/axios',
'nuxt-stripe-module'
],
stripe: {
version: 'v3',
publishableKey: 'pk_test_XXX',
},
/*
** Axios module configuration
*/
axios: {
// See https://github.com/nuxt-community/axios-module#options
},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
publicPath: '/public/',
vendor: [],
extractCSS: true,
bable: {
presets: [
'es2015',
'stage-8'
],
plugins: [
['transform-runtime', {
'polyfill': true,
'regenerator': true
}]
]
},
extend (config, { isDev }) {
if (isDev && process.client) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
},
router: {
middleware: 'router-auth'
}
},
plugins: [
{ src: '~/plugins/fireauth', ssr: true }
]
}
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
actions: {
incrementCounterUp () {
this.commit('increment')
}
},
getters: {
counter: state => state.counter
},
mutations: {
increment (state) {
state.counter++
}
}
})
}
export default createStore
At the end of the day, I was not able to identify exactly what in my application was the error.
I assume that my during my initialization, configuration or development I touched something that should not have been touched, installed something that should not have be installed, messed with a package I should not have or was to bold in my nuxt.config.js changes.
I created a new nuxt app following the same install instructions. https://nuxtjs.org/guide/installation/
Moved the above _id.vue component exactly as it is and once I got dependencies updated it worked perfectly as seen in the image below.
Thank you very much #Boussadjra Brahim, #xaviert, #Andrew1325 for you assistance.

Unexpected behaviour removing a child component (row)

Description:
I have a table with some products, each row is a custom vue <row> component.
Each element has a closing (removing) button that triggers the custom "remove" event. The main app listens to this event and removes the children (by index)
The row a part from some static text it contains an input with a number.
The problem:
The parent (Vue app) removes the row, but the value of the input is then moved (and replaces its previous value) to the input in the next row.
Expected behaviour:
I want to simply remove the item I do not care about the value of the text input once it's removed. It should not move its value to the next sibling.
I attach an example.
let row = Vue.component('row', {
name: 'row',
props: ['number', 'name', 'sq'],
data: () => ({
quantity: 0
}),
template: '<tr>' +
'<td>{{number}}</td>' +
'<td>{{name}}</td>' +
'<td><button v-on:click="quantity--">-</button><input type="text" :value="quantity"><button v-on:click="quantity++">+</button></td>' +
'<td><button v-on:click="remove">×</button></td>' +
'</tr>',
methods: {
remove: function() {
this.$emit('remove', this.quantity)
}
},
beforeMount() {
this.quantity = this.sq
}
})
new Vue({
el: "#app",
data: {
out: [],
rows: [{
name: "Icecream",
sq: 0
},
{
name: "Sugar cube",
sq: 50
},
{
name: "Peanut butter",
sq: 0
},
{
name: "Heavy cream",
sq: 0
},
{
name: "Cramberry juice",
sq: 0
}
]
},
methods: {
removeRow: function(index, quantity) {
this.out.push(`Removing row ${index} (${this.rows[index].name} | ${quantity} units)`)
this.rows.splice(index, 1)
}
},
computed: {
log: function() {
return this.out.join("\r\n")
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
h2 {
font-weight: bold;
margin-bottom: 10px;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
td {
padding: 4px 5px;
}
input {
width: 40px;
text-align: center;
}
h4 {
margin-top: 20px;
margin-bottom: 5px;
}
#log {
padding: 10px;
background: #20262E;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<h2>Cart:</h2>
<table>
<row v-for="(row, index) in rows" :number="index" :name="row.name" :sq="row.sq" v-on:remove="removeRow(index, $event)"></row>
</table>
<h4>Log</h4>
<pre id="log" v-html="log"></pre>
</div>
As #Bert mentioned in the comments.
The problem was that I was missing a key.
https://v2.vuejs.org/v2/api/#key
Adding it solved the problem
Thanks

vuejs2 event listening not working

I am following this tutorial https://github.com/ratiw/vuetable-2-tutorial and trying to develop my laravel admin panel using vuejs.
Filter in the list vue is not working
This is my list.vue
<template>
<div>
<filter-bar></filter-bar>
<vuetable ref="vuetable"
api-url="/api/category/list"
:fields="fields"
pagination-path=""
:css="css.table"
:sort-order="sortOrder"
:multi-sort="true"
detail-row-component="my-detail-row"
:append-params="moreParams"
#vuetable:cell-clicked="onCellClicked"
#vuetable:pagination-data="onPaginationData"
></vuetable>
<div class="vuetable-pagination">
<vuetable-pagination-info ref="paginationInfo"
info-class="pagination-info"
></vuetable-pagination-info>
<vuetable-pagination ref="pagination"
:css="css.pagination"
:icons="css.icons"
#vuetable-pagination:change-page="onChangePage"
></vuetable-pagination>
</div>
</div>
</template>
<script>
import VueEvents from 'vue-events'
Vue.use(VueEvents)
var Vuetable = require('vuetable-2/src/components/Vuetable.vue');
Vue.use(Vuetable);
var VuetablePagination = require('vuetable-2/src/components/VuetablePagination.vue');
var VuetablePaginationInfo = require('vuetable-2/src/components/VuetablePaginationInfo.vue');
Vue.component('custom-actions', require('../CustomActions.vue'))
Vue.component('filter-bar', require('../FilterBar.vue'))
export default {
components: {
Vuetable,
VuetablePagination,
VuetablePaginationInfo,
},
data () {
return {
fields: [
{
name: 'id',
sortField: 'id',
},
{
name: 'name',
sortField: 'name',
},
{
name: '__component:custom-actions',
title: 'Actions',
titleClass: 'text-center',
dataClass: 'text-center'
}
],
css: {
table: {
tableClass: 'table table-bordered table-striped table-hover',
ascendingIcon: 'glyphicon glyphicon-chevron-up',
descendingIcon: 'glyphicon glyphicon-chevron-down'
},
pagination: {
wrapperClass: 'pagination',
activeClass: 'active',
disabledClass: 'disabled',
pageClass: 'page',
linkClass: 'link',
},
icons: {
first: 'glyphicon glyphicon-step-backward',
prev: 'glyphicon glyphicon-chevron-left',
next: 'glyphicon glyphicon-chevron-right',
last: 'glyphicon glyphicon-step-forward',
},
},
sortOrder: [
{ field: 'id', sortField: 'id', direction: 'asc'}
],
moreParams: {}
}
},
methods: {
onPaginationData (paginationData) {
this.$refs.pagination.setPaginationData(paginationData)
this.$refs.paginationInfo.setPaginationData(paginationData)
},
onChangePage (page) {
this.$refs.vuetable.changePage(page)
},
onCellClicked (data, field, event) {
console.log('cellClicked: ', field.name)
this.$refs.vuetable.toggleDetailRow(data.id)
},
onFilterSet (filterText) {
this.moreParams = {
'filter': filterText.trim()
}
Vue.nextTick( () => this.$refs.vuetable.refresh())
},
onFilterReset () {
this.moreParams = {}
Vue.nextTick( () => this.$refs.vuetable.refresh())
}
},
mounted() {
this.$events.$on('filter-set', eventData => this.onFilterSet(eventData))
this.$events.$on('filter-reset', e => this.onFilterReset())
}
}
</script>
<style>
.pagination {
margin: 0;
float: right;
}
.pagination a.page {
border: 1px solid lightgray;
border-radius: 3px;
padding: 5px 10px;
margin-right: 2px;
}
.pagination a.page.active {
color: white;
background-color: #337ab7;
border: 1px solid lightgray;
border-radius: 3px;
padding: 5px 10px;
margin-right: 2px;
}
.pagination a.btn-nav {
border: 1px solid lightgray;
border-radius: 3px;
padding: 5px 7px;
margin-right: 2px;
}
.pagination a.btn-nav.disabled {
color: lightgray;
border: 1px solid lightgray;
border-radius: 3px;
padding: 5px 7px;
margin-right: 2px;
cursor: not-allowed;
}
.pagination-info {
float: left;
}
</style>
Filter in the list vue is not working
This is my FilterBar.vue
<template>
<div class="filter-bar ui basic segment grid">
<div class="ui form">
<div class="inline field">
<label>Search for:</label>
<input type="text" v-model="filterText" class="three wide column" #keyup.enter="doFilter" placeholder="name, nickname, or email">
<button class="ui primary button" #click="doFilter">Go</button>
<button class="ui button" #click="resetFilter">Reset</button>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
filterText: ''
}
},
methods: {
doFilter () {
this.$events.fire('filter-set', this.filterText)
},
resetFilter () {
this.filterText = ''
this.$events.fire('filter-reset')
}
}
}
</script>
Event is being fired in the filterbar vue component, but listener in list.vue component doesn't pick it up
I tried the fix in the issues tab
1.using method and mounted
2.using created