I have some html using Vue.js here:
<div id="app">
<ul class="navbar-nav">
<li class="nav-item" v-for="tab in tabs">
{{ tab.name }}
</li>
</ul>
</div>
I have the javascript here:
var app = new Vue({
el: '#app',
data: {
tabs: [
{ name: "Home", active: "" },
{ name: "Challenges", active: "active" },
{ name: "Scoreboard", active: "" },
{ name: "About", active: "" }
]
}
});
I want to set class to tabs.active since I'm using bootstrap. How can I do that?
Add
v-bind:class="tab.active"
So your code should look like this:
var app = new Vue({
el: '#app',
data: {
tabs: [{
name: "Home",
active: ""
},
{
name: "Challenges",
active: "active"
},
{
name: "Scoreboard",
active: ""
},
{
name: "About",
active: ""
}
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul class="navbar-nav">
<li class="nav-item" v-for="tab in tabs" v-bind:class="tab.active">
{{ tab.name }}
</li>
</ul>
</div>
Use a class binding like this:
<li class="nav-item" :class="{active: tab.active === 'active'}" v-for="tab in tabs">
new Vue({
el: '#app',
data: {
tabs: [
{ name: "Home", active: "" },
{ name: "Challenges", active: "active" },
{ name: "Scoreboard", active: "" },
{ name: "About", active: "" }
]
}
});
.active .nav-link {
color: white;
background: blue;
}
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<ul class="navbar-nav">
<li class="nav-item" :class="{active: tab.active === 'active'}" v-for="tab in tabs">
{{ tab.name }}
</li>
</ul>
</div>
Related
This navbar has a 1 level dropdown menu. I want to create up to 3 levels but when adding a grandchildren condition to the children it won't work. With this setting, how would I be able to create a 3 level dropdown menu?
Component Header.vue
<template>
<!-- Top menu -->
<nav
id="mainNav"
:class="$route.path==='/home' ? '' : 'bg-primary'"
class="navbar navbar-expand-md navbar-dark fixed-top"
>
<!-- <div class="rtl-layout" #click="addToggleClass()">RTL</div>-->
<div class="container ">
<router-link class="navbar-brand" routerLinkActive="active-link" to="/home">
<!-- <img src="/static/img/zemle-logo.png" class="img-fluid" width="110" height="37">-->
<h3 class="text-white">Logo</h3>
</router-link>
<button
aria-controls="navbarCollapse" aria-expanded="true" aria-label="Toggle navigation" class="navbar-toggler"
data-target="#navbarCollapse" data-toggle="collapse" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div id="navbarCollapse" class="collapse navbar-collapse">
<ul id="main" class="navbar-nav ml-auto main-menu list-unstyled">
<li
v-for="(menuItem,i) in menus"
:id="'menuNo'+i"
:key="i"
class="parent nav-item"
#click="menuToggleLink('menuNo'+i);"
>
<router-link
v-if="menuItem.type == 'link'"
:to="menuItem.state"
class="nav-link"
#click.native="removeCollapseInClass();"
>
{{ menuItem.name }}
</router-link>
<a
v-if="menuItem.type == 'sub'"
class="nav-link"
href="javascript:void(0)"
>
{{ menuItem.name }}
<i :class="menuItem.icon" #click.stop="menuToggle('menuNo'+i)"></i>
</a>
<ul
v-if="menuItem.type == 'sub' && menuItem.children"
class="sub-menu arrow-up list-unstyled">
<li
v-for="(grandchildItem,i) of menuItem.children"
:key="i"
class="nav-item"
>
<router-link
v-if="grandchildItem.type == 'link'"
:to="grandchildItem.state"
class="nav-link"
#click.native="removeCollapseInClass()"
>
{{ grandchildItem.name }}
</router-link>
</li>
</ul>
</li>
<li>
<div
class="search-form"
click-outside
>
<span
data-target="#search-style-simple"
#click="showSearch()"
>
<i class="fa fa-search"></i>
</span>
<div
id="search-style-simple"
:class="{'search-active': searchactive}"
class="module-container"
>
<form action="javascript:void(0);" class="search-box" method="get" role="search">
<input class="form-control" name="" placeholder="Search" type="search" value=""/>
<button type="submit"><i class="fa fa-search"></i></button>
</form>
</div><!-- /module-container -->
</div><!-- /module -->
</li>
</ul>
</div>
</div>
</nav>
</template>
<script>
export default {
data() {
return {
searchactive: false,
menus: [
{
state: "/home",
name: "Home",
type: "link"
},
{
state: "",
name: "Products",
type: "sub",
icon: 'fa fa-caret-down',
children: [
{state: 'apparel', name: 'Apparel', type: "link"},
{state: 'bathroom', name: 'Bathroom', type: "link"},
{state: 'bedding', name: 'Bedding', type: "link"},
{state: 'decorative-details', name: 'Decorative Details', type: "link"},
]
},
{
state: "",
name: "Shop",
type: "sub",
icon: 'fa fa-caret-down',
children: [
{state: 'product-grid', name: 'Product Grid', type: "link"},
{ state: 'product-cart', name: 'Product Cart', type:"link"},
{ state: 'product-checkout', name: 'Product Checkout', type:"link"},
{state: 'product-detail', name: 'Product Detail', type: "link"}
]
},
{
state: "",
name: "Blog",
type: "sub",
icon: 'fa fa-caret-down',
children: [
{state: 'blog-column3', name: 'Blog Column1', type: "link"},
{state: 'blog-masonry3', name: 'Blog Masonry', type: "link"},
{state: 'blog-sidebar', name: 'Blog Sidebar', type: "link"},
{state: 'blog-detail', name: 'Blog Detail', type: "link"}
]
}
]
}
},
mounted() {
this.onScrollEvent();
},
methods: {
showSearch() {
this.searchactive = !this.searchactive;
},
menuToggleLink(id) {
if (document.getElementById(id).classList.contains("open")) {
document.getElementById(id).classList.remove("open");
} else if (!document.getElementById(id).classList.contains("open")) {
let elements = document.querySelectorAll(".parent");
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('open');
}
document.getElementById(id).classList.add("open");
}
},
addToggleClass() {
document.querySelector("body").classList.toggle("rtl-enable");
},
removeCollapseInClass() {
document.getElementById("navbarCollapse").classList.remove('show');
},
onScrollEvent() {
var headerSticky = document.getElementById('mainNav');
window.onscroll = function () {
if (window.pageYOffset >= 100) {
headerSticky.classList.add("scrollHeader");
} else {
headerSticky.classList.remove("scrollHeader");
}
}
}
}
}
</script>
I have tried modifying the children and adding a grandchildren to it but it won't display the 2nd or 3rd level menu.
I am trying to create a 2 level navigation bar with this code but when I try to add another children to one of the children in the scrip it won't work. The idea is for the user to go to a second level where he can select other links. It should hover on link in navbar, then go to the 1st level menu and then hover on one of the option to get the 2nd level menu.
<template>
<!-- Top menu -->
<nav
id="mainNav"
class="navbar navbar-expand-md navbar-dark fixed-top"
:class="$route.path==='/home' ? '' : 'bg-primary'"
>
<!-- <div class="rtl-layout" #click="addToggleClass()">RTL</div>-->
<div class="container ">
<router-link class="navbar-brand" to="/home" routerLinkActive="active-link">
<!-- <img src="/static/img/zemle-logo.png" class="img-fluid" width="110" height="37">-->
<h3 class="text-white" >Sospes Logo</h3>
</router-link>
<button
class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="true" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul id="main" class="navbar-nav ml-auto main-menu list-unstyled">
<li
#click="menuToggleLink('menuNo'+i);"
class="parent nav-item"
v-for="(menuItem,i) in menus"
:id="'menuNo'+i"
:key="i"
>
<router-link
class="nav-link"
:to="menuItem.state"
v-if="menuItem.type == 'link'"
#click.native="removeCollapseInClass();"
>
{{ menuItem.name }}
</router-link>
<a
v-if="menuItem.type == 'sub'"
class="nav-link"
href="javascript:void(0)"
>
{{ menuItem.name }}
<i :class="menuItem.icon" #click.stop="menuToggle('menuNo'+i)"></i>
</a>
<ul
v-if="menuItem.type == 'sub' && menuItem.children"
class="sub-menu arrow-up list-unstyled" >
<li
class="nav-item"
v-for="(grandchildItem,i) of menuItem.children"
:key="i"
>
<router-link
class="nav-link"
:to="grandchildItem.state"
v-if="grandchildItem.type == 'link'"
#click.native="removeCollapseInClass()"
>
{{ grandchildItem.name }}
</router-link>
</li>
</ul>
</li>
<li>
<div
class="search-form"
click-outside
>
<span
data-target="#search-style-simple"
#click="showSearch()"
>
<i class="fa fa-search"></i>
</span>
<div
class="module-container"
:class="{'search-active': searchactive}"
id="search-style-simple"
>
<form role="search" method="get" class="search-box" action="javascript:void(0);">
<input type="search" class="form-control" placeholder="Search" value="" name="" />
<button type="submit"><i class="fa fa-search"></i></button>
</form>
</div><!-- /module-container -->
</div><!-- /module -->
</li>
</ul>
</div>
</div>
</nav>
</template>
<script>
export default{
data(){
return{
searchactive:false,
menus: [
{
state: "/home",
name: "Home",
type:"link"
},
{
state:"",
name:"Pages",
type:"sub",
icon: 'fa fa-caret-down',
children: [
{ state: 'about', name: 'About', type:"link"},
{ state: 'features', name: 'Features', type:"link"},
{ state: 'contact', name: 'Contact', type:"link"},
{ state: 'pricing', name: 'Pricing', type:"link"},
{ state: 'search', name: 'Search', type:"link"},
{ state: 'portfolio-v1', name: 'Products V1', type:"link"},
{ state: 'portfolio-v2', name: 'Products V2', type:"link"},
{ state: 'portfolio-v3', name: 'Products V3', type:"link"}
]
},
{
state:"",
name:"Features",
type:"sub",
icon: 'fa fa-caret-down',
children: [
{ state: 'login', name:'Login', type:"link"},
{ state: 'sign-up', name: 'Sign Up', type:"link"},
{ state: 'thank-you', name: 'Thank You', type:"link"},
{ state: 'maintenance', name: 'Maintenance', type:"link"},
{ state: 'not-found', name: '404', type:"link"}
]
},
{
state:"",
name:"Shop",
type:"sub",
icon: 'fa fa-caret-down',
children: [
{ state: 'product-grid', name:'Product Grid', type:"link"},
{ state: 'product-cart', name: 'Product Cart', type:"link"},
{ state: 'product-checkout', name: 'Product Checkout', type:"link"},
{ state: 'product-detail', name: 'Product Detail', type:"link"}
]
},
{
state:"",
name:"Blog",
type:"sub",
icon: 'fa fa-caret-down',
children: [
{ state: 'blog-listing-sidebar', name:'blog column ', type:"link"},
{ state: 'blog-column3', name: 'Blog Column1', type:"link"},
{ state: 'blog-masonry3', name: 'Blog Masonry', type:"link"},
{ state: 'blog-sidebar', name: 'Blog Sidebar', type:"link"},
{ state: 'blog-detail', name: 'Blog Detail', type:"link"}
]
}
]
}
},
mounted(){
this.onScrollEvent();
},
methods:{
showSearch(){
this.searchactive = !this.searchactive;
},
menuToggleLink(id){
if (document.getElementById(id).classList.contains("open")){
document.getElementById(id).classList.remove("open");
} else if(!document.getElementById(id).classList.contains("open")) {
let elements = document.querySelectorAll(".parent");
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('open');
}
document.getElementById(id).classList.add("open");
}
},
addToggleClass(){
document.querySelector("body").classList.toggle("rtl-enable");
},
removeCollapseInClass(){
document.getElementById("navbarCollapse").classList.remove('show');
},
onScrollEvent(){
var headerSticky = document.getElementById('mainNav');
window.onscroll = function() {
if (window.pageYOffset >= 100) {
headerSticky.classList.add("scrollHeader");
} else {
headerSticky.classList.remove("scrollHeader");
}
}
}
}
}
</script>
<style>
.scrollHeader{
background-color: #0B3242;
}
</style>
This is the menu and below my navigation menu and method that on click should open the subitems inside nav item on click but I cant seem to be find where I'm lacking
[![dropdown_menu][1]][1]
new Vue({
el: '#app',
data: {
//menu
"menu_title": "a",
"child_routes": [{
"path": "/a1",
"menu_title": "a1"
},
{
"path": "/a2",
"menu_title": "a2"
}
]
},
{
"menu_title": "b",
"child_routes": [{
"path": "/b1",
"menu_title": "b1"
},
{
"path": "/b2",
"menu_title": "b2"
},
{
"path": "/b1",
"menu_title": "b3"
}
]
},
{
"menu_title": "c",
"child_routes": [{
"path": "/c1",
"menu_title": "c1"
},
{
"path": "/c2",
"menu_title": "c2"
},
{
"path": "/c3",
"menu_title": "c3"
}
]
}
},
methods: {
navlinks() {
var navItemParent = document.querySelector("nav-item");
var navLink = document.querySelector(".idb-nav .nav-item .nav-link");
var navItem = document.querySelector(".idb-nav .nav-item");
navItem.classList.toggle("active");
if (navItem.contains("active")) {
navItem.classList.remove("active");
navLink.classList.toggle("active");
}
}
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<nav class="idb-sidebar-nav">
<ul class="idb-nav list-unstyled m-15 p-0">
<template v-for="(menu, index) in sideBarLinks.routes">
<li class="nav-item" v-if="menu.child_routes!=null" :key="index">
<a href="javascript:void(0)" class="nav-link" #click="navlinks" >
<i :class="menu.menu_icon" class="menu-icon"></i>
<span class="menu-title">{{menu.menu_title}}</span>
</a>
<ul class="list-unstyled sub-menu">
<router-link
:to="subMenu.path"
tag="li"
v-for="(subMenu, key) in menu.child_routes"
:key="key"
>
<a href="javascript:void(0)" class="sub-menu-nav-link">
<span>{{subMenu.menu_title}}</span>
</a>
</router-link>
</ul>
</li>
<router-link
:key="index"
:to="menu.path"
tag="li"
class="nav-item"
v-else
>
<a class="nav-link">
<i :class="menu.menu_icon" class="mr-15"></i>
<span class="menu-title">{{menu.menu_title }}</span>
</a>
</router-link>
</template>
</ul>
</nav>
</div>
The classes toggling should be managed as part of the data. Try this and see if it works for you:
HTML
<div id="app">
<nav class="idb-sidebar-nav">
<ul class="idb-nav list-unstyled m-15 p-0">
<template v-for="(menu, index) in sideBarLinks.routes" :key="index">
<li class="nav-item"
v-if="menu.child_routes && menu.child_routes.length">
<a :class="[ 'nav-link', { 'active': menu.active } ]"
href="javascript:void(0);"
#click="toggleMenu(index)">
<i :class="menu.menu_icon" class="menu-icon"></i>
<span class="menu-title">{{menu.menu_title}}</span>
</a>
<ul class="list-unstyled sub-menu">
<router-link tag="li"
v-for="(subMenu, key) in menu.child_routes"
:key="key"
:to="subMenu.path">
<a href="javascript:void(0);" class="sub-menu-nav-link">
<span>{{subMenu.menu_title}}</span>
</a>
</router-link>
</ul>
</li>
<router-link v-else
:key="index"
:to="menu.path"
tag="li"
class="nav-item">
<a :class="[ 'nav-link', { 'active': menu.active } ]"
href="javascript:void(0);"
#click="toggleMenu(index)">
<i :class="menu.menu_icon" class="mr-15"></i>
<span class="menu-title">{{menu.menu_title }}</span>
</a>
</router-link>
</template>
</ul>
</nav>
</div>
routes.json
For improved readability and maintainability, you'd best be moving the list to separate file.
[
{
"menu_title": "a",
"child_routes": [
{
"path": "/a1",
"menu_title": "a1"
},
{
"path": "/a2",
"menu_title": "a2"
}
],
active: true // First item opened by default (if you like)
},
{
"menu_title": "b",
"child_routes": [
{
"path": "/b1",
"menu_title": "b1"
},
{
"path": "/b2",
"menu_title": "b2"
},
{
"path": "/b1",
"menu_title": "b3"
}
],
active: false
},
{
// ...
}
]
app.js
import * as routes from './routes.json';
const vm = new Vue({
el: '#app',
data() {
return {
sideBarLinks: {
routes
}
}
},
methods: {
toggleSidebar(index) {
this.sideBarLinks
.routes
.forEach((menu, i) => menu.active = (i === index));
}
}
});
I am trying to get value from object and push into array using Vue. I wanted to separate every value when into different array every time I click my item. Every time I click todo should be push on different array, how I can separate to push into different array
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
mytodo:[]
},
methods: {
myClickTodo: function(e){
this.mytodo.push(e.target.innerText)
console.log(e.target.innerText)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h2>My list One:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>todo 1 </p>
<p>{{mytodo}}</p>
<hr>
<h2>My list Two:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo">
{{ todo.text + " from todo two" }}
</li>
</ul>
<p>todo 2</p>
<p>{{mytodo}}</p>
</div>
Quick fix
One solution is to change mytodos into an array of 2 arrays (one for each TODO list):
data() {
return {
mytodo: [[], []]
};
}
Then, update your click-handler to pass the specific array element of mytodos along with the todo item to be added:
<!-- My list One -->
<li v-for="todo in todos" #click="myClickTodo(mytodos[0], todo)">
<!-- My list Two -->
<li v-for="todo in todos" #click="myClickTodo(mytodos[1], todo)">
And update myClickTodo to handle these new arguments:
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
}
}
new Vue({
el: '#app',
data: () => ({
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
mytodo: [[], []]
}),
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
console.log(todo.text);
}
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<h2>My list One:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo[0], todo)">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>todo 1 </p>
<p>{{mytodo[0]}}</p>
<hr>
<h2>My list Two:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo[1], todo)">
{{ todo.text + " from todo two" }}
</li>
</ul>
<p>todo 2</p>
<p>{{mytodo[1]}}</p>
</div>
Components
A cleaner solution is to encapsulate the TODO list into a reusable component (e.g., named "my-list"):
Vue.component('my-list', {
data: () => ({
title: '',
mytodo: [],
}),
props: {
todos: {
type: Array,
default: () => []
}
},
template: `<div>
<h2>{{title}}</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo, todo)">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>{{mytodo}}</p>
</div>`,
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
console.log(todo.text);
}
}
});
...which would allow you to simplify your app template to this:
<my-list title="My List One:" :todos="todos"></my-list>
<my-list title="My List Two:" :todos="todos"></my-list>
Vue.component('my-list', {
data: () => ({
mytodo: [],
}),
props: {
title: '',
todos: {
type: Array,
default: () => []
}
},
template: `<div>
<h2>{{title}}</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo, todo)">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>{{mytodo}}</p>
</div>`,
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
console.log(todo.text);
}
}
});
new Vue({
el: '#app',
data: () => ({
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
}),
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<my-list title="My List One:" :todos="todos"></my-list>
<my-list title="My List Two:" :todos="todos"></my-list>
</div>
I'm creating a basic MTG Deckbuilder using Vue.Js. I'm trying to have the user type the card name into an input box then when the button is clicked, the deck list is update with the card name. Currently,the list add's a blank element for the card instead of the card name. Any ideas?
app.Vue:
<template>
<div id="app">
<deckBuilder #addCard="addCard" :title="title" :card="card" :deck="deck" />
</div>
</template>
<script>
import deckBuilder from './components/deckBuilder'
export default {
name: 'app',
components: {
deckBuilder,
},
data: () => ({
title: 'MTG Deck Builder',
card: {
name: '',
},
deck:[],
}),
methods: {
addCard: function(event,) {
this.deck.push(this.card.name);
},
},
}
</script>
deckBuilder.Vue:
<template>
<div>
<h1>{{ title }}</h1>
<input v-model="card.name" placeholder="Type a Card Name" />
<p> the card is: {{ card.name }}
<button #click="addCard">Add!</button>
<h2>Deck</h2>
<ul>
<li v-for="item in deck">{{ item.card }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'deckBuilder',
props: ['title', 'card', 'deck'],
methods: {
addCard() {
this.$emit('addCard')
}
},
}
</script>
Because you push string item instead of object
this.deck.push(this.card.name);
Correct template will be {{ item }}, not {{ item.card }}
This is because you are not emitting any data in your $emit
Try this,
In deckbuilder.vue
addCard() {
this.$emit('addCard',this.card.name);
}
In app.vue
addCard: function(cardName){
this.deck.push(cardName);
}
In html, v-for should be this way
<li v-for="item in deck">{{ item }}</li>
Try This
<!-- Menu Content -->
<ul class="nav-list" style="overflow: visible;">
<!-- Items -->
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<nuxt-link :to="menuItem.link" :class="menuItem.class">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<!-- Link Name -->
<span class="links_name">{{ menuItem.name }}</span>
</nuxt-link>
</li>
</span>
</ul>
<script>
export default {
name: 'SidebarMenu',
menuItems: {
type: Array,
default: () => [
{
link: '/',
name: '_home',
icon: 'bx-home',
class: '',
},
{
link: '/blog',
name: '_blog',
icon: 'bx-edit',
class: '',
},
{
link: '/projects',
name: '_projects',
icon: 'bx-code',
class: ''
},
{
link: '/about',
name: '_about',
icon: 'bx-user',
class: ''
},
],
},
}
</script>