vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.83k stars 33.67k forks source link

Show view when its ready to be shown #367

Closed gapipro closed 9 years ago

gapipro commented 10 years ago

So lets assume we have 2 views. First is list of items and second is edit form for items. Every view has its own loading logic (Few rest calls). When all loading is done then view is shown. This works great on initial start but when page is loaded and you only switch from one view to another each time new view is shown before data is fully loaded, because changing current view triggers data loading and it switches html at the same time. This causes page content to blink a little because it is shown when data is not yet loaded.

How to solve this? Is it ok to have loading logic in views or should it be in parent controller that manages views?

gapipro commented 10 years ago

I solved this issue with changed view directive:

Vue.directive('xview',{
    bind: function () {

        // track position in DOM with a ref node
        var el       = this.raw = this.el,
            parent   = el.parentNode,
            ref      = this.ref = document.createComment('v-view')
        parent.insertBefore(ref, el)
        parent.removeChild(el)

        // cache original content
        /* jshint boss: true */
        var node,
            frag = this.inner = document.createElement('div')
        while (node = el.firstChild) {
            frag.appendChild(node)
        }

    },

    update: function(value) {

        var Ctor  = this.compiler.getOption('components', value);
        if (!Ctor) return;

        this.oldVM = this.childVM;

        this.childVM = new Ctor({
            el: this.raw.cloneNode(true),
            parent: this.vm,
            compilerOptions: {
                rawContent: this.inner.cloneNode(true)
            }
        });

        this.el = this.childVM.$el;

        this.childVM.$root.$on('ready',function(){
            if (this.compiler.init) {
                this.ref.parentNode.insertBefore(this.el, this.ref)
            } else {
                this.childVM.$before(this.ref)
            }
            this.unbind();
        }.bind(this));
    },

    unbind: function() {
        if (this.oldVM) {
            this.oldVM.$destroy()
        }
    }
});
yyx990803 commented 10 years ago

Good concern - I will consider adding this to the official v-view.

gapipro commented 9 years ago

How do we now solve this problem in latest Vue?

yyx990803 commented 9 years ago

The recommended way is still to use a custom directive for view management if you want the finest control.

gapipro commented 9 years ago

Ok, did just that and it worked fine. Btw: How can you get access to templateParser when writing custom directive?

yyx990803 commented 9 years ago

Hmm there's currently no way to do that, but I will open it up in next release ;)