Knockoutjs SPA boiler plate

Knockoutjs SPA boiler plate

by Himanshu Joshi

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/sammy.js/0.7.4/sammy.min.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css">
<div>
     <h2 data-bind="text: header"></h2>

    <hr/>
    <ul class="nav nav-pills" data-bind="foreach:sections">
        <li data-bind="css: {active: $root.selectedSection() == $data}"> <a data-bind="text:$data, attr:{href:'#' + $data}"></a>

        </li>
    </ul>
    <hr/>
    <div id="content">
        <div data-bind="visible: selectedSection() === 'profile', stopBinding: true">
            <div id="profile">
                <input data-bind="value: first" />
                <input data-bind="value: last" />
            </div>
        </div>
        <div data-bind="visible: selectedSection() === 'settings', stopBinding: true">
            <div id="settings">
                <input type="checkbox" data-bind="checked: isActive" />Is Active</div>
        </div>
        <div data-bind="visible: selectedSection() === 'notifications', stopBinding: true">
            <div id="notifications">Email:
                <input data-bind="value: emailAddress" />
            </div>
        </div>
    </div>
    <hr/>
    <div data-bind="text: footer"></div>
</div>

CSS

a {
    padding: 5px;
}
li {
    display: inline;
}
h2 {
    font-weight: bold;
    font-size: 1.4em;
}
#content {
    padding: 20px;
}

JavaScript

//let KO know that we will take care of managing the bindings of our children
ko.bindingHandlers.stopBinding = {
    init: function () {
        return {
            controlsDescendantBindings: true
        };
    }
};

//KO 2.1, now allows you to add containerless support for custom bindings
ko.virtualElements.allowedBindings.stopBinding = true;

var profileModel = {
    first: ko.observable("Bob"),
    last: ko.observable("Smith")
};

var shellModel = {
    header: ko.observable("Administration"),
    sections: ["profile", "settings", "notifications"],
    selectedSection: ko.observable("profile"),
    footer: ko.observable("copyright information"),

    settingsvmisbound: ko.observable(false),
    notificationvmIsbound: ko.observable(false)
};

var settingsModel = {
    isActive: ko.observable(true)
};

var notificationsModel = {
    emailAddress: ko.observable("[email protected]")
};

ko.applyBindings(shellModel);
ko.applyBindings(profileModel, document.getElementById("profile"));

Sammy(function () {

    this.get('#:section', function () {

        shellModel.selectedSection(this.params.section);
        if (this.params.section === 'profile') {

        } else if (this.params.section === 'settings') {

            if (!shellModel.settingsvmisbound()) {
                ko.applyBindings(settingsModel, document.getElementById("settings"));
                //set the value to true to prevent applybinding the next time when the page is visited
                shellModel.settingsvmisbound(true);
            } else {
                //if you want to update your viemodel with data from            server then the code goes here
            }
        } else if (this.params.section === 'notifications') {

            if (!shellModel.notificationvmIsbound()) {
                ko.applyBindings(notificationsModel, document.getElementById("notifications"));
                shellModel.notificationvmIsbound(true);
            } else {
                alert('already bound');
    ...