Arjan Treur
Arjan Treur

Reputation: 86

VueJs async template/component with placeholder

I am pretty new to VueJs, so I am still figuring things out. Since our templates are stored in the database, I want my templates to load async. For my components I now use the component-factory approach.

var c = Vue.component('my-async-component', function(resolve, reject){ 
  setTimeout(function(){
    resolve({
      template: '<div class="loader">loaded asynchronous: {{ pageName }}</div>',
      data() {
        return {
          pageName: 'my Page'
        }
      }
    })
  },2000)
})

But is it possible to have some kind of placeholder while loading it? I know I can do something with But in that case I need to have a parent component and I would like this to be independent.

On a Vue-instance you can do stuff in the render function end hook it up to mounted like:

var app = new Vue({
  el: '#app',
  data: {
    finish: false,
    template: null
  },
  render: function(createElement) {
    if (!this.template) {
      return createElement('div', 'loading...');
    } else {
      return this.template();
    }
  },
  mounted() {
    var self = this;
    $.post('myUrl', {foo:'bar'}, function(response){
      var tpl = response.data.template;
      self.template = Vue.compile(tpl).render;
    })
  }
})

Is this possible in a component? And is this still working when I have some nested divs (see an other question of mine: here)

Upvotes: 2

Views: 2399

Answers (1)

Arjan Treur
Arjan Treur

Reputation: 86

Ok, I figured it out. I just needed to reed de VUE guide a little bit bettter. I just followed the advanced async example from the docs and now I have a working example.

So I have my template like this:

    <div id="app">
      <my-async-component></my-async-component>
    </div>

Then in my JS I declared the template like:

    var c = Vue.component('my-async-component', function(){
      return {
        component: new Promise(function(resolve, reject){
          // setTimeout to simulate an asynchronous call
          setTimeout(function(){ 
            resolve({
              template: '<div class="loader">loaded asynchronous</div>'
            })
          },3000)
        }),
        loading: Vue.component('loader', {
          template: '<p>loading...</p>'
        }),
        error: Vue.component('load-error', {
          template: '<p>error loading component</p>'
        }),
        delay: 200,
        timeout: 10000
      }
    })

    var vm = new Vue({
      el: '#app'
    });

The loading and error components could also be globally registered components, so it's easy to reuse.

Hopefully I could help someone with this answer to my own question.

Upvotes: 2

Related Questions