Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
189
rated 0 times [  191] [ 2]  / answers: 1 / hits: 15653  / 6 Years ago, tue, may 8, 2018, 12:00:00

I have a Vue component simplified below.



Here is the template



<template>
<slot></slot>
</template>


The slot may contain HTML, which is why I decided to use a slot rather than a prop which I would simply bind to. I'd like to keep it that way.



I have a method that gets new HTML from the server. I'd like to use this new HTML to update the slot. I'm not sure if slots are reactive and how I can accomplish this.



I can view the default slot using this.$slots.default[0], but I don't know how to update it with a string of HTML content. Simply assigning the string to the element is obviously incorrect, to .innerHtml does not work because it isn't an available function, and to .text doesn't work. I assume that even though the text element exists on the slot object, the element properties take precedence.



Per suggestion in comments, I've tried this along with a computer property.



<span v-html=messageContent><slot></slot></span>


But now the problem is that it overwrites the slot passed to me.



How can I reactively update a slot with new HTML in Vue.JS?


More From » vue.js

 Answers
18

I think your issue comes from a misunderstanding of how <slot> inherently works in VueJS. Slots are used to interweave content from a consuming parent component into a child component. See it as a HTML equivalent of v-bind:prop. When you use v-bind:prop on a component, you are effectively passing data into a child component. This is the same as slots.



Without any concrete example or code from your end, this answer is at best just guess-work. I assume that your parent component is a VueJS app itself, and the child component is the one that holds the <slot> element.



<!-- Parent template -->
<div id=app>
<custom-component>
<!-- content here -->
</custom-component>
</div>

<!-- Custom component template -->
<template>
<slot></slot>
</template>


In this case, the app has a default ground state where it passes static HTML to the child component:



<!-- Parent template -->
<div id=app>
<custom-component>
<!-- Markup to be interweaved into custom component -->
<p>Lorem ipsum dolor sit amet.</p>
</custom-component>
</div>

<!-- Custom component template -->
<template>
<slot></slot>
</template>


Then, when an event is fired, you want to replace that ground-state markup with new incoming markup. This can be done by storing the incoming HTML in the data attribute, and simply using v-html to conditionally render it. Let's say we want to store the incoming markup in app's vm.$data.customHTML:



data: {
customHTML: null
}


Then your template will look like this:



<!-- Parent template -->
<div id=app>
<custom-component>
<div v-if=customHTML v-html=customHTML></div>
<div v-else>
<p>Lorem ipsum dolor sit amet.</p>
</div>
</custom-component>
</div>

<!-- Custom component template -->
<template>
<slot></slot>
</template>


Note that in contrast to the code you have tried, the differences are that:




  • It is the parent component (i.e. the consuming component) that is responsible for dictating what kind of markup to pass to the child

  • The child component is as dumb as it gets: it simply receives markup and renders it in the <slot> element






See proof-of-concept below:





var customComponent = Vue.component('custom-component', {
template: '#custom-component-template'
});

new Vue({
el: '#app',
data: {
customHTML: null
},
components: {
customComponent: customComponent
},
methods: {
updateSlot: function() {
this.customHTML = '<p>Foo bar baz</p>';
}
}
});

.custom-component {
background-color: yellow;
border: 1px solid #000;
}

<script src=https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js></script>

<div id=app>
<h1>I am the app</h1>
<button type=button @click=updateSlot>Click me to update slot content</button>
<custom-component>
<div v-if=customHTML v-html=customHTML>
</div>
<div v-else>
<p>Lorem ipsum dolor sit amet.</p>
</div>
</custom-component>
</div>

<!-- custom-component template -->
<script type=text/template id=custom-component-template>
<div class=custom-component>
<h2>I am a custom component</h2>
<!-- slot receives markup set in <custom-component> -->
<slot></slot>
</div>
</script>




[#54484] Friday, May 4, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
nadiatristinl

Total Points: 151
Total Questions: 116
Total Answers: 108

Location: Japan
Member since Tue, Jul 26, 2022
2 Years ago
nadiatristinl questions
Tue, Mar 15, 22, 00:00, 2 Years ago
Wed, Dec 29, 21, 00:00, 2 Years ago
Thu, Dec 17, 20, 00:00, 4 Years ago
Sat, Jul 11, 20, 00:00, 4 Years ago
Wed, Apr 29, 20, 00:00, 4 Years ago
;