Consider the following code. I want to toggle an excerpt and description. The code directly below does that, but it means having the <a>
outside of the article, and I would prefer it inside.
<article v-if="!toggle" v-html="item.excerpt"></article>
<a href="#" v-if="!toggle" @click.prevent="toggle = 1">Read more...</a>
<article v-if="toggle" v-html="item.description"></article>
<a href="#" v-if="toggle" @click.prevent="toggle = 0">Show less...</a>
It could be rewritten as
<article v-if="!toggle">
<span v-html="item.excerpt"></span>
<a href="#" @click.prevent="toggle = 1">Read more...</a>
</article>
<article v-if="toggle">
<span v-html="item.description"></span>
<a href="#" @click.prevent="toggle = 0">Show less...</a>
</article>
But that would mean the excerpt/description is wrapped with a <span>
. Is there a way to use the v-html
directive and not output the wrapping tag?
The v-html directive is used to update a element's innerHTML with our data. This is what separates it from v-text which means while v-text accepts string and treats it as a string it will accept string and render it into HTML.
What I would like to do is (does not work)
<article v-if="toggle">
<template v-html="item.description"></template>
<a href="#" @click.prevent="toggle = 0">Show less...</a>
</article>
but it turns out that using a template
this way only works with control-flow directives (v-for
and v-if
). So I wondered if I could sneak around it by adding a control-flow directive to the template
tag (also does not work)
<article v-if="toggle">
<template v-if="toggle" v-html="item.description"></template>
<a href="#" @click.prevent="toggle = 0">Show less...</a>
</article>
or by putting the v-html
on the article
tag (of course not)
<article v-if="toggle" v-html="item.description">
<a href="#" @click.prevent="toggle = 0">Show less...</a>
</article>
That left me with two options I knew would work:
(1) Use a tag. A slight improvement over using a span
is using a custom tag, which the browser is guaranteed not to default-style in any way. The tag is included in the HTML, but does not affect the display compared to having bare HTML.
<article v-if="toggle">
<non-styled v-html="item.description"></non-styled>
<a href="#" @click.prevent="toggle = 0">Show less...</a>
</article>
(2) Use a custom directive. Although v-html
replaces the entire innerHTML of its element, you can certainly write a directive to insert its value at the beginning (or end) of its element and not remove everything else.
<article v-if="toggle" v-start-with-html="item.description">
<a href="#" @click.prevent="toggle = 0">Show less...</a>
</article>
It's a very straightforward command, although I'm sure my implementation is under-thought-out in terms of dealing with node updates.
directives: {
startWithHtml: {
inserted(el, binding) {
el.insertAdjacentHTML('afterbegin', binding.value);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With