Vue js show hide element on click - javascript

I am new in vue js. I want to show hide elements on click.
So that What I can do -
make a property in data object like
isHidden: false
and add a mehtod like
showHide(){
return this.isHidden = !this.isHidden;
}
And bind the showHide method on click event like
<li #click="showHide">Some text</a>
But the problem is- if there are several list items binding the same click event,
all lists will be shown on click, or all will hide. But I want the
target element will only show or hide by click.
How can I do this, please?

You can use some data to determine what element you want show/hide. For example: id, index of each element
<button v-for="(i, ind) in listElement" #click="toggleElement(ind)" :key="ind">
Toggle {{ i }}
</button>
<p v-for="(i, ind) in listElementShow" :key="ind">
Element: {{ i }}
</p>
Logic:
data() {
return {
listElement: [ { name: 1, isShow: true}, { name: 2, isShow: true}],
}
},
computed: {
listElementShow() {
return this.listElement.filter(e => e.isShow);
}
}
methods: {
toggleElement(index) {
this.listElement[index].isShow = !this.listElement[index].isShow;
}
}

You can do something like this:
<template>
<ul class="list-with-hidden-items">
<li
v-for="item in list"
:key="item.id"
#click="showHide(item.id)"
>
{{ item.text }}
</li>
</ul>
</template>
<script>
export default {
data: () => ({
hidden: {}
}),
methods: {
showHide(id) {
this.$set(this.hidden, id, !this.hidden[id]);
}
}
}
</script>
and then you can render where you want your item to be shown like this:
<div v-if="!this.hidden.item1">I am shown because of item1 is not hidden</div>

