Knockout Talk, Complete Demo

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.1.0/knockout-min.js"></script>
<script src="https://github.com/downloads/rniemeyer/knockout-sortable/knockout-sortable.js"></script>
<div id="wrap">
    <h2 data-bind="text: title"></h2>
    <div data-bind="with: selectedQuestion">
        <input data-bind="value: title" />
        <select data-bind="value: type">
            <option value="text">Single-Line Text</option>
            <option value="textarea">Multi-Line Text</option>           
            <option value="dropdown">Drop Down List</option>           
            <option value="checkboxes">Check Box List</option>           
            <option value="radios">Radio Button List</option>           
        </select>
        <!-- ko if: isMultipleChoice -->
        <ol data-bind="sortable: answers">
            <li><input data-bind="value: title" /><button data-bind="click: $parent.delete">Delete</button></li>
        </ol>
        <button data-bind="click: add">Add Another</button>
        <!-- /ko -->
        <button data-bind="click: $root.save">Save</button>        
    </div>
    <ol data-bind="sortable: questions">
        <li>
            <label data-bind="text: title, attr: { for: 'eq' + $index() }"></label>
            <!-- ko if: isText -->
            <input data-bind="attr: { id: 'eq' + $index() }" />
            <!-- /ko -->
            <!-- ko if: isTextarea -->
            <textarea data-bind="attr: { id: 'eq' + $index() }"></textarea>
            <!-- /ko -->
            <!-- ko if: isDropdown -->
            <select data-bind="attr: { id: 'eq' + $index() }, foreach: answers">
                <option data-bind="text: title"></option>                    
            </select>
            <!-- /ko -->
            
            <ul class="utility-bar">
                <li><button data-bind="click: $root.edit">edit</button></li>                
                <li><button data-bind="click: $root.copy">copy</button></li>             ...

CSS

.utility-bar {float:right;}
.utility-bar li {display:inline;}
.clear {clear:both;}

JavaScript

/*globals ko */
var data = {
        formId: 1,
        title: 'Contact Form',
        questions: [{
            title: 'Name',
            type: 'text'},
        {
            title: 'Reason',
            type: 'dropdown',
            answers: ['Sales', 'Support']},
        {
            title: 'Message',
            type: 'textarea'}]
    },
    AjaxPersistanceManager = { submit: function (form) { console.dir(form); } },
    QuestionViewModel = function (question) {
        var self = this,
            answers = $.map(question.answers || [], function (a) { return { title: ko.observable(a) }; });
        self.title = ko.observable(question.title);
        self.type = ko.observable(question.type);
        self.answers = ko.observableArray(answers);
        self.isText = ko.computed("hej");
        self.isTextarea = ko.computed(function () { return self.type() === 'textarea'; });
        self.isDropdown = ko.computed(function () { return self.type() === 'dropdown'; });
        self.isCheckBoxes = ko.computed(function () { return self.type() === 'checkboxes'; });
        self.isRadios = ko.computed(function () { return self.type() === 'radios'; });
        self.isMultipleChoice = ko.computed(function () { return self.isDropdown() || self.isCheckBoxes() || self.isRadios(); });
        
        self.delete = function (answer) {
            self.answers.remove(answer);
        };
        self.add = function () {
            self.answers.push({ title: ko.observable('') });
        };
        
        self.debug = ko.computed(function () { return ko.toJSON(self); });
    },
    FormViewModel = function (form) {
        var self = this,
            questions = $.map(form.questions, function (q) { return new QuestionViewModel(q); });
        self.formId = ko.observable(form.formId);
        self.title = ko.observable(form.title);
        self.questions = ko.observableArray(questions);
        self.selectedQuestion = ko.observable(null);

        self.edit = function...