How to animate todo moving from one list to another with Vue.js? - vue.js

I am trying to do this svelte example todo moving animation with Vue.js.
Below you can find what I have done so far. Just click on the todo to see.
new Vue({
el: "#app",
data: {
items: [
{ id: 1, name: 'John', done: false },
{ id: 2, name: 'Jane', done: false },
{ id: 3, name: 'Jade', done: true },
{ id: 4, name: 'George', done: true },
]
},
computed: {
done () {
return this.items.filter(i => i.done)
},
undone () {
return this.items.filter(i => !i.done)
}
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
height: 500px;
transition: all 0.2s;
}
.todos {
display: grid;
grid-template-columns: 1fr 1fr;
}
.todo {
border: 1px solid #ccc;
}
.todo.undone {
grid-column: 2 /span 1;
}
.todo.done {
grid-column: 1 /span 1;
background: blue;
color: white;
}
.flip-list-move {
transition: all 1s ease-in-out;
}
.header-wrapper {
display: grid;
grid-auto-flow: column;
}
.header, .todo {
display: grid;
grid-template-columns: repeat(3, 1fr);
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="header-wrapper">
<div class="header">
<span>Name</span>
<span>Age</span>
<span>Gender</span>
</div>
<div class="header">
<span>Name</span>
<span>Age</span>
<span>Gender</span>
</div>
</div>
<transition-group name="flip-list" tag="div" class="todos">
<div class="todo done" v-for="item of done" :key="item.id" #click="toggle(item)">
<span>{{item.name}}</span>
<span>26</span>
<span>Male</span>
</div>
<div class="todo undone" v-for="item of undone" :key="item.id" #click="toggle(item)">
<span>{{item.name}}</span>
<span>20</span>
<span>Male</span>
</div>
</transition-group>
</div>
In order to animate the todo move from one list to another, I used CSS grid but I can't find a way to distinguish todos (left and right) without having a grid cell which is empty.
I would appreciate if there is a better way to achieve the example in svelte docs or a way to omit the empty cells.
Even though it seemed easy in the beginning, it's a bit tricky.

You can target the first element by tracking the index in the v-for loop. Index 0 is always going to be the first element. And give it the following style:
grid-row-start: 1;
EDIT DEMO:
new Vue({
el: "#app",
data: {
items: [
{ id: 1, name: 'John', done: false },
{ id: 2, name: 'Jane', done: false },
{ id: 3, name: 'Jade', done: true },
{ id: 4, name: 'George', done: true },
]
},
computed: {
done () {
return this.items.filter(i => i.done)
},
undone () {
return this.items.filter(i => !i.done)
}
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
height: 500px;
transition: all 0.2s;
}
.todos {
display: grid;
grid-template-columns: 1fr 1fr;
}
.todo {
border: 1px solid #ccc;
}
.todo.undone {
grid-column: 2 /span 1;
}
.todo.done {
grid-column: 1 /span 1;
background: blue;
color: white;
}
.first-right {
grid-row-start: 1;
}
.flip-list-move {
transition: all 1s ease-in-out;
}
.header-wrapper {
display: grid;
grid-auto-flow: column;
}
.header, .todo {
display: grid;
grid-template-columns: repeat(3, 1fr);
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="header-wrapper">
<div class="header">
<span>Name</span>
<span>Age</span>
<span>Gender</span>
</div>
<div class="header">
<span>Name</span>
<span>Age</span>
<span>Gender</span>
</div>
</div>
<transition-group name="flip-list" tag="div" class="todos">
<div class="todo done" v-for="item of done" :key="item.id" #click="toggle(item)">
<span>{{item.name}}</span>
<span>26</span>
<span>Male</span>
</div>
<div :class="['todo', 'undone', { 'first-right': index === 0 }]" v-for="(item, index) of undone" :key="item.id" #click="toggle(item)">
<span>{{item.name}}</span>
<span>20</span>
<span>Male</span>
</div>
</transition-group>
</div>

Adding grid-row-start to the first undone element doesn't works if there are more than 6 items in array.
As a solution, I used the index of v-for loop to add to every undone todo the corresponding grid-row-start.
index starts at 0 so we have to make index + 1
<div
class="todo undone"
v-for="(item, index) of undone"
:key="item.id"
:style="{'grid-row': index + 1}" // => HERE we guarantee no gaps are present in undone list`
#click="toggle(item)"
>
<span>{{item.name}}</span>
<span>20</span>
<span>Male</span>
</div>
You can find the working example on this codesandbox

Related

How to hide next and prev btn in carousel using vue 2 / nuxt js?

I have created a multi items carousel in which i slide one item at a time.
Initially i want to hide prev btn , but when clicked on next btn and one or more item is moved/slide to left in want the prev btn to be visible and when i am at end of the caorusel items i want to hide next button
template
<div class="main-container">
<div class="carousel-container position-relative" ref="container">
<div class="carousel-inner overflow-hidden">
<div class="carousel-track" >
<nuxt-link to="" class="card-container" v-for="(index, i) in 9" :key="i">
<div class="card"></div>
</nuxt-link>
</div>
</div>
<div class="btns-container">
<button class="prevBtn" #click="prev" >
prev
</button>
<button class="nextBtn" #click="next" >
next
</button>
</div>
</div>
</div>
script
methods: {
next() {
const track = document.querySelector('.carousel-track')
const item = document.querySelector('.card-container')
track.scrollLeft += item.clientWidth
},
prev() {
const track = document.querySelector('.carousel-track')
const item = document.querySelector('.card-container')
track.scrollLeft -= item.clientWidth
},
}
styles
.carousel-track{
display: flex;
overflow: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: none;
}
.carousel-track::-webkit-scrollbar {
display: none;
}
.card-container{
flex-shrink: 0;
scroll-snap-align: start;
}
.btns-container button{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.prevBtn{
left: -1rem;
}
.nextBtn{
right: -1rem;
}
You should not use querySelectors but rather state since you're working with Vue.
Sorry, I didn't had a carousel example so I did something a bit different.
<template>
<div class="main-container">
<div ref="container" class="carousel-container position-relative">
<div class="carousel-inner overflow-hidden">
<div class="carousel-track">
<nuxt-link
v-for="(city, index) in cities"
:key="city.id"
to=""
class="card-container"
>
<div
class="card"
:class="index === currentCityIndex && 'active-city'"
>
{{ city.name }}
</div>
</nuxt-link>
</div>
</div>
<br />
<p>Current city index: {{ currentCityIndex }}</p>
<div class="btns-container">
<button v-show="currentCityIndex !== 0" class="prevBtn" #click="prev">
prev
</button>
<button
v-show="currentCityIndex !== cities.length - 1"
class="nextBtn"
#click="next"
>
next
</button>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
currentCityIndex: 0,
cities: [
{ name: 'New york', id: '1' },
{ name: 'Los Angeles', id: '2' },
{ name: 'Chicago', id: '3' },
{ name: 'Houston', id: '4' },
{ name: 'Philadelphia', id: '5' },
{ name: 'Phoenix', id: '6' },
{ name: 'San Antonio', id: '7' },
{ name: 'San Diego', id: '8' },
{ name: 'Dallas', id: '9' },
{ name: 'San Jose', id: '10' },
],
}
},
methods: {
next() {
this.currentCityIndex++
},
prev() {
this.currentCityIndex--
},
},
}
</script>
<style scoped>
.active-city {
border: 2px solid red;
}
</style>
The idea is mainly to do a check on the button with v-show="currentCityIndex !== 0" and display it depending on the current index you're on. You can of course also use visibility or any kind of cool CSS approach to avoid any shift regarding the location of the buttons.
v-show="currentCityIndex !== cities.length - 1" is checking if we are on the last element of your collection.
This is a basic carrousel I sometimes use and modify if I need it. It is originally an infinite carrousel but I added that function you are looking for.
You can copy the code and check how it works and sure I can be improve a lot. But so far it works.
Template
<template>
<div class="main-container">
<div class="carrousel-container">
<span ref="nextArrow" #click="nextSlide" class="slider-btn next">
<svg
width="25"
height="43"
viewBox="0 0 25 43"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M23.5858 20.0623L4.39859 0.875151C3.13866 -0.384778 0.984375 0.507553 0.984375 2.28936V40.6638C0.984375 42.4456 3.13866 43.3379 4.39859 42.078L23.5858 22.8908C24.3668 22.1097 24.3668 20.8434 23.5858 20.0623Z"
/>
</svg>
</span>
<span ref="prevArrow" #click="prevSlide" class="slider-btn prev">
<svg
width="25"
height="43"
viewBox="0 0 25 43"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.41421 20.0623L20.6014 0.875151C21.8613 -0.384778 24.0156 0.507553 24.0156 2.28936V40.6638C24.0156 42.4456 21.8613 43.3379 20.6014 42.078L1.41421 22.8908C0.633165 22.1097 0.633165 20.8434 1.41421 20.0623Z"
/>
</svg>
</span>
<!-- carousel -->
<div
:id="activeSlideIndex"
v-if="showSlides"
class="carousel-container"
>
<div
class="slide"
ref="slide"
v-for="(slide, idx) in slides"
:class="slide.position"
:key="slide.id"
>
{{ idx }}
</div>
</div>
<!-- carousel -->
</div>
</div>
</template>
Script and Styles
<script>
export default {
props: {
slides: {
type: Array,
default: () => [
{ id: 1, name: "sliderOne" },
{ id: 2, name: "slider Two" },
{ id: 3, name: "slider Three" },
],
},
},
mounted() {
this.orderSlides(this.slides, this.activeSlideIndex);
},
data() {
return {
activeSlideIndex: 0,
showSlides: false,
};
},
methods: {
nextSlide() {
++this.activeSlideIndex;
this.displayOrder(this.activeSlideIndex);
},
prevSlide() {
--this.activeSlideIndex;
this.displayOrder();
},
displayOrder() {
if (this.activeSlideIndex === this.slides.length) {
console.log(this.activeSlideIndex);
this.activeSlideIndex = 0;
} else if (this.activeSlideIndex < 0) {
this.activeSlideIndex = this.slides.length - 1;
}
this.orderSlides(this.slides, this.activeSlideIndex);
},
orderSlides(array, activeIndex) {
array.forEach((element, idx) => {
element.position = "nextSlide";
if (idx === activeIndex) {
element.position = "activeSlide";
} else if (
idx === activeIndex - 1 ||
(activeIndex === 0 && idx === array.length - 1)
) {
element.position = "lastSlide";
}
});
if (!this.showSlides) {
this.showSlides = true;
}
// toggle arrows
if (activeIndex === array.length - 1) {
this.$refs.nextArrow.style.display = "none";
} else if (activeIndex === 0) {
this.$refs.prevArrow.style.display = "none";
} else {
this.$refs.nextArrow.style.display = "block";
this.$refs.prevArrow.style.display = "block";
}
},
},
};
</script>
<style scoped>
.main-container {
height: 100vh;
width: 100%;
background: rgba(0, 0, 0, 0.6);
overflow: hidden;
display: grid;
place-content: center;
}
.carrousel-container {
width: 769px;
height: 631px;
position: relative;
padding-top: 37px;
padding-bottom: 20px;
}
.slider-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.slider-btn svg {
fill: red;
}
.next {
right: 25px;
}
.prev {
left: 25px;
}
.carousel-container {
width: 600px;
height: 631px;
overflow: hidden;
position: relative;
display: flex;
background: white;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0 auto;
}
.slide {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
transition: 0.3s all linear;
background: var(--primary-light);
border-radius: var(--border-radius-1);
}
.slide.activeSlide {
opacity: 1;
transform: translateX(0);
}
.slide.lastSlide {
transform: translateX(-100%);
}
.slide.nextSlide {
transform: translate(100%);
}
img {
width: 100%;
}
</style>

Unwanted animation bug in Vue.js

This is an unwanted animation bug that seems to be normal, but I want the element to be animationed which is in <input v-model="todo"/>. The problem is each time I press on add button to add the todo name (<input v-model="todo"/>), the last element 'last' runs the animation.
P.s. I tried to keep the code as simple as possible.
Vue.createApp({
data() {
return {
todo: "",
todo_list: ['last'],
};
},
methods: {
add() {
this.todo_list.unshift(this.todo);
console.log(this.todo_list);
},
remove(index) {
this.todo_list.splice(index, 1);
},
},
}).mount('#app');
.list-enter-active,
.list-leave-active {
transition: all 200ms ease-out;
}
.list-enter-from {
transform: translateY(-20px);
}
.list-leave-to {
opacity: 0;
transform: translateX(20px);
}
article {
width: 50%;
padding: 10px;
background-color: #dddddd;
border: 1px solid #cfcfcf;
border-radius: 5px;
margin-block: 10px
}
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
<input type="text" v-model="todo" /> <button #click="add">add</button>
<transition-group name="list" tag="section">
<article v-for="(todo, index) in todo_list" :key="index" #click="remove(index)">
<span>{{ todo }}</span>
</article>
</transition-group>
</div>
The reason you're experiencing this issue, is because you're using the index as a key.
If you added the elements to the end of the list, this would be fine.
But since you're adding it to the start, it will cause the issue you're seeing.
I'd suggest you make each todo an object, and add a unique identifier to each object. This can be a simple integer that you increment. Then you can use that property as the key.
Example
let id = 1;
Vue.createApp({
data() {
return {
todo: "",
todo_list: [{
id: id++,
value: 'last'
}],
};
},
methods: {
add() {
const todo = {
id: id++,
value: this.todo
}
this.todo_list.unshift(todo);
},
remove(index) {
this.todo_list.splice(index, 1);
},
},
}).mount('#app');
.list-enter-active,
.list-leave-active {
transition: all 200ms ease-out;
}
.list-enter-from {
transform: translateY(-20px);
}
.list-leave-to {
opacity: 0;
transform: translateX(20px);
}
article {
width: 50%;
padding: 10px;
background-color: #dddddd;
border: 1px solid #cfcfcf;
border-radius: 5px;
margin-block: 10px
}
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
<input type="text" v-model="todo" /> <button #click="add">add</button>
<transition-group name="list" tag="section">
<article v-for="(todo, index) in todo_list" :key="todo.id" #click="remove(index)">
<span>{{ todo.value }}</span>
</article>
</transition-group>
</div>

How can I modify a value in a array with a click method ? [VueJS]

I just started vuejs today. I got vue "example1" which contain as data, a variable "items". This variable contains an array "deck". This array contains multiple character stats (team, weapon, position...).
I don't know how to figure this out, if you have any solution or any direction where I can find my anwser.
I want on click on the character, to modify the gridColumn position, which is binded by "x". They are displayed on a 9*12 grid.
Thanks a lot.
html, body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#board {
display: grid;
grid-template-columns: repeat(12, 80px);
grid-template-rows: repeat(9, 80px);
grid-gap: 10px;
}
#board .card {
background-color: pink;
border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<section id="board">
<div class="card" v-for="item in items" v-bind:style="{backgroundColor:item.bg,gridColumn:item.x,gridRow:item.y}" v-on:click="move">
{{ item.clan }}
<br>
{{ item.arme }}
<br>
{{ item.force }}
</div>
</section>
<script>
var deck = [
//natif
{
clan: 'natif',
arme:'filet',
force: 1,
bg: 'green',
x: 2,
y: 6
},
{
clan: 'natif',
arme:'filet',
force: 2,
bg: 'green',
x: 3,
y: 6
}
//etc
];
var example1 = new Vue({
el: '#board',
data: {
items: deck
},
methods: {
move: function () {
// increase "x" value of the clicked item.
}
}
});
</script>
You can pass the index of the item clicked and modify it inside the function by referencing the index.
html, body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#board {
display: grid;
grid-template-columns: repeat(12, 80px);
grid-template-rows: repeat(9, 80px);
grid-gap: 10px;
}
#board .card {
background-color: pink;
border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<section id="board">
<div class="card" v-for="(item,index) in items" v-bind:style="{backgroundColor:item.bg,gridColumn:item.x,gridRow:item.y}" v-on:click="move(index)">
{{ item.clan }}
<br>
{{ item.arme }}
<br>
{{ item.force }}
</div>
</section>
<script>
var deck = [
//natif
{
clan: 'natif',
arme:'filet',
force: 1,
bg: 'green',
x: 2,
y: 6
},
{
clan: 'natif',
arme:'filet',
force: 2,
bg: 'green',
x: 3,
y: 6
}
//etc
];
var example1 = new Vue({
el: '#board',
data: {
items: deck
},
methods: {
move: function (i) {
this.items = this.items.map((item,indx) => {
if(indx === i)
return ({...item,x: item.x + 1});
return item;
}) //modify logic accordingly
}
}
});
</script>
This is how you do it according to the OFFICIAL VUE.JS DOCUMENTATION
[Mutating the array with Vue.set method]:
var deck = [
//natif
{
clan: 'natif',
arme: 'filet',
force: 1,
bg: 'green',
x: 2,
y: 6
},
{
clan: 'natif',
arme: 'filet',
force: 2,
bg: 'green',
x: 3,
y: 6
}
//etc
];
var example1 = new Vue({
el: '#board',
data: {
items: deck
},
methods: {
move: function(index) {
/* creating a REFERENCE of the clicked item's object */
let modifiedObject = this.items[index];
/* increaseing "x" value of temporary REFERENCE */
modifiedObject.x++;
/* Mutating the items array WITHOUT LOSING REACTIVITY by replacing the existing object with local modified object */
Vue.set(this.items, index, modifiedObject);
}
}
});
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#board {
border: 1px solid black;
display: grid;
grid-template-columns: repeat(12, 40px);
grid-template-rows: repeat(9, 40px);
grid-gap: 10px;
}
#board .card {
background-color: pink;
border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<section id="board">
<div class="card" v-for="(item,index) in items" v-bind:style="{backgroundColor:item.bg,gridColumn:item.x,gridRow:item.y}" v-on:click="move(index)">
{{ item.clan }}
<br> {{ item.arme }}
<br> {{ item.force }}
</div>
</section>

Fix animated images on slide

I'm trying to make an animation when changing a slide. The old slide disappears with the animation, and the new one shows up with the animation. My animation is alternating. Help. Thank you all !!
var app = new Vue({
el: '#app',
data() {
return {
selectedIndex: 0,
message: "Test work vue",
isOpenSlide: true,
startVal: 0,
decimals: 0,
duration: 2.5,
options: {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '.',
prefix: '',
suffix: ''
},
items: [
{
title: 'Center of osteopatia and rehabilitation',
url_img: 'https://i.imgur.com/gQp3VSW.jpg',
info_block: [
{
incremental: '800',
description: 'Increasing the number of transactions from organic search results'
},
{
incremental: '240',
description: 'Raising your revenue'
}
]
},
{
title: 'SLide 2',
url_img: 'https://newevolutiondesigns.com/images/freebies/space-wallpaper-5.jpg',
info_block: [
{
incremental: '140',
description: 'Increasing the numb organic search results'
},
{
incremental: '790',
description: 'Raising your revenue'
}
]
},
{
title: ' SLIDE 3',
url_img: 'https://www.planwallpaper.com/static/images/4433836-space-wallpapers.jpg',
info_block: [
{
incremental: '110',
description: 'Increasing the number of trans'
},
{
incremental: '99',
description: 'Raising your revenue'
}
]
}
]
}
},
methods: {
select(index) {
this.selectedIndex = index
},
index_dotnav: function (index) {
this.selectedIndex = index
},
open() {
this.isOpenSlide = true;
},
close() {
this.isOpenSlide = false;
},
toggle() {
if (this.isOpenSlide) {
this.close();
} else {
this.open();
}
},
ChangeSlider() {
setTimeout(() => {
if (++this.selectedIndex === this.items.length) {
this.selectedIndex = 0;
}
this.toggle();
this.ChangeSlider()
}, 5000)
},
callback(instance) {
instance.start();
}
},
mounted() {
this.ChangeSlider();
}
})
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
ul {
padding-left: 0;
margin: 0;
}
.img-block,
section > *,
.uk-slideshow,
.uk-slideshow > ul {
height: 100vh !important;
}
.information-slide .uk-container {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto 0;
display: flex;
flex-direction: column;
justify-content: center;
color: #fff;
}
.slideshow > div.dotnav-block {
top: 50%;
left: 95%;
z-index: 2;
}
.slideshow > div.dotnav-block li a {
background: #fff;
}
.slideshow > div.dotnav-block li.active a {
width: 13px;
height: 13px;
}
.slideshow > div.dotnav-block ul {
align-items: center;
}
.slideshow .slideshow-items > li {
display: none;
}
.slideshow .slideshow-items > li.active {
display: block;
position: relative;
}
.slideshow .slideshow-items > li img {
height: 100%;
width: auto;
object-fit: cover;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-rc.14/css/uikit.min.css"/>
<body>
<div id="app">
<section>
<div class="uk-child-width-1-2" uk-grid>
<div>
<h1>{{ message }}</h1>
</div>
<div>
<div id="slideshow">
<div class="slideshow">
<ul class="slideshow-items">
<li v-for="(item,index) in items" :class="{'active':index===selectedIndex}"
v-on:click="select(index)">
<div class="information-slide">
<transition name="slide">
<div class="img-block" v-show="isOpenSlide">
<img v-bind:src="item.url_img" alt="">
</div>
</transition>
<div class="uk-container">
<div class="title title-1">{{item.title}}</div>
<div class="info-block">
<div class="info" v-for="(iblock,ind) in item.info_block">
<div class="incremental">
<span>+</span>
<!--<app-count-up-->
<!--:startVal="startVal"-->
<!--:endVal="iblock.incremental"-->
<!--:decimals="decimals"-->
<!--:duration="duration"-->
<!--:options="options"-->
<!--:callback="onReady"></app-count-up>-->
<span>%</span>
</div>
<div class="description descr-1">{{iblock.description}}</div>
</div>
</div>
</div>
</div>
</li>
</ul>
<div class="dotnav-block uk-position-bottom-center uk-position-small">
<ul class="uk-dotnav uk-dotnav-vertical">
<li :class="{'active':index===selectedIndex}" v-for="(item,index) in items"
v-on:click="index_dotnav(index)">
Item {{index}}</li>
</ul>
</div>
</div>
</div>
</template>
</div>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-rc.14/js/uikit.min.js"></script>

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