To elaborate on some of these answers, you want to keep track of what's hidden and not hidden in your data object using a isHidden flag or similar.
Then when you loop through your object using v-for, conditionally set the isHidden property for the current item when it's clicked.
new Vue({
el: "#app",
data: {
itemList: [{
"id": 1,
"text": "first item",
"isHidden": false
},
{
"id": 2,
"text": "second item",
"isHidden": true,
},
{
"id": 3,
"text": "third item",
"isHidden": false,
},
],
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in itemList" :key="item.id">
<button #click="item.isHidden = !item.isHidden">
<span v-if="item.isHidden">Show</span>
<span v-else>Hide</span>
</button>
<span v-if="!item.isHidden">{{ item.text }}</span>
</li>
</ul>
</div>

You can use a dynamically bound classObject to do such a thing.
See Class and Style Bindings
Sandbox
<template>
<div #click="showHide()" :class="{ isHidden: isHidden }">
<p>This is a thing</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
isHidden: false,
};
},
methods: {
showHide() {
this.isHidden = !this.isHidden;
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.isHidden {
background-color: grey;
}
div {
background-color: #fff;
}
</style>

Related

Am having issue implementing the javascript code with vue

Am very new to vuejs.am trying to replicate the javascript with vue. where a user can toggle button. I have a list of buttons and I would like to toggle the active class but remove the active class from all other buttons.. Is there a better way of writtting the function without the querySelector? Am really stuck..
<template>
<div #click="selectItem" class="menu-tabs">
<button type="btn" class="menu-tab-item active" data-target="#remis-transfer"> Transfer
</button>
<button type="btn" class="menu-tab-item text-muted" data-target="#bank-transfer">
Transfer Money
</button>
<button type="btn" class="menu-tab-item text-muted" data-target="#fueling">
Fueling
</button>
</div>
</template>
<script>
export default {
methods: {
selectItem(e) {
if (e.target.classList.contains("menu-tab-item") && !e.target.classList.contains("active")) {
const target = e.target.getAttribute("data-target")
menuTabs.querySelector(".active").classList.remove("active");
e.target.classList.add("active");
const menuSection = document.querySelector(".menu-section");
menuSection.querySelector(".menu-tab-content.active").classList.remove("active");
menuSection.querySelector(target).classList.add('active');
}
}
}
}
</script>
Look at the code
var Main = {
data() {
return {
active: 0,
buttonList: [
{
text: "Transfer",
target: "#remis-transfer",
},
{
text: "Transfer Money",
target: "#bank-transfer",
},
{
text: "Fueling",
target: "#fueling",
},
],
};
},
methods: {
selectItem(i) {
this.active = i;
},
},
};
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
<div class="menu-tabs">
<button
type="btn"
class="menu-tab-item"
v-for="(item, index) in buttonList"
:class="[{ active: active == index }, { 'text-muted': active != index }]"
:data-target="item.target"
:key="index"
#click="selectItem(index)"
>
{{ item.text }}
</button>
</div>
</div>
You can simply define some states like:
data() {
return {
myActiveClass: 'active',
myMutedClass: 'text-muted'
}
},
and pass this myActiveClass and myMutedClass states to your elements like this:
class=menu-tab-item ${myMutedClass} ${myActiveClass}
with this approach, you can quickly achieve what you want. So when you want an element to not be active, in your function you can make myActiveClass = '', or if you want the text to lose muted class you can say myMutedClass = '' .
Just make sure to play with states in the way you want.

how to bind value of v-for to v-if

I'm working with BootstrapVue. To my problem: I have a v-for in my template in which I have two buttons.
Looping over my v-for my v-if doesn't generate unique IDs and than after clicking one button each button will be triggered (from Open me! to Close me! and other way around).
How can I manage to get each button only triggers itself and doesn't affect the other?
I think I have to use my n of my v-for but I actually don't know how to bind this to a v-if..
Thanks in advance!
<template>
<div>
<div v-for="n in inputs" :key="n.id">
<b-button v-if="hide" #click="open()">Open me!</b-button>
<b-button v-if="!hide" #click="close()">Close me! </b-button>
</div>
<div>
<b-button #click="addInput">Add Input</b-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
id: null,
inputs: [{
id: 0
}],
hide: true,
};
},
methods: {
open() {
this.hide = false
},
close() {
this.hide = true
},
addInput() {
this.inputs.push({
id: this.id += 1;
})
}
}
};
</script>
Everything seems to look fine. In order to handle each button triggers,
you can maintain an object like so:
<script>
export default {
data() {
return {
inputs: [{id: 0, visible: false}],
};
},
methods: {
open(index) {
this.inputs[index].visible = false
},
close(index) {
this.inputs[index].visible = true
},
addInput() {
this.inputs.push({id: this.inputs.length, visible: false});
}
}
};
</script>
and your template should be like
<template>
<div>
<div v-for="(val, index) in inputs" :key="val.id">
<b-button v-if="val.visible" #click="open(index)">Open me!</b-button>
<b-button v-if="!val.visible" #click="close(index)">Close me! </b-button>
</div>
</div>
</template>
Edit:
You don't need to insert an id every time you create a row, instead can use the key as id. Note that the inputs is an object and not array so that even if you want to delete a row, you can just pass the index and get it removed.
I would create an array of objects. Use a boolean as property to show or hide the clicked item.
var app = new Vue({
el: '#app',
data: {
buttons: []
},
created () {
this.createButtons()
this.addPropertyToButtons()
},
methods: {
createButtons() {
// Let's just create buttons with an id
for (var i = 0; i < 10; i++) {
this.buttons.push({id: i})
}
},
addPropertyToButtons() {
// This method add a new property to buttons AFTER its generated
this.buttons.forEach(button => button.show = true)
},
toggleButton(button) {
if (button.show) {
button.show = false
} else {
button.show = true
}
// We are changing the object after it's been loaded, so we need to update ourselves
app.$forceUpdate();
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template>
<div>
<div v-for="button in buttons" :key="button.id">
<button v-if="button.show" #click="toggleButton(button)">Open me!</button>
<button v-if="!button.show" #click="toggleButton(button)">Close me! </button>
</div>
</div>
</template>
</div>

How to make it so that "Show more" & "Show less" buttons only work for the text in their own div and not for all texts using Vue.js [duplicate]

I'm making a list of items with v-for loop. Inside each item of the loop there is button with click event method that showing description text.
When i click on the button, it should toggle only inside it's own item, but it affecting all elements in v-for list.
So, how to make a toggle method that will affect only it's own item?
<template>
<div>
<div v-for="item in items" :class="{ activeclass: isActive }">
<div class="item-text">
{{item.text}}
</div>
<button #click="toggle()">show</button>
<div v-show="isActive" class="item-desc">
{{item.desc}}
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
items: [
{
text: 'Foo',
desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
},
{
text: 'Bar',
desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
}
],
isActive: false
}
},
methods: {
toggle: function () {
this.isActive = !this.isActive;
}
},
}
</script>
As #Nora said you can (and probably should) create a separate component for each list item, so you would have a component that accepts an item as a prop, then each component can have it's own isActive flag, which keeps the markup nice and clean:
Component:
Vue.component('toggle-list-item', {
template: '#list-item',
props: ['item'],
methods: {
toggle() {
this.isActive = !this.isActive;
}
},
data() {
return {
isActive: false
}
},
})
Markup
Now you can simply place the component inside your v-for:
<div id="app">
<div v-for="item in items">
<toggle-list-item :item="item"></toggle-list-item>
</div>
</div>
Here's the JSFiddle: https://jsfiddle.net/w10qx0dv/
You can add a property on each item in your list if description should be shown:
<template>
<ul>
<li v-for="item in items" :class="{ activeclass: item.isActive }">
<div class="item-text">
{{ item.text }}
</div>
<button #click="toggle(item)">show</button>
<div v-show="item.isActive" class="item-desc">
{{ item.desc }}
</div>
</li>
</ul>
</template>
<script>
export default {
data () {
return {
items: [
{
isActive: false,
text: 'Foo',
desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
},
{
isActive: false,
text: 'Bar',
desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
}
],
}
},
methods: {
toggle: function (item) {
item.isActive = !item.isActive;
}
},
}
</script>
Alternatively, you can extract the li into a separate component.
I've ran into the same problem, I solved it this way.
I took an array and pushed the clicked item's index and based on index available in the array, we can now show or hide the element.
<template>
<div>
<div v-for="(item,i) in items">
<div class="item-text">
{{ item.text }}
</div>
<button #click="toggle(i)">show</button>
<div v-show="clickedItems.includes(i)" class="item-desc">
{{ item.desc }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{
text: 'Foo',
desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
},
{
text: 'Bar',
desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
}
],
clickedItems:[]
}
},
methods: {
toggle() {
if (this.clickedItems.includes(i)) {
this.clickedItems.splice(this.clickedItems.indexOf(i), 1);
} else {
this.clickedItems.push(i);
}
}
},
}
</script>

