0
votes

I have this HTML pattern:

<div id="New"> == ajax loaded content == </div>

It was easy to render HTML at server side and use innerHTML to inject the content into the right place.
Now I am trying to use Vue.js to do the same thing but render HTML at the client side. I can make this pattern into a component, let's say componentA, with template:

componentA  

template:
`<div><slot></slot></div>`

It works if the HTML page content is something like:

<componentA>
  <componentB></componentB> and some other none component content
</componentA>

The componentB is rendered and replaced the slot in componentA.

The problem is how do I use AJAX call (the call is made outside of componentA) to load

  <componentB></componentB> and some other none component content

into the slot of componentA, and still make componentB to render correctly? In real situation, the content from AJAX call can be

<componentB>, <componentC>, <componentD> ...

The following will treat componentB as regular string

in HTML:
<componentA>
  <div id="New"></div>
</componentA>

in JS:
document.getElementById('New').innerHTML =
 '<componentB></componentB> And some other none component content';

Is there a proper way to render string from AJAX return with Vue syntax as Vue?

1

1 Answers

0
votes

One solution is put the ajax response like <component></component> to Component.template inside render function (Vue Guide: Render Function).

Like below demo:

const Foo = Vue.component('foo', {template: '<p>Foo - {{flag}}</p>', props: ['flag']})
const Bar = Vue.component('bar', {template: '<p>Bar - {{flag}}</p>', props: ['flag']})
const Generic = Vue.component('generic', { 
  render: function (createElement) {
    return createElement('div', [
      createElement('h3', 'Title'),
      createElement('button', {on: {click: this.loadComponent}}, 'Load Component'),
      this.dynamicComponent
      && createElement(Vue.component('v-fake-slot', {template:this.dynamicComponent, props: ['flag']}), {
        props: {
          flag: this.parent
        }
      }) 
    ])
  },
  props: ['parent'],
  data () {
    return {
      components: ['<foo :flag="flag"></foo>', '<bar :flag="flag"></bar>'],
      index: 0,
      dynamicComponent: ''
    }
  },
  methods: {
    loadComponent: function () {
      setTimeout(() => {
        this.index += 1
        this.dynamicComponent = this.components[this.index % 2]
      }, 1000)
    }
  }
})



new Vue({
  el: '#app',
  data () {
    return {
      test: 'root'
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <generic :parent="test"></generic>
</div>