Knockout - Item Wrapper Example

Contains: * simplified navigation * synchronous data-loading and -rendering

by plus5keen

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<div class="liveExample">
    <div class="nav" data-bind="with: navModel">
        <p>Nav Id: <input data-bind="value: activeItemId, valueUpdate: 'afterkeydown'" /></p>
        <p>Edit Mode: <input type="checkbox" data-bind="" /></p>
    </div>
    <div class='browseView'>
        <button data-bind="click: createItem">Create Item</button>
        <h2 data-bind="text: sectionTitle"></h2>
        <div data-bind="if: activeItem">
            <!-- ko with: activeItem -->
                <p>Id: "<!-- ko text: id -->not yet bound<!-- /ko -->"</p>
                <div>
                    <div><label>First name</label></div>
                    <div><input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></div>
                </div>
                <div>
                    <label>First name again</label>
                    <div><input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></div>
                </div>
                <div>
                    <label>Last name</label>
                    <div><input data-bind="value: lastName, valueUpdate: 'afterkeydown'" /></div>
                </div>
                <h3>Hello, <!-- ko text: fullName -->not yet bound<!-- /ko -->!</h2>
                <button data-bind="click: rebase">Rebase</button>
            <!-- /ko -->
        </div>
    </div>
    <pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
</div>

CSS

body { font-family: arial; font-size: 14px; }
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }

JavaScript

(function () {
    var _ = { // fake _ for compatibility
        each: function (arr, fn) {
            for(var i = 0, il = arr.length; i < il; i++) {
                fn(arr[i]);
            }
        },
        mapObject: function (obj, fn) {
            var result = {};
            for(var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    result[key] = fn(obj[key]);
                }
            }
            return result;
        }
    };
    var unwrap = ko.utils.unwrapObservable;
    
    var createActionSet = function () {
        var actions = [];
    
        var actionSet = function () {
            _.each(actions, function (action) {
                action();
            });
        };
        actionSet.add = function (action) {
            actions.push(action);
        };
    
        return actionSet;
    };
    
    var createKOProp = function (target, key) {
        var inner = ko.observable();
        var result = ko.computed({
            read: function () {
                var lt = unwrap(target);
                var value = lt ? lt[key] : void 0;
                if (inner() !== value) {
                    inner(value);
                }
                return value;
            },
            write: function (value) {
                var lt = unwrap(target);
                inner(lt ? (lt[key] = value) : void 0);
            }
        });
        return result;
    };
    
    var createKOArrayProp = function (target, key) { // TODO
        var inner = ko.observableArray();
        var result = ko.computed({
            read: function () {
                var lt = unwrap(target);
                var value = lt ? lt[key] : void 0;
                if (inner() !== value) {
                    inner(value);
                }
                return value;
            },
            write: function (value) {
                var lt = unwrap(target);
                inner(lt ? (lt[key] = value) : void 0);
            }
 ...