Post
Render Vue Components inside Twitter Bootstrap Modal as Vue Component
When Vue
To solve this; [Vue.compile](https://vuejs.org/v2/api/#Vue-compile) to the rescue!
Modal
Example below is the Twitter Bootstrap static modal.
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Twitter Bootstrap 4: Modal
Before we make the VueModal.vue component, we make extra component HtmlCompiler.vue
Vue Component HtmlCompiler
Option 1: HtmlCompiler as global component
const div = document.createElement('div')
Vue.component('htmlCompiler', {
name: 'HtmlCompiler',
props: ['code'],
render(h) {
div.innerHTML = this.code
return h(Vue.compile(div.outerHTML))
}
})
Global Vue: main.js
This will definitely work, but I don’t think it’s a good idea because every function call will create a DIV-element in the Virtual Dom, just because you’re using these functions innerHTML and outerHTML.
Improved the code
Option 2: HtmlCompiler as a component to import later
<script>
const div = document.createElement('div')
export default {
name: 'HtmlCompiler',
props: ['code'],
render(h) {
div.innerHTML = this.code
return h(Vue.compile(div.outerHTML))
}
}
</script>
Vue Component: components/HtmlCompiler.vue
The Static Modal as Vue Component
Code below will show you HtmlCompiler as the imported version and not as a global Vue Component.
<template>
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" v-text="title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<html-compiler
class="modal-body"
:code="body"></html-compiler>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</template>
<script>
import HtmlCompiler from './components/HtmlCompiler.vue'
export default {
name: 'VueModal',
components: {
HtmlCompiler
}
props: ['title', 'body']
}
</script>
Vue Component: components/VueModal.vue
I recommend to use HtmlCompiler as global component, I mean all required components that might render in this Modal. This method is fine, if you care about Treeshaking
Refactored Version
Small library
import Vue from 'Vue'
const div = document.createElement('div')
const vueCompile = html => {
div.innerHTML = html
return Vue.compile(div.outerHTML)
}
export default vueCompile
Javascript library: lib/vueCompile.js
Vue Component VueModal
<template>
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" v-text="title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" v-html="compiledBody">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</template>
<script>
import vueCompile from './lib/vueCompile'
Vue.component('vueModal', {
name: 'VueModal',
props: ['title', 'body'],
computed: {
compiledBody () {
return vueCompile(this.body)
}
}
})
</script>
Version 2 Theoretical: components/VueModal.vue
(Work in Progress)