ForceModelCorrection

force model correction example

by Jaak Kütt

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.3.0.debug.js"></script>
<script type="text/html" id="default">
    <div class="item" data-bind="'if':id">
        <div data-bind="html:content1"></div>
        <div id="epos1" data-bind="contentAvailable: ['children','pos1']">
            <div class="root" data-bind="template: { name: 'default', foreach: children().pos1 }">
        </div>
        <div>
            <div id="epos2" data-bind="contentAvailable: ['children','pos2']">
                <div class="root" data-bind="template: { name: 'default', foreach: children().pos2 }">
            </div>
            <div id="epos3" data-bind="contentAvailable: ['children','pos3']">
                <span data-bind="html:children().pos3().length"></span>
                <div data-bind="foreach: children().pos3()">
                    <span data-bind="html:id"></span>
                </div>
            </div>
        </div>
    </div>
</script>    

<div class="root" data-bind="template: { name: 'default', foreach: items }">
    
</div>

CSS

.item{border:1px solid black;padding:10px;margin:10px;}

JavaScript

ko.bindingHandlers.contentAvailable = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {        
        ko.utils.domData.set(element, '__ko_withIfBindingData', {});   
        return { controlsDescendantBindings: true };
    },      
    'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        
        console.log('fired update',element,valueAccessor());    
        
        var dataValue = ko.utils.unwrapObservable(valueAccessor());
        
        if(!bindingContext.$data.hasOwnProperty(dataValue[0]) || typeof(bindingContext.$data[dataValue[0]]) != "function"){
            bindingContext.$data[dataValue[0]]=ko.observable({});
        }
        if(!bindingContext.$data[dataValue[0]]().hasOwnProperty(dataValue[1]) || typeof(bindingContext.$data[dataValue[0]]()[dataValue(1)]) != "function"){
            bindingContext.$data[dataValue[0]]()[dataValue[1]]=ko.observableArray([]);
            shouldDisplay=true;    
        }else{
            shouldDisplay=true;
        }
        
        var withIfData = ko.utils.domData.get(element, '__ko_withIfBindingData'),
        isFirstRender = !withIfData.savedNodes,
        needsRefresh = isFirstRender || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
        if (needsRefresh) {
            if (isFirstRender) {
                withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element),true);
            }                
            if (shouldDisplay) {
                if (!isFirstRender) {
                    ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
                }
                ko.applyBindingsToDescendants(bindingContext, element);
            } else {
                ko.virtualElements.emptyNode(element);
            }
            withIfData.didDisplayOnLastUpdate = shouldDisplay;
        }
    }    
};

function viewChild(id){
   ...