Highlighting parent menu from router-link in VueJS - vue.js

I have developed a split sidebar menu. On the left there is icons which when pressed activate the menu bar on the right side for the submenu items. The submenu contains the router-link tags which I am able to tap into the active class of the selected link to highlight it. The issue is I need to apply the active class to the left icon bar as well since that is the parent menu. Once the application is loaded when you click the icons the active class will become active if the item is selected. My issue is purely during load because if someone types in the URL the custom router link the left sidebar does not have any functionality linking it to the router since the links are in the right part of the sidebar. Any methodology built into vue to handle something like this? If not is there another method I could try?
My sidebar component code is below. The code basically creates two sides, the icon side and the menu side. The icons and menu's are developed using v-for and looping through the data set which provides the links and icons to use.
<template id="side-navigation">
<div :class="theme">
<nav :class="sidebarcontainer">
<div class="sidebar-left">
<div class="arms-icon">
</div>
<div class="main-menu-items">
<ul>
<li v-for="(item,i) in MainNavLinks"
:key="i"
:class="{'active-main-menu-item': i === activeIconIndex}"
v-on:click="selectIconItem(i)">
<a>
<i :class="item.icon"></i>
</a>
</li>
</ul>
</div>
<div class="bottom-menu-items">
<ul>
<li v-for="(item,i) in FeaturesNavLinks"
:key="i"
:class="{ 'active-main-menu-item': i+MainNavLinks.length === activeIconIndex}"
v-on:click="selectIconItem(i+MainNavLinks.length)">
<a>
<i :class="item.icon"></i>
</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-right" :class="{'active-right-sidebar' : isIconActive}">
<div class="sidebar-content">
<div class="searchbarcontent">
<div class="inputWithIcon">
<input placeholder="Search" id="sub-nav-seachbar" class="searchbar" type="text">
<i class="fas fa-search" id="searchicon-btn"></i>
</div>
</div>
<div v-for="(item,i) in MainNavLinks"
:key="i"
:class="{'active-sub-menu-item' : i === activeIconIndex}"
class="right-menu-content">
<ul>
<li v-for="(SubNavLink,i) in item.SubNavLinks"
class="sub-nav-group">
<h4 class="sub-nav-header">
{{SubNavLink.SubNavHeader}}
</h4>
<ul>
<li v-for="(SubNavMenuItem,i) in SubNavLink.SubNavMenuItems"
class="sub-nav-items">
<router-link :to="SubNavMenuItem.link"><span class="sub-menu-icons"><i :class="SubNavMenuItem.icon"></i></span>{{SubNavMenuItem.title}}</router-link>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</nav>
</div>
</template>
<script>
Vue.component('side-navigation', {
template: '#side-navigation',
methods: {
selectIconItem(i) {
if (this.activeIconIndex === i) {
if (this.isIconActive === true) {
this.isIconActive = false;
} else {
this.isIconActive = true;
}
} else {
this.activeIconIndex = i;
this.isIconActive = true;
}
},
},
data() {
return {
theme: 'color',
activeIconIndex: null,
isIconActive: false,
sidebarcontainer: 'sidebar-container',
MainNavLinks: [
{
name: 'Dashboard',
link: '/',
icon: 'fa fa-th-large fa-lg',
SubNavLinks: [
{
SubNavHeader: 'Dash Category 1',
SubNavMenuItems: [{
title: 'Item 1',
link: '/',
icon: 'fas fa-list-ul'
},
{
title: 'Item 2',
link: '/item2',
icon: 'fas fa-list-ul'
}]
},
{
SubNavHeader: 'Dash Category 2',
SubNavMenuItems: [{
title: 'Item 3',
link: '/item3',
icon: 'fas fa-list-ul'
},
{
title: 'Item 4',
link: '/item4',
icon: 'fas fa-list-ul'
}]
}
]
},
{
name: 'Reviews',
link: '/Reviews',
icon: 'far fa-clipboard fa-lg',
SubNavLinks: [
{
SubNavHeader: 'Reviews Category 1',
SubNavMenuItems: [{
title: 'Item 1',
link: '/item1',
icon: 'fas fa-list-ul'
},
{
title: 'Item 2',
link: '/item2',
icon: 'fas fa-list-ul'
}]
},
{
SubNavHeader: 'Reviews Category 2',
SubNavMenuItems: [{
title: 'Item 3',
link: '/item3',
icon: 'fas fa-list-ul'
},
{
title: 'Item 4',
link: '/item4',
icon: 'fas fa-list-ul'
}]
}
]
},
{
name: 'Upload',
link: '/Upload',
icon: 'fa fa-upload fa-lg',
SubNavLinks: [
]
},
{
name: 'Analytics',
link: '/Analytics',
icon: 'fas fa-chart-line fa-lg',
SubNavLinks: [
]
},
{
name: 'Files',
link: '/Files',
icon: 'far fa-folder-open fa-lg',
SubNavLinks: [
]
}
],
FeaturesNavLinks: [
{
name: 'Notifications',
link: '/',
icon: 'fas fa-bell fa-lg'
},
{
name: 'Chat',
link: '/',
icon: 'fas fa-comment-alt fa-lg'
},
{
name: 'Email',
link: '/',
icon: 'fas fa-envelope fa-lg'
},
{
name: 'Profile',
link: '/',
icon: 'fas fa-user fa-lg'
}
]
}
}
})
</script>
<style scoped>
.sidebar-container {
display: flex;
flex-direction: row;
box-shadow: 2px 0px 4px -1px rgb(0 0 0 / 15%);
position: sticky;
}
/*left icon section of sidebar*/
.sidebar-left {
display: flex;
flex-direction: column;
align-items: center;
width: 100px;
position: relative;
height: 100vh;
overflow-y: auto;
overflow-x: hidden;
}
.color .sidebar-left {
background-color: #ff7100;
}
.light .sidebar-left {
border-right: 1px solid #ebedf3;
}
.main-menu-items {
padding: 20px 20px;
flex-grow: 1;
}
.sidebar-left ul {
padding: 0px;
}
.sidebar-left li {
list-style-type: none;
text-align: center;
margin-bottom: 10px;
}
.sidebar-left a {
height: 50px;
width: 50px;
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
border-radius: .42rem;
}
.color .sidebar-left a:hover > *, .color .sidebar-left a:hover {
background-color: #da6000f7;
color: #fff !important;
}
.light .sidebar-left a:hover > *, .light .sidebar-left a:hover {
background-color: #f3f6f9;
color: #ff7d44 !important;
}
.color .active-main-menu-item a > *, .color .active-main-menu-item a {
background-color: #da6000f7;
color: #fff !important;
}
.light .active-main-menu-item a > *, .light .active-main-menu-item a {
background-color: #f3f6f9;
color: #ff7d44 !important;
}
.color .sidebar-left i {
color: #fff;
}
.light .sidebar-left i {
color: #a5a5a5;
}
/*right sidebar styling*/
.sidebar-right {
width: 0px;
position: relative;
transition: all 1s;
overflow: hidden;
height: 100vh;
overflow-y: auto;
}
.active-right-sidebar {
width: 325px;
transition: all 1s;
}
.sidebar-content{
padding:20px;
}
.right-menu-content {
display: none;
overflow: hidden;
white-space: nowrap;
padding: 0px 20px;
}
.active-sub-menu-item {
display: block;
}
/*sidebar searchbar*/
.searchbar {
width: 100%;
height: 40px;
border: 0px;
border-radius: 40px;
outline: none;
padding: 8px;
box-sizing: border-box;
transition: 0.3s;
letter-spacing: 2px;
background-color: #e6e6e6;
}
.inputWithIcon input[type="text"], .inputWithIcon input[type="password"] {
padding-left: 35px;
}
.inputWithIcon {
position: relative;
height: 40px;
overflow: hidden;
width: 100%;
}
.searchbarcontent {
padding: 0px 20px;
display: flex;
height: 50px;
width: 100%;
justify-content: center;
align-items: center;
margin-bottom: 10px;
}
#searchicon-btn {
padding: 9px 25px 9px 5px;
top: 4px;
color: #aaa;
position: absolute;
right: 0px;
cursor: pointer;
}
.sidebar-right ul {
padding: 0px;
}
.sidebar-right li {
list-style-type: none;
}
.sidebar-right a {
text-decoration: none;
}
.sub-nav-header {
display: flex;
align-items: center;
height: 50px;
font-size: 1rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .3px;
color: #7e8299;
}
.sub-nav-items {
display: flex;
align-items: center;
height: 45px;
font-size: .9rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .3px;
}
.sub-nav-items a {
color: #7f818d;
}
.sub-nav-group{
margin-bottom: 15px;
}
.sub-menu-icons {
width: 30px;
padding-right: 20px;
}
.router-link-exact-active {
color: #ff7100 !important;
}
/*scrollbar*/
/* custom scrollbar */
::-webkit-scrollbar {
width: 20px;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #00000014;
border-radius: 20px;
border: 6px solid transparent;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: #0000001f;
}
</style>

