I’m trying to create an accordion using vuejs.
I found some examples online, but what I want is different. For SEO purpose I use “is” and “inline-template”, so the accordion is kind of static not fully created in Vuejs.
I have 2 problems/questions:
1) I need to add a class “is-active” on the component based on user interaction(clicks), because of this I receive the following error.
Property or method “contentVisible” is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option.
This probable because I need to set it at instance level. But “contentVisible” have a value (true or false) different for each component.
So I thought using at instance level an array of “contentVisible” and a props (pass thru instance) and custom events on child to update the instance values.
2) Could work but it is a static array. How can I make a dynamic array (not knowing the number of item components) ?
<div class="accordion">
<div>
<div class="accordion-item" is="item" inline-template :class="{ 'is-active': contentVisible}" >
<div>
<a @click="toggle" class="accordion-title"> Title A1</a>
<div v-show="contentVisible" class="accordion-content">albatros</div>
</div>
</div>
<div class="accordion-item" is="item" inline-template :class="{ 'is-active': contentVisible}" >
<div>
<a @click="toggle" class="accordion-title"> Title A2</a>
<div v-show="contentVisible" class="accordion-content">lorem ipsum</div>
</div>
</div>
</div>
var item = {
data: function() {
return {
contentVisible: true
}
},
methods: {
toggle: function(){
this.contentVisible = !this.contentVisible
}
}
}
new Vue({
el:'.accordion',
components: {
'item': item
}
})
Update
I create the following code but the custom event to send the modification from component to instance is not working, tabsactive is not changing
var item = {
props: ['active'],
data: function() {
return {
contentVisible: false
}
},
methods: {
toggle: function(index){
this.contentVisible = !this.contentVisible;
this.active[index] = this.contentVisible;
**this.$emit('tabisactive', this.active);**
console.log(this.active);
}
}
}
new Vue({
el:'.accordion',
data: {
tabsactive: [false, false]
},
components: {
'item': item
}
})
<div class="accordion" **@tabisactive="tabsactive = $event"**>
<div class="accordion-item" is="item" inline-template :active="tabsactive" :class="{'is-active': tabsactive[0]}">
<div>
<a @click="toggle(0)" class="accordion-title"> Title A1</a>
<div v-show="contentVisible" class="accordion-content">albatros</div>
</div>
</div>
<div class="accordion-item" is="item" inline-template :active="tabsactive" :class="{'is-active': tabsactive[1]}">
<div>
<a @click="toggle(1)" class="accordion-title" > Title A2</a>
<div v-show="contentVisible" class="accordion-content">lorem ipsum</div>
</div>
</div>
</div>
3
Answers
On point 1:
You have to define
contentVisible
as a vue instance variable, as you have accessed it with vue directive v-show, it searches this in vue data, watchers, methods, etc, and if it does not find any reference, it throws this error.As your
accordion
element is associated with the parent component, you may have to addcontentVisible
data there, like following:If you have multiple items, you may use some other technique to show one of them, like have a data variable
visibleItemIndex
which can change from 1 to n-1, where n is number of items.In that case, you will have
v-show="visibleItemIndex == currentIndex"
in the HTML.You can as well have hash for saving which index are to de displayed and which to be collapsed.
On point 2:
You can use v-for if you have dynamic arrays. you can see the documentation here.
I’m having a real hard time understanding what exactly it is you want or why you would want it, but I think this does it?
This works for me: