3
votes

is there any way how can I set/override slot's content from inside the component? Like

Template:

<div>
    <slot></slot>
</div>

JS:

export default {
    ...
     mounted() {
        this.$slot.render("<button>OK</button>");
     }
    ...
}

I know I can use v-html on my element to dynamically push content into component template, but I mean not just pure HTML I mean HTML with Vue directives. Like:

JS:

export default {
    ...
     mounted() {
        this.$slot.default.render('<button @click="submit">OK</button>');
     },
    methods: {
        submit() {
            // Here I want to get :)
        }
    }
    ...
}

Basically I want Vue to render (like parse and render, not like innerHTML) certain string in scope of my component and put in on certain spot in my component. The reason is I get the new content from server via AJAX.

I'm sorry but I can't still get my head around after 2 days of googling.

Thanks a lot!

2
Probably not. Your best chance is to build the component template string before creating the actual object (but it will not support any change). That's a pretty bad solution, so you most likely should consider refactoring your app.FitzFish
feels a bit like working against the frameworkNicolas Heimann

2 Answers

3
votes

According to this you can instantiate a component programmatically and insert slot content as well.

import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
    propsData: { type: 'primary' }
})
instance.$slots.default = [ 'Click me!' ]
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
0
votes

I think this is your best chance: building your component on the fly. Here in the example I use a simple placeholder (with v-cloak).

You may obtain a better result using vue-router to add your newly created component during the execution, with router.addRoutes so your app doesn't have to wait to instantiate the whole vue.

function componentFactory(slot) {
  return new Promise((resolve, reject) => {
    window.setTimeout(() => { // Asynchronous fetching
      resolve({ // Return the actual component
        template: `<div>
            ${slot}
          </div>`,
        methods: {
          submit() {
            console.log('hello');
          }
        }
      });
    }, 1000);
  });
}

componentFactory('<button @click="submit">OK</button>') // Build the component
  .then(component => {
    new Vue({ // Instantiate vue
      el: '#app',
      components: {
        builtComponent: component
      }
    });
  });
[v-cloak], .placeholder {
	display: none;
}

[v-cloak] + .placeholder {
	display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>

<div id='app' v-cloak>
  <built-component></built-component>
</div>
<div class="placeholder">
  This is a placeholder, my vue app is loading...
</div>