Knockout jQuery UI Widget Binding

Demonstrates using Knockout with custom jQuery UI Widget binding. Custom binding at https://gist.github.com/889400

by argiropoulostauros

HTML

<script src="https://github.com/downloads/SteveSanderson/knockout/jquery.tmpl.js"></script>
<script src="https://github.com/SteveSanderson/knockout/raw/master/build/output/knockout-latest.debug.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/ui-lightness/jquery-ui.css">
<script src="https://gist.github.com/raw/889400/knockout-jquery-ui-widget.js"></script>
<h2>Knockout with jQuery UI Widget Bindings</h2>

<div>
    <label for='category'>Category:</label>
    <span id='category' 
    data-bind='template: { 
    foreach: categories, 
    name: "category_picker_tmpl",
    templateOptions: { 
    selected: selectedCategory } 
    },
    jqueryui: "buttonset" ' >
    </span>
</div>

<script id='category_picker_tmpl' type='text/x-jquery-template'>
    <input type='radio' id='radio_${id}'
    name='category_radios' value='${id}' 
    data-bind='checked: $item.selected' />
    <label for='radio_${id}' 
    data-bind='text: name'></label>
</script>

<div>
    <label for='product'>Product:</label>
    <input id='product' 
    data-bind='value: product,
    jqueryui: { 
    widget: "autocomplete", 
    options: { 
    source: productCompletions(),
    minLength: 0 } 
    }' />
    <small>(with autocomplete)</small>
</div>

<div>
    <label for='quantity'>Quantity:</label>
    <input id='quantity' type='text' 
    data-bind='value: quantity' />
    <span id='quantity_slider' 
    data-bind='jqueryui: { 
    widget: "slider", 
    options: { 
    max: 10,
    value: quantity(),
    slide: function(evt,ui) { quantity(ui.value); }
    } 
    }' >
    </span>
</div>

<div>
    <label for='deadline'>Date Needed:</label>
    <input id='deadline' type='text' 
    data-bind='jqueryui: "datepicker",
    value: deadline' />
    <small>(with datepicker)</small>
</div>

<div>
    <label for='summary'>Summary:</label>
    <div id='summary' class="ui-widget-content"
    data-bind='text: summary,
    jqueryui: "draggable"' >
   ...

CSS

html {
    font-size: 80%;
}

body > div {
    margin-top: 1em;
}

body > div > label {
    display: inline-block;
    width: 8em;
    margin-right: 0.2em;
    text-align: right;
}

small {
    font-size: 0.8em;
    color: #999999;
}

#quantity_slider {
    margin-left: 0.5em;
    display: inline-block;
    width: 6em;
}

#summary {
    display: inline-block;
    padding: 0.5em;
}

img.ui-datepicker-trigger {
    margin-left: 3px;
}

JavaScript

var viewModel = {
    categories: [
        {
        id: 'fruit',
        name: 'Fruit',
        products: [
            'Apple', 'Banana', 'Blueberry', 'Cherry',
            'Lemon', 'Lime', 'Orange', 'Pear',
            'Raspberry', 'Strawberry'
            ]},
    {
        id: 'vegetable',
        name: 'Vegetables',
        products: [
            'Carrot', 'Eggplant', 'Lettuce', 'Tomato'
            ]},
    {
        id: 'grain',
        name: 'Grains',
        products: [
            'Barley', 'Corn', 'Rice', 'Rye', 'Wheat'
            ]}
    ],
    selectedCategory: ko.observable('fruit'),
    product: ko.observable(""),
    deadline: ko.observable(""),
    quantity: ko.observable("0"),

    getProductCompletions: function() {
        var category = this.selectedCategory();
        for (var i = 0; i < this.categories.length; i++) {
            if (this.categories[i].id === category) {
                return this.categories[i].products;
            }
        }
        return [];
    },

    getSummary: function() {
        return this.quantity() + " " + this.product() + " needed" + (this.deadline() ? " by " + this.deadline() : "")
    }
};
viewModel.productCompletions = ko.dependentObservable(
viewModel.getProductCompletions, viewModel);
viewModel.summary = ko.dependentObservable(
viewModel.getSummary, viewModel);

ko.applyBindings(viewModel);