Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

suppressing the v-html wrapping tag

Tags:

vue.js

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?

like image 981
Craig Ward Avatar asked Aug 17 '17 09:08

Craig Ward


People also ask

What is V in HTML?

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.


1 Answers

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);
      }
    }
  }
like image 130
Roy J Avatar answered Oct 20 '22 07:10

Roy J