I have a set of data that needs to be looped through but each item in that data has a different onClick event. Something along the lines like:
list: [
{
text: 'a',
icon: 'a-icon',
onClick: () => {
// do stuff a
},
},
{
text: '`b`',
icon: 'b-icon',
onClick: () => {
// do stuff b
},
},
]
what I initially tried to do was:
<div v-for="(item, i) in list" :key="i" @click="item.onClick()"></div>
which didn't work. The error was:
TypeError: item.onClick is not a function
Then I tried:
<div v-for="(item, i) in list" :key="i" @click="list[i].onClick()"></div>
which looks weird but works. Only I can't access this
inside onClick
function. I could just pass this
to the function directly like @click="list[i].onClick(this)"
but it look weird too.
I knonw I can write a method and do switch
according to the index. But then I had to write the onClick
function seperately.
Is there a better way to do this?
CodePudding user response:
const app = new Vue({
el: "#app",
data() {
return {
list: [{
text: 'a',
icon: 'a-icon',
onClick: (item) => {
let element = document.getElementById(item.text);
console.log(element);
console.log("Item" item);
console.log("Hi")
},
},
{
text: '`b`',
icon: 'b-icon',
onClick: (item) => {
console.log("Item" item);
console.log("Hello")
},
},
]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, i) in list" :key="i" :id="item.text" @click="item.onClick(item)">{{item.text}}</div>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
It's depends on what you mean by this
. Is this
the HTML element you are working with, or the array element being looped.
<div v-for="(item, i) in list" :key="i" @click="item.onClick(item)"></div> //If `this` refers to the array element being looped
If this
refers to the HTML element in that loop: You can assign an unique id
, probably :id="'item_list' id"
then pass it as method parameter live above. Then select the element within the method. There's defintely a better way but till now that's what I can think of
And in addition, since you are using arrow function, it may point to its nearest parent that have this
. Try using anonymous function if it suits your need.
CodePudding user response:
You have many ways to pass the refence of the function to click event but the simplest are just @click="item.onClick"
or @click="item.onClick(myArgs)"
About this
context, as you are using es6 arrow function as handler, this
will be the vue data context.
- if you declare you data as Object literal like
data: { list: [] }
,this
won't be the Vue instance. - if you declare it as a Function like
data() { return { list: [] } }
,this
will be the Vue instance. So go with this second option for your case.
DEMO: https://jsfiddle.net/The_Bear/cpx6kovf/9/
JS
data() {
return {
list: [
{
text: 'Item One',
onClick: () => {
console.log('click 1', this) // `this` will be VUE instance
}
},
{
text: 'Item Two',
onClick: () => {
console.log('click 2', this) // `this` will be VUE instance
}
}
]
}
}
TEMPLATE
<div v-for="(item, i) in list" :key="i" @click="item.onClick"></div>
INFO: VueJS: Defining 'data' using object literal vs function returning an object
DATA VUE DOCS: https://vuejs.org/v2/api/#data