Vue click prevent triggers - vue.js

I'm making a menu, with some accordion links, that when clicked, will show more options. The problem now, is that when I click one, they all trigger.
I need to trigger only the element that has been clicked.
I've tried #click.prevent, stop, self etc and not working. Maybe I'm missing something??
<li :aria-expanded="foo">
<button id="foo-1" #click="foo = !foo" :aria-pressed="foo" :aria-expanded="foo" >
FOO
</button>
<ul v-show="foo">
<li> Accordion option </li>
</ul>
</li>
<li :aria-expanded="foo">
<button id="foo-2" #click="foo = !foo" :aria-pressed="foo" :aria-expanded="foo" >
FOO
</button>
<ul v-show="foo">
<li> Accordion option </li>
</ul>
</li>
I'm using foo as boolean type.
Any idea??
Thanks you!!

The problem is all the <li>s are bound to the same foo variable, so editing one reference affects all others.
The solution is to create separate variables for each <li>. For example, you could change foo to be an array, and bind each individually:
<template>
<li>
<button #click="foo[0] = !foo[0]">FOO</button>
</li>
<li>
<button #click="foo[1] = !foo[1]">FOO</button>
</li>
<template>
<script>
export default {
data() {
return {
foo: []
}
}
}
</script>

Related

How to make vuejs navbar link active on click without route

I have a vue bootstrap navbar. All of the nav items have a route except one. The one that doesn't (Contact) launches a modal on click. When an item is selected I want the item to be white.
I do this and it works for items that have a corresponding route:
:active='$route.name ==""'
Navbar
<ul class="navbar-nav">
<li class="nav-item">
<router-link class="nav-link" :to="{
path: '/',
hash: 'home',
}" :active='$route.name =="home"'>Home</router-link>
</li>
<li class="nav-item">
<router-link to="/About" :active='$route.name =="about"' class="nav-link">About</router-link>
</li>
<li class="nav-item">
<a class="nav-link" v-b-modal.modal-contact>Contact</a>
</li>
</ul>
How do I get the Contact item to be active on click?
I had the same problem as you and solved it like this.
First, you define a method that will use the name property of this.$route
export default {
name: 'App',
methods: {
getActiveNavLink(name) {
//This is for the navbar classes, you can modify them as
//as you need. (This will be assigned every-time we call this
//function).
let classString = "nav-item nav-link "
//We compare the given name with the route current name.
if (this.$route.name === name) {
//If it is true, we append to the class string the "active" value
classString += "active"
}
//Return the class string.
return classString;
}
}
}
Then in your navbar you do something like this
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">The navegation bar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<router-link
:to="{ name: 'home'}"
:class="getActiveNavLink('home')" >
Home
</router-link>
<router-link
:to="{ name: 'secondRoute'}"
:class="getActiveNavLink('secondRoute')"><!--class="nav-item nav-link">-->
To the second route!
</router-link>
<router-link :to=...>
...
</router-link>
</div>
</div>
</div>
</nav>
That way, everytime you call the getActiveNavLink you pass the name of the route to compare, and if the name of the route is the same as your $route.name you will get an active navbar element!
Also, dont worry about the router-link classes being overwritten, they are not, the classes that we add, are appended, not overwritten.
its works for me for add class attributte and methods calling
You could use router.push(). When you open the modal, push to that path, when you leave the modal, push to the previous path.
https://router.vuejs.org/guide/essentials/navigation.html

Class and Style binding on certain conditions

I'm making a navigation component with nuxt.js, vue and storyblok. In this navigation i have a few items. i'm getting my navi items out of the storyblok API. i want to style certain navi items differently when the 'highlighted' attribute in the API equals to true or false.
My problem is that i dont exactlty know how to do that. this is what i have at this point.
div in my navigation component:
<div v-if="items" class="main-nav">
<nav>
<ul>
<li v-bind:class="{ highlighted: item.highlighted === isHighlighted, not_highlighted: item.highlighted === isNotHighlighted}" v-editable="items" :key="index" v-for="(item, index) in items">
<LinkType class="nav-link" :link="item.link" :linkText="item.name">{{ item.name }}</LinkType>
</li>
</ul>
</nav>
</div>
this is how i retrieve my data:
data() {
return {
items: this.$store.state.settings.main_nav ? this.$store.state.settings.main_nav : [],
isHighlighted: true,
isNotHighlighted: false
}
}
whenever i try to console.log item.hightlighted it gives back an undefined error. i would appreciate some help.
Try as below =>
<div v-if="items" class="main-nav">
<nav>
<ul>
<li v-bind:class="item.highlighted === isHighlighted ? 'highlighted' : 'not_highlighted'" v-editable="items" :key="index" v-for="(item, index) in items">
<LinkType class="nav-link" :link="item.link" :linkText="item.name">{{ item.name }}</LinkType>
</li>
</ul>
</nav>
</div>
You can also remove isNotHighlighted: false from data.

How to make a bootstrap dropdown parent link clickable

A parent link of a bootstrap dropdown isn't clickable by default so the link isn't working.
This is the html code:
<div class="dropdown">
<a id="item7" class="dropdown-toggle" data-toggle="dropdown" href="/mylink">MyLink</a>
<ul class="dropdown-menu">
<li class="submenuitem">
item 1
</li>
<li class="submenuitem">
item 2
</li>
</ul>
</div>
I want /myLink to clickable. How do I fix that?
Add this code to you page and parent links will work:
<script>
jQuery(function($) {
$('.dropdown > a').click(function(){
location.href = this.href;
});
});
</script>
I found that the easiest way to do it in bootstrap 4 is by deleting the "data-toggle" attribute from the parent element!

After I refresh the website the selectedIndex will change to the initial value

I have the
after I refresh the browser, the selected class go to the 首页, do not stay in 数据中心.
Who can help me with the issue?
my key code:
template:
<ul class="nav">
<li class="nav-item" ><router-link :to="homePath" :class="selectedIndex===0 ? 'selected' : '' " #click.native="selectedIndex=0">首页</router-link></li>
<li class="nav-item" ><router-link :to="dataCenterPath" :class="selectedIndex===1 ? 'selected' : '' " #click.native="selectedIndex=1">数据中心</router-link></li>
</ul>
script:
data(){
return {
selectedIndex: 0,
...
}
}
Whenever you refresh the page the JavaScript is reloaded and all the properties revert back to their initial values.
In your case selectedIndex is set back to 0.
To add the selected class to the link automatically when the target route is active make use of active-class prop on the ,router-link> as follows
<ul class="nav">
<li class="nav-item" ><router-link :to="homePath" active-class="selected" #click.native="selectedIndex=0">首页</router-link></li>
<li class="nav-item" ><router-link :to="dataCenterPath" active-class="selected" #click.native="selectedIndex=1">数据中心</router-link><li>
</ul>
edit
<ul class="nav">
<li class="nav-item" ><router-link :to="homePath" exact active-class="selected" #click.native="selectedIndex=0">首页</router-link></li>
<li class="nav-item" ><router-link :to="dataCenterPath" active-class="selected" #click.native="selectedIndex=1">数据中心</router-link><li>
</ul>
Make use of exact prop on home router link

How to access V-for elements

I have Large Image elements dynamically rendered using v-for
<div class="preview-pic tab-content">
<div class="tab-pane"
v-bind:class="activeClass"
:id= index
v-for="(imgLink, index) in itemSelected.itemImages"
v-bind:ref="index">
<img :src="imgLink.urlLargeImage" />
</div>
</div>
I also have Thumbnail images rendered in v-for
<li v-for="(imgLink, index) in itemSelected.itemImages">
<a #click="onImgClicked" :data-target="'#' + index" data-toggle="tab">
<img :src="imgLink.urlThumbnail" />
</a>
</li>
in my methods:
methods:{
onImgClicked: function (index) {
document.getElementById(index).className="active" // works but is it vue-way?
this.$refs.0.className = "active" // only works if i know what index of the thumbnail will be clicked
}
}
When a thumbnail image is clicked, I'd like to make it's corresponding large image to be active by setting the css class "active". I can accomplish this with document.getelementbyid, but is that the vue-way? My attempt with $refs
I also attempted using v-bind but I was unsuccessful because either all large images will be active or not active.
If you only want one image active at a time, add an activeImage property to your data.
data(){
return {
activeImage: null
}
}
Modify your template in this way.
<div class="preview-pic tab-content">
<div class="tab-pane"
:class="{active: imgLink === activeImage}"
:id= index
v-for="(imgLink, index) in itemSelected.itemImages"
v-bind:ref="index">
<img :src="imgLink.urlLargeImage" />
</div>
</div>
...
<li v-for="(imgLink, index) in itemSelected.itemImages">
<a #click="activeImage = imgLink"
:data-target="'#' + index" data-toggle="tab">
<img :src="imgLink.urlThumbnail" />
</a>
</li>
And get rid of your onImgClicked. Also, you will want to set activeImage to null when you don't want any image active.
Alternatively, if more than one image could be active at a time, add a boolean active property to your imgLink objects, and change your template to
:class="{active: imgLink.active}"
and
#click="imgLink.active = !imgLink.active"