vuejs mouseover add class to this element

How can I add class on mouse over on list item & remove class on mouse leave
<li class="test" #mouseenter="thumbStyle" #mouseleave="thumbStyle2">1</li>
<li class="test" #mouseenter="thumbStyle" #mouseleave="thumbStyle2">2</li>
<li class="test" #mouseenter="thumbStyle" #mouseleave="thumbStyle2">3</li>
In data & methods
data(){
isActive:false
}
thumbStyle:function(){
this.isActive = true;
},
thumbStyle2:function(){
this.isActive = false;
},
I have tried this but it is only adding class to first element (li) when I over on any list(li). So what is the technique to add only this(hovered) li. Like in jquery there are $(this)
The ideal way to handle this is that each of the elements you want to control the state of, are a model, then you can easily manipulate the state of each item.
Here is an example:
new Vue({
el: '#app',
data: function() {
return {
items: [{
label: 'Planes',
active: false
}, {
label: 'Trains',
active: false
}, {
label: 'Automobiles',
active: false
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.15/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in items"
#mouseenter="item.active = true"
#mouseleave="item.active = false"
>{{ item.label }} is {{ item.active }}</li>
</ul>
</div>
I have solved as belows
thumbStyle:function(e){
var clickedElement = e.target;
$(clickedElement).addClass('active');
},
thumbStyle2:function(e){
var clickedElement = e.target;
$(clickedElement).removeClass('active');
},

how to add or remove class in vuejs 2 based on id

I want to add or remove class to an element based on id using vuejs, but this code applies the behaviour to all elements. How can I add/remove a class to the element by id? Thanks all in advance.
new Vue({
el:"#test",
data: {
msg: 'msg goes here',
isActive: false
},
methods: {
log: function(e) {
this.isActive = ! this.isActive
//alert(e.currentTarget.id);
}
}
});
.active {
background: red
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id="test">
<div id="1" v-on:click="log($event)" v-bind:class="{ active: isActive }">
{{ msg }}
</div>
<div id="2" v-on:click="log($event)" v-bind:class="{ active: isActive }">
{{ msg }}
</div>
</div>
Here is an example of using components to achieve the behavior you are looking for:
// register
const clickable = Vue.component('clickable', {
props: ['msg'],
data: function() {
return {
isActive: false
}
},
template: '<div :class="{ active: isActive }" #click="isActive = !isActive">{{ msg }}</div>'
})
new Vue({
el: "#test",
components: {
clickable
},
data: function() {
return {
msg: 'msg goes here',
isActive: false
}
}
});
.active {
background: red
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id="test">
<clickable :msg='msg'></clickable>
<clickable :msg='msg'></clickable>
</div>
You have not internalized basic vuejs concepts.
https://v2.vuejs.org/v2/guide/components.html
Both of your elements should be separate components.

Categories