admin管理员组文章数量:1344177
After some research the following suggestion by Mr. Evan You was found:
So without any hesitation I gave it a try:
Component template
<template>
<div v-on='{ click: dataType === `section` ? toggleSectionElements : null }'>
... magic
</div>
<template>
JS Logic
<script>
export default {
name: `product-section`,
props: [`section`, `sectionName`, `depth`],
methods: {
toggleSectionElements() {
... magic
}
},
puted: {
dataType() {
if (this.$props.section.sections || this.$props.depth === 0) {
return `section`
} else {
return `element`
}
}
}
}
</script>
But for described case it results in error during rendering:
[Vue warn]: Invalid handler for event "click": got null
Can someone please suggest what has been done wrong? :thinking:
Update
The way Data Model
looks like:
DataModel: {
mainSectionA: {
sections: {
sectionA: {
sections: {
elementA: { values: { ... } },
elementB: { values: { ... } }
}
values: { ... }
}
sectionB: {
elementA: { values: { ... } },
elementB: { values: { ... } }
}
},
values: { ... }
},
mainSectionB: {
sections: {
elementA: { values: { ... } },
elementB: { values: { ... } },
elementC: { values: { ... } },
... elements
},
values: { ... }
}
}
After some research the following suggestion by Mr. Evan You was found: https://github./vuejs/vue/issues/7349#issuement-354937350
So without any hesitation I gave it a try:
Component template
<template>
<div v-on='{ click: dataType === `section` ? toggleSectionElements : null }'>
... magic
</div>
<template>
JS Logic
<script>
export default {
name: `product-section`,
props: [`section`, `sectionName`, `depth`],
methods: {
toggleSectionElements() {
... magic
}
},
puted: {
dataType() {
if (this.$props.section.sections || this.$props.depth === 0) {
return `section`
} else {
return `element`
}
}
}
}
</script>
But for described case it results in error during rendering:
[Vue warn]: Invalid handler for event "click": got null
Can someone please suggest what has been done wrong? :thinking:
Update
The way Data Model
looks like:
DataModel: {
mainSectionA: {
sections: {
sectionA: {
sections: {
elementA: { values: { ... } },
elementB: { values: { ... } }
}
values: { ... }
}
sectionB: {
elementA: { values: { ... } },
elementB: { values: { ... } }
}
},
values: { ... }
},
mainSectionB: {
sections: {
elementA: { values: { ... } },
elementB: { values: { ... } },
elementC: { values: { ... } },
... elements
},
values: { ... }
}
}
Share
edited Feb 23, 2019 at 13:23
volna
asked Feb 23, 2019 at 8:21
volnavolna
2,6104 gold badges31 silver badges68 bronze badges
4 Answers
Reset to default 4Just change it to the below and it will work
v-on="condition ? { mouseover: handler } : {}"
or, if your handler is called mouseover
v-on="condition ? { mouseover } : {}"
Instead of polluting your template with ternary logic, you should actually perform the check inside the click handler instead. It not only makes your template more readable, but also makes maintaining the code easier since all logic has been abstracted and delegated to the event handler's callback instead.
Quick solution
Therefore the quick solution is to actually ensure that the toggleSectionElements()
will only work when a correct dataType
is present. This can be achieved by using a guard clause:
toggleSectionElements() {
// Guard clause to prevent further code execution
if (this.dataType() !== 'section')
return;
// Magic here
}
Even better, is that if separate handlers should be assigned to each dataType
: you can then create a factory function for that purpose:
methods: {
// This is just a factory function
toggleElements() {
switch (this.dataType()) {
case 'section':
return this.toggleSectionElements;
case 'element':
// Something else...
}
},
toggleSectionElements() {
// Magic for section element
}
}
Suggestion: using atomic ponents
Since it might be costly to bind click event handlers to elements that end up doing nothing, you can also break down your ponent to be more atomic. The collection element will be responsible of receiving an array of "section" or "element", and each "section"/"element" will have its own ponent, something like this:
- You have a collection ponent, say
<my-collection>
, that holds all "section" and "element" ponents - "section" ponent will use the
<my-section>
ponent - "element" ponent will use the
<my-element>
ponent
This is when VueJS bees really powerful: you can use dynamic ponent inside <my-collection>
to determine which ponent to use depending on the dataType
encountered.
This is done by running a v-for
through the collection, and then using v-bind:is="..."
to determine whether a specific collection item should be using "section" or "element". I understand that this is probably going to go out of scope of your original question, but it's a worthwhile design to consider:
const collectionComponent = Vue.ponent('my-collection', {
template: '#my-collection-ponent',
data: function() {
return {
collection: [{
dataType: 'section',
description: 'Hello I am section 1'
}, {
dataType: 'element',
description: 'Hello I am element 1'
}, {
dataType: 'section',
description: 'Hello I am section 2'
}, {
dataType: 'element',
description: 'Hello I am element 2'
}]
}
},
methods: {
ponentToUse(dataType) {
return 'my-' + dataType;
}
}
});
const sectionComponent = Vue.ponent('my-section', {
template: '#my-section-ponent',
props: ['itemData'],
methods: {
toggle() {
console.log('Doing some magic.');
}
}
});
const elementComponent = Vue.ponent('my-element', {
template: '#my-element-ponent',
props: ['itemData']
});
new Vue({
el: '#app'
});
.box {
border: 1px solid #999;
cursor: pointer;
margin: 10px;
padding: 10px;
}
.box:hover {
background-color: #eee;
}
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-collection />
</div>
<script type="text/x-template" id="my-collection-ponent">
<div>
<ponent
v-for="(item, i) in collection"
v-bind:key="i"
v-bind:is="ponentToUse(item.dataType)"
v-bind:itemData="item" />
</div>
</script>
<script type="text/x-template" id="my-section-ponent">
<div @click="toggle" class="box">
<h1>{{ itemData.dataType }}</h1>
<p>{{ itemData.description }}</p>
<p>Clicking on me will invoke a section-specific logic</p>
</div>
</script>
<script type="text/x-template" id="my-element-ponent">
<div class="box">
<h1>{{ itemData.dataType }}</h1>
<p>{{ itemData.description }}</p>
<p>Clicking on me will do nothing</p>
</div>
</script>
here:
click: dataType === `section` ? toggleSectionElements : null
in the not-equal case you pass null, but the value on click expects a function. you can try an emptry function:
click: dataType === `section` ? toggleSectionElements : ()=>{}
In Vue 3 you can pass null
to the listener. Combining it with optional chaining you can do this:
@click="handler?.() || null"
Same for old browsers:
@click="handler ? handler() : null"
本文标签: javascriptvon clickadd handler only if condition has been metStack Overflow
版权声明:本文标题:javascript - v-on click, add handler only if condition has been met - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743690319a2522601.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论