Search code examples
javascriptjqueryknockout.jsknockout-components

Knockout 3.2 - 'if' based transition between AMD loaded components


I have an SPA that uses knockout components dynamically loaded with require.

Here is what it currently looks like

        <!-- ko if: state() === 'one' -->
        <component-one></component-one>
        <!-- /ko -->

        <!-- ko if: state() === 'two' -->
        <component-two></component-two>
        <!-- /ko -->

        <!-- ko if: state() === 'three' -->
        <component-three params="myParam: MyParam()"></component-three>
        <!-- /ko -->

        <!-- ko if: state() === 'four' -->
        <component-four></component-four>
        <!-- /ko -->

What I'm looking for is something that produces the same result as the if binding for virtual elements but also allows me to place a transition (fade in/ out) when the state changes.

I have found something like this http://jsfiddle.net/rniemeyer/kNtdu/ which appears to work for knockout 2.1 but not 3.2.

Please note I'm not looking for just a fadeVisible, but more along the lines of a fadeIf.

Thanks for any help.


Solution

  • Here's a binding that I just put together.

    ko.bindingHandlers.ifFading = {
        init: function(element, valueAccessor, ignored1, ignored2, bindingContext) {
            var template = $(ko.virtualElements.childNodes(element)).filter("*").clone(),
                lastValue = false;
            ko.virtualElements.emptyNode(element);
    
            ko.computed(function () {
                var dataValue = !!ko.unwrap(valueAccessor());
                if (dataValue !== lastValue) {
                    lastValue = dataValue;
                    if (dataValue) {
                        var templateClone = template.clone();
                        ko.virtualElements.setDomNodeChildren(element, templateClone);
                        templateClone.hide();
                        ko.applyBindingsToDescendants(bindingContext, element);
                        templateClone.fadeIn();
                    } else {
                        $(ko.virtualElements.childNodes(element)).fadeOut(function () {
                            ko.virtualElements.emptyNode(element);
                        });
                    }
                }
            }, null, { disposeWhenNodeIsRemoved: element });
    
            return { controlsDescendantBindings: true };
        }
    };
    ko.virtualElements.allowedBindings.ifFading = true;
    

    In action: http://jsfiddle.net/mbest/6tpn5uhy/

    Here's a simpler version that doesn't use fadeOut: http://jsfiddle.net/mbest/6tpn5uhy/1/