Use nested routes.
Parent <router-link>'s should have the class .router-link-active.
The exact <router-link> should have .router-link-exact-active.
Check out this code for an interactive example.

Related

Migrating the code of vue2.x to vue3.x, encountered Unexpected mutation of "task" prop in the v-model module

I used the Composition API when migrating the project from vue2.x to vue3.0, but the page does not work properly, in vue3.0
The environment prompts me to have an "Unexpected mutation of "task" prop" error, I want to know how to write the correct compos API
This is Vue2.x code
<template>
<transition name="fade">
<div class="task" v-if="!task.deleted">
<input :id="id" type="checkbox" v-model="task.done" />
<label :for="id">{{ task.title }}</label>
<transition name="fade">
<span
class="task_delete"
v-show="task.done"
#click="deleteTask({ task })"
>
<i class="fa fa-trash"></i>
</span>
</transition>
</div>
</transition>
</template>
<script>
import { mapMutations } from "vuex";
let GID = 1;
export default {
props: {
task: {
type: Object,
required: true,
},
},
data() {
return {
id: `task-${GID++}`,
};
},
methods: {
...mapMutations(["deleteTask"]),
},
};
</script>
<style lang="scss">
.task {
display: flex;
padding: 12px 0;
border-bottom: 1px solid #eee;
font-size: 14px;
}
.task input {
display: none;
}
.task label {
flex: 1;
line-height: 20px;
}
.task label:before,
.task label:after {
content: "";
display: inline-block;
margin-right: 20px;
margin-top: 1px;
width: 14px;
height: 14px;
vertical-align: top;
}
.task label:before {
border: 1px solid #ccc;
border-radius: 2px;
background-color: white;
}
.task label:after {
content: "\f00c";
position: relative;
display: none;
z-index: 10;
margin-right: -16px;
width: 10px;
height: 10px;
padding: 3px;
border-radius: 2px;
font: normal normal normal 10px/1 FontAwesome;
color: white;
background-color: #ccc;
float: left;
}
.task input:checked + label:after {
display: inline-block;
}
.task_delete {
padding: 0 10px;
color: #ccc;
font-size: 16px;
}
.fade-leave-to,
.fade-enter {
opacity: 0;
}
.fade-enter-to,
.fade-leave {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
</style>
This is Vue3.0 code use Composition API, but not work
<template>
<transition name="fade">
<div class="task" v-if="!data.task.deleted">
<input :id="id" type="checkbox" v-model="data.task.done" />
<label :for="id">{{ data.task.title }}</label>
<transition name="fade">
<span
class="task_delete"
v-show="data.task.done"
#click="deleteTask({ task })"
>
<i class="fa fa-trash"></i>
</span>
</transition>
</div>
</transition>
</template>
<script>
import { reactive } from "vue";
import { mapMutations } from "vuex";
let GID = 1;
export default {
name: "Task",
props: {
task: {
type: Object,
required: true,
},
},
setup(props) {
const data = reactive({
task: props.task,
id: `task-${GID++}`,
});
return { data };
},
methods: {
...mapMutations(["deleteTask"]),
},
};
</script>
<style lang="scss">
.task {
display: flex;
padding: 12px 0;
border-bottom: 1px solid #eee;
font-size: 14px;
}
.task input {
display: none;
}
.task label {
flex: 1;
line-height: 20px;
}
.task label:before,
.task label:after {
content: "";
display: inline-block;
margin-right: 20px;
margin-top: 1px;
width: 14px;
height: 14px;
vertical-align: top;
}
.task label:before {
border: 1px solid #ccc;
border-radius: 2px;
background-color: white;
}
.task label:after {
content: "\f00c";
position: relative;
display: none;
z-index: 10;
margin-right: -16px;
width: 10px;
height: 10px;
padding: 3px;
border-radius: 2px;
font: normal normal normal 10px/1 FontAwesome;
color: white;
background-color: #ccc;
float: left;
}
.task input:checked + label:after {
display: inline-block;
}
.task_delete {
padding: 0 10px;
color: #ccc;
font-size: 16px;
}
.fade-leave-to,
.fade-enter {
opacity: 0;
}
.fade-enter-to,
.fade-leave {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
</style>
I think the problem is you're using v-model for props on checkbox, it will change props value directly and vue not allow it. Try update props value manual by emit event. And u dont need to use props with reactive in child component, but need to reactive that props in parent component
<input :id="id" type="checkbox" v-value="task.done" #change="updateCheckbox($event)")/>
In script:
export default {
name: "Task",
props: {
task: {
type: Object,
required: true,
},
},
emits: ['updateCheckbox'],
setup(props) {
const data = reactive({
id: `task-${GID++}`,
});
return { data };
},
methods: {
updateCheckbox(e) {
this.$emit('updateCheckbox', e.target.value)
}
},
};

How do you have a default/initially selected option with custom slots in vue-select?

I'm not sure how to set a default/initial selected option using vue-select, specifically when you use slots.
Here is the code: https://vue-select.org/guide/slots.html
I would want one of the options to initially display on page load.
Pass the option object you want as a default value into the v-model prop of the component.
Vue.component('v-select', VueSelect.VueSelect)
new Vue({
el: '#app',
data: {
selectedOption: {
title: 'Read the Docs',
icon: 'fa-book',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
options: [
{
title: 'Read the Docs',
icon: 'fa-book',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
{
title: 'View on GitHub',
icon: 'fa-github',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
{
title: 'View on NPM',
icon: 'fa-database',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
{
title: 'View Codepen Examples',
icon: 'fa-pencil',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
}
]
}
})
body {
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
}
h1,.muted {
color: #2c3e5099;
}
h1 {
font-size: 26px;
font-weight: 600;
text-rendering: optimizelegibility;
-moz-osx-font-smoothing: grayscale;
-moz-text-size-adjust: none;
}
#app {
max-width: 30em;
margin: 1em auto;
}
#app .dropdown li {
border-bottom: 1px solid rgba(112, 128, 144, 0.1)
}
#app .dropdown li:last-child {
border-bottom: none;
}
#app .dropdown li a {
padding: 10px 20px;
display: flex;
width: 100%;
align-items: center;
font-size: 1.25em;
}
#app .dropdown li a .fa {
padding-right: 0.5em;
}
<script src="https://unpkg.com/vue-select#3.2.0/dist/vue-select.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>Vue Select - Custom Option Templating</h1>
<v-select :options="options" v-model="selectedOption" label="title">
<template slot="option" slot-scope="option">
<span class="fa" :class="option.icon"></span>
{{ option.title }}
</template>
</v-select>
</div>

Vuejs list reorder doesn't trigger transitions

I've been doing some vuejs for almost a year now and I never really got animations and transitions to work, it seems very unclear to me how all this is supposed to work and today I decided to try and finally understand them but once again I am stuck, the transition simply won't work and I don't understand what I'm doing wrong.
Here is my code:
The HTML
<div id="app">
<div class="row">
<div class="container-fluid">
<transition-group name="flip-list" tag="div" class="row horizontal-scroll">
<div class="col-xs-12 col-md-2 col-lg-2 col-card"
v-for="(someCard, index) in someCards" v-bind:key="index">
<div class="some-card" #click="changeOrder(someCard)">
{{ someCard.someTitle }}
</div>
</div>
</transition-group>
</div>
</div>
</div>
The JS
new Vue({
el: "#app",
data: {
someCards: [
{
order: 2,
someTitle: 'Title 1'
},
{
order: 2,
someTitle: 'Title 2'
},
{
order: 2,
someTitle: 'Title 3'
},
{
order: 3,
someTitle: 'Title 4'
},
{
order: 3,
someTitle: 'Title 5'
},
{
order: 1,
someTitle: 'Title 6'
},
{
order: 1,
someTitle: 'Title 7'
},
{
order: 1,
someTitle: 'Title 8'
},
{
order: 3,
someTitle: 'Title 1'
}
]
},
methods: {
changeOrder(someCardData) {
let newRandom = Math.floor(Math.random() * 3) + 1;
while (newRandom === someCardData.order) {
newRandom = Math.floor(Math.random() * 3) + 1;
}
someCardData.order = newRandom;
this.reorderList();
},
reorderList() {
this.someCards.sort(function(objA, objB) {
return objA.order - objB.order;
})
},
}
})
The CSS
/* default */
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
/* bootstrap */
.row {
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, .col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, .col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, .col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, .col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, .col-xl-auto {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
/* my css */
.horizontal-scroll {
overflow-x: auto;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.col-card {
max-width: 14%;
}
.some-card {
height: 220px;
font-size: 16px;
text-align: center;
padding-right: 5px;
margin-top: 5px;
-webkit-box-shadow: 1px 1px 5px rgba(0,0,0,.1);
box-shadow: 1px 1px 5px rgba(0,0,0,.1);
border-radius: 2px;
background: #fff;
margin-bottom: 20px;
position: relative;
border-top-style: solid;
}
.flip-list-move {
transition: transform 1s;
}
https://jsfiddle.net/eywraw8t/459088/
I am trying to have an animation triggered when I reorder a card in a list of cards aligned in a row. To change the position of a card, simply click on it. The reorder works but no transition is done.
I used this documentation
https://v2.vuejs.org/v2/guide/transitions.html#List-Move-Transitions
and have seen a couple of fairly easy tutorials but I must be missing something. Can someone please check the code out and tell me what it is ?
Thanks
It's because you're using the index as a key. The index will always be the same for the same position even if the card changes. I'd give each card a unique id and then use that as a key instead ..
new Vue({
el: "#app",
data: {
someCards: [{
id: 0,
order: 2,
someTitle: 'Title 1'
},
{
id: 1,
order: 2,
someTitle: 'Title 2'
},
{
id: 2,
order: 2,
someTitle: 'Title 3'
},
{
id: 3,
order: 3,
someTitle: 'Title 4'
},
{
id: 4,
order: 3,
someTitle: 'Title 5'
},
{
id: 5,
order: 1,
someTitle: 'Title 6'
},
{
id: 6,
order: 1,
someTitle: 'Title 7'
},
{
id: 7,
order: 1,
someTitle: 'Title 8'
},
{
id: 8,
order: 3,
someTitle: 'Title 1'
}
]
},
methods: {
changeOrder(someCardData) {
let newRandom = Math.floor(Math.random() * 3) + 1;
while (newRandom === someCardData.order) {
newRandom = Math.floor(Math.random() * 3) + 1;
}
someCardData.order = newRandom;
this.reorderList();
},
reorderList() {
this.someCards.sort(function(objA, objB) {
return objA.order - objB.order;
})
},
}
})
/* default */
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
/* bootstrap */
.row {
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12,
.col,
.col-auto,
.col-sm-1,
.col-sm-2,
.col-sm-3,
.col-sm-4,
.col-sm-5,
.col-sm-6,
.col-sm-7,
.col-sm-8,
.col-sm-9,
.col-sm-10,
.col-sm-11,
.col-sm-12,
.col-sm,
.col-sm-auto,
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11,
.col-md-12,
.col-md,
.col-md-auto,
.col-lg-1,
.col-lg-2,
.col-lg-3,
.col-lg-4,
.col-lg-5,
.col-lg-6,
.col-lg-7,
.col-lg-8,
.col-lg-9,
.col-lg-10,
.col-lg-11,
.col-lg-12,
.col-lg,
.col-lg-auto,
.col-xl-1,
.col-xl-2,
.col-xl-3,
.col-xl-4,
.col-xl-5,
.col-xl-6,
.col-xl-7,
.col-xl-8,
.col-xl-9,
.col-xl-10,
.col-xl-11,
.col-xl-12,
.col-xl,
.col-xl-auto {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
/* my css */
.horizontal-scroll {
overflow-x: auto;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.col-card {
max-width: 14%;
}
.some-card {
height: 220px;
font-size: 16px;
text-align: center;
padding-right: 5px;
margin-top: 5px;
-webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1);
box-shadow: 1px 1px 5px rgba(0, 0, 0, .1);
border-radius: 2px;
background: #fff;
margin-bottom: 20px;
position: relative;
border-top-style: solid;
}
.flip-list-move {
transition: transform 1s;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<div class="row">
<div class="container-fluid">
<transition-group name="flip-list" tag="div" class="row horizontal-scroll">
<div class="col-xs-12 col-md-2 col-lg-2 col-card" v-for="(someCard, index) in someCards" v-bind:key="someCard.id">
<div class="some-card" #click="changeOrder(someCard)">
{{ someCard.someTitle }}
</div>
</div>
</transition-group>
</div>
</div>
</div>
JSFiddle

Overlay items are not accessible

I am creating a full screen navigation
This navigation is opening on a button click. The problem is that the liand close button are not accessible. I am not able to click on them.
Html
<div id="myNav" class="overlay">
<v-btn class="white--text closebtn" icon v-on:click.prevent="CloseDialog">
<v-icon>cancel</v-icon>
</v-btn>
<div class="overlay-content">
About
Services
Clients
Contact
</div>
</div>
Css
.overlay {
height: 100%;
width: 0;
position: fixed;
z-index: 4;
top: 0;
left: 0;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0, 0.9);
overflow-x: hidden;
transition: 0.5s;
}
.overlay-content {
z-index :99;
position: relative;
top: 25%;
width: 100%;
text-align: center;
margin-top: 30px;
}
.overlay a {
padding: 8px;
text-decoration: none;
font-size: 36px;
color: #818181;
display: block;
transition: 0.3s;
}
.overlay a:hover, .overlay a:focus {
color: #f1f1f1;
}
.overlay .closebtn {
position: absolute;
top: 40px;
right: 55px;
font-size: 80px;
cursor :pointer
}
#media screen and (max-height: 450px) {
.overlay a {font-size: 20px}
.overlay .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}
Javscript
<script>
import { mapGetters } from "vuex"
export default {
computed: mapGetters({ isLoggedIn: 'CheckAuth', items: 'GetItems' }),
data() {
return {
clipped: true,
drawer: true,
fixed: false,
miniVariant: true,
right: true,
rightDrawer: false,
title: 'Vuetify.js'
}
},
methods: {
Login() {
this.$store.dispatch('ChangeAuth');
},
OpenDialog() {
document.getElementById("myNav").style.width = "100%";
},
CloseDialog() {
document.getElementById("myNav").style.width = "0%";
}
}
}
</script>
This is a pure CSS issue. You can either add :after pseudo element and create the background with it. Or you can use pointer-events: none;
CSS property on the overlay element.

Vuejs doesn't show icon in component

I try to use Vuejs with jquery. I don't why this is not working. When first loading, icons doesn't seem. I don't know what is wrong. when you click on items, plus and minus icons seen and it is working as expected. But why it is not working in first loading ?
Any help will be appreciated.
var data = {
name: 'My Tree',
children: [{
name: 'hello'
}, {
name: 'wat'
}, {
name: 'child folder',
children: [{
name: 'child folder',
children: [{
name: 'hello'
}, {
name: 'wat'
}]
}, {
name: 'hello'
}, {
name: 'wat'
}, {
name: 'child folder',
children: [{
name: 'hello'
}, {
name: 'wat'
}]
}]
}]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
computed: {
isFolder: function() {
return this.model.children &&
this.model.children.length
}
},
});
// boot up the demo
var demo = new Vue({
el: '#demo',
ready: function() {
},
data: {
treeData: data
}
});
Vue.nextTick(function() {
$('.tree li:has(ul)').addClass('parent_li').find(' > span').attr('title', 'Collapse this branch');
$('.tree li.parent_li > span').on('click', function(e) {
var children = $(this).parent('li.parent_li').find(' > ul > li');
if (children.is(":visible")) {
children.hide('fast');
$(this).attr('title', 'Expand this branch').find(' > i').addClass('icon-plus-sign').removeClass('icon-minus-sign');
} else {
children.show('fast');
$(this).attr('title', 'Collapse this branch').find(' > i').addClass('icon-minus-sign').removeClass('icon-plus-sign');
}
e.stopPropagation();
});
})
.tree {
min-height: 20px;
padding: 19px;
margin-bottom: 20px;
background-color: #fbfbfb;
border: 1px solid #999;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05)
}
.tree li {
list-style-type: none;
margin: 0;
padding: 10px 5px 0 5px;
position: relative
}
.tree li::before,
.tree li::after {
content: '';
left: -20px;
position: absolute;
right: auto
}
.tree li::before {
border-left: 1px solid #999;
bottom: 50px;
height: 100%;
top: 0;
width: 1px
}
.tree li::after {
border-top: 1px solid #999;
height: 20px;
top: 25px;
width: 25px
}
.tree li span {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 1px solid #999;
border-radius: 5px;
display: inline-block;
padding: 3px 8px;
text-decoration: none
}
.tree li.parent_li>span {
cursor: pointer
}
.tree>ul>li::before,
.tree>ul>li::after {
border: 0
}
.tree li:last-child::before {
height: 30px
}
.tree li.parent_li>span:hover,
.tree li.parent_li>span:hover+ul li span {
background: #eee;
border: 1px solid #94a0b4;
color: #000
}
<link href="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<ul id="demo">
<div class="tree well">
<item :model="treeData"></item>
</div>
</ul>
<script type="text/x-template" id="item-template">
<li>
<span><i v-if="isFolder" class="icon-minus-sign"></i> {{model.name}}</span>
<ul v-if="isFolder">
<item v-for="model in model.children" :model="model"></item>
</ul>
</li>
</script>
Actually it was my fault. I called wrong class name for the icon. I am updating and everything will work fine. I hope this vue recursive tree model will be useful for others.