Reputation: 583
I am trying to create a component for a popover using Bootstrap4 in Vue:
<template>
<div>
<div :id="uid + '_Content'" class="d-none">
<slot name="content">
</slot>
</div>
<div :class="'call' + uid">
<slot name="caller">
</slot>
</div>
</div>
</template>
<script>
module.exports = {
data() {
return {
uid: this.genUID()
}
},
props: {
title: {
type: String,
required: false,
default: ''
}
},
mounted() {
_this = this;
// PopOver Definition
const popover = new bootstrap.Popover(document.querySelector('.call' + this.uid), {
container: 'body',
title: this.title,
html: true,
placement: 'auto',
sanitize: false,
customClass: 'noselect',
content: () => {
return document.querySelector("#" + _this.uid + "_Content").innerHTML;
}
});
},
methods: {
genUID() {
return "Popover_" + Math.random().toString(16).slice(2);
}
}
}
</script>
However, when passing content to <slot name="content">
from another component, the data is not reactive. Is there any config information that I am missing to make it reactive? Is this even possible with Vue and (regular) Bootstrap (not Bootstrap-Vue).
Upvotes: 0
Views: 884
Reputation: 2099
You're losing reactivity because your content
option to bootstrap.Popover
is returning a string of your element's HTML, not the element itself. The popover just copies the HTML as it exists when it is opened. If you pass the element, Bootstrap will reparent the element itself into the popover, so changes to the element's children should be reflected. (Note that this could still be disrupted by a virtual DOM change that rewrote the element itself, which is why Bootstrap-Vue would still be better here.) If the popover might be reused, you'll need to reparent the element back into your component's own tree each time the popover is closed. You'll also need to make provision for the _Content
element to only be hidden while it isn't reparented.
Here's how it all would look:
<template>
<div ref="container" class="Popover__Container">
<div ref="content" class="Popover__Content">
<slot name="content">
</slot>
</div>
<div ref="caller" class="Popover__Caller">
<slot name="caller">
</slot>
</div>
</div>
</template>
<script>
module.exports = {
props: {
title: {
type: String,
required: false,
default: ''
}
},
mounted() {
const content = this.$refs.content;
// PopOver Definition
const popover = new bootstrap.Popover(this.$refs.caller, {
container: 'body',
title: this.title,
html: true,
placement: 'auto',
sanitize: false,
customClass: 'noselect',
content: content
});
$(this.$refs.caller).on('hidden.bs.popover', () =>
{
this.$refs.container.prepend(content);
});
}
}
</script>
<style scoped>
.Popover__Container > .Popover__Content {
display: none;
}
</style>
(I've also replaced the UID approach with refs, since that is a more Vue-like approach.)
Upvotes: 1