Vue: What if I just... replace a component definition?
by Admiral Potato
HTML
<link rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css">
<script src="//unpkg.com/babel-polyfill@latest/dist/polyfill.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script>
<div id="app">
<custom-content
:content="content_a"
:env="env"
></custom-content>
<custom-content
:content="content_b"
:env="env"
></custom-content>
<form class="mono" @submit.prevent>
<p>env.contact</p>
<label for="first_name">
First Name
<input id="first_name" v-model="env.contact.first_name" />
</label>
<label for="last_name">
Last Name
<input id="last_name" v-model="env.contact.last_name" />
</label>
</form>
<form class="mono" @submit.prevent>
<p>content_a</p>
<textarea v-model="content_a.html"></textarea>
<textarea v-model="content_a.js"></textarea>
</form>
<form class="mono" @submit.prevent>
<p>content_b</p>
<textarea v-model="content_b.html"></textarea>
<textarea v-model="content_b.js"></textarea>
</form>
</div>
SCSS
.mono {
* {
font-family: monospace;
}
textarea {
display: block;
height: 120px;
width: 100%;
}
}
JavaScript
Vue.component('custom-content', {
template: `
<component
:key="content.html + content.js"
:is="componentName"
:env="env"
></component>
`,
props: {
content: Object,
env: Object
},
beforeCreate () {
this.componentName = 'dynamic-child-' + btoa(Math.random().toString().slice(2)).replace(/([0-9]|=)/g, '')
Vue.component(this.componentName, {
template: `<div class="dynamic_child" id="${this.componentName}"><h1>You should never see this</h1></div>`,
})
console.log('customConent.beforeCreate', this.componentName)
},
created () {
console.log('customConent.created', this.componentName)
this.replaceComponent()
},
methods: {
replaceComponent () {
console.log('replaceComponent started', 'what', this.componentName)
const functionBodyString = `var view = {};${this.content.js};return view;`
const mixin = (new Function(functionBodyString)).apply(null)
Vue.component(this.componentName, {
name: this.componentName,
mixins: [mixin],
template: `<div class="dynamic_child" id="${this.componentName}">${this.content.html}</div>`,
data () {
return {
previousEnvKeys: []
}
},
props: {
env: Object
},
created () {
this.updateEnv()
},
methods: {
updateEnv () {
let newEnvKeys = []
this.previousEnvKeys.forEach((key) => {
this.$set(this, key, null)
})
const scope = Object.assign(
{
general: this.env.account.general
},
this.env
)
console.log('dynamicChild.updateEnv', {
scope,
previousEnvKeys: this.previousEnvKeys
})
Object.entries(scope).map(([key, value]) => {
newEnvKeys.push(key)
this[key] = value
this.$set(this,...