(Knockout) jQuery UI Select List (Multiple)

Uses Knockout to do a select list where the option selected can have multiple properties.

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-latest.debug.js"></script>
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/base/jquery-ui.css">
<script src="https://raw.github.com/fnagel/jquery-ui/selectmenu/ui/jquery.ui.selectmenu.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/themes/ui-lightness/jquery-ui.css">
<ul style="overflow: none; clear: both; list-style: none;" id="main">
    <li>
        <select name="products" id="products" data-bind="options: Products, optionsCaption: 'select a product...', optionsText: 'name', value: Selected, valueUpdate: blur">
        </select>
    </li>
    <li>
        <select name="medium" id="medium" data-bind="jqSelect: true, options: Selected() ? Selected().mediums : null, value: Medium, optionsText: 'name', valueUpdate: blur"></select>
    </li>
</ul>
<div data-bind="text: Selected() ? Selected().name: 'None selected'"></div>
<div data-bind="text: Selected() ? ko.toJSON(Selected().mediums) : 'No mediums available'"></div>
<div data-bind="text: Selected() ? Selected().guid: ''"></div>

CSS

#main > li {
    width: 45%;
    float: left;
}
/*
* jQuery UI Select Menu 1.8.14
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Button#theming
*/
.ui-selectmenu {
    display: block;
    position: relative;
    height: 2.2em;
    vertical-align: middle;
    text-decoration: none;
    overflow: auto;
    zoom: 1; }
.ui-selectmenu-icon {
    position: absolute;
    right: 6px;
    margin-top: -8px;
    top: 50%; }
.ui-selectmenu-menu {
    /* z-index: 1005 to make selectmenu work with dialog */
    padding: 0;
    margin: 0;
    list-style: none;
    position: absolute;
    left: 0;
    top: 0;
    display: none;
    overflow: hidden;
    z-index: 1005; }
.ui-selectmenu-menu li {
    padding: 0;
    margin: 0;
    display: block;
    border-top: 1px dotted transparent;
    border-bottom: 1px dotted transparent;
    border-right-width: 0 !important;
    border-left-width: 0 !important;
    font-weight: normal !important; }
.ui-selectmenu-menu li a {
    line-height: 1.4em;
    display: block;
    padding: .405em 1em;
    outline: none;
    text-decoration: none; }
.ui-selectmenu-status {
    line-height: 1.4em;
    display: block;
    padding: .405em 1em;
    outline: none;
    text-decoration: none;
    vertical-align: middle; }
.ui-selectmenu-open {
    display: block; }
.ui-selectmenu-popup {
    margin-top: -1px; }

.ui-selectmenu-menu li.ui-state-disabled a, .ui-state-disabled {
    cursor: default; }

.ui-selectmenu-menu li.ui-selectmenu-hasIcon a,
.ui-selectmenu-hasIcon .ui-selectmenu-status {
    padding-left: 20px;
    position: relative;
    margin-left: 5px; }

.ui-selectmenu-menu li .ui-icon, .ui-selectmenu-status .ui-icon {
    position: absolute;
    top: 1em;
    margin-top: -8px;
    left: 0; }

.ui-selectmenu-status {
    line-height: 1.4em; }

.ui-selectmenu-menu li span, .ui-selectmenu-status span {
    display: block;
 ...

JavaScript

(function($) {
    ko.bindingHandlers.jqSelect = {
        update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
            // first, get the latest data that we're bound to
            var value = valueAccessor(),
                allBindings = allBindingsAccessor();

            // try to unwrap whatever we were passed.
            var valueUnwrapped = ko.utils.unwrapObservable(value);
            var $element = $(element);
            if($element.destroy) {
               $element.destroy(); 
            }
            $element.selectmenu({
                style: 'dropdown',
                width: 180
            });
        }
    };
})(jQuery);

function Medium(guid, name) {
    this.guid = ko.observable(guid);
    this.name = ko.observable(name);
}

function Product(guid, name, mediums) {
    this.guid = ko.observable(guid);
    this.name = ko.observable(name);
    this.mediums = ko.observableArray(mediums);
}

var viewModel = {
    Products: ko.observableArray([
        new Product("5658ff20-f230-4176-97d1-0ac21abfdbdf", "Windows XP", [
        new Medium("1", "CD"),
        new Medium("2", "DVD"),
        new Medium("3", "Download")
        ]),
        new Product("1d7b9b28-25b7-40de-bec1-0a5426228f5b", "Windows Vista", [
        new Medium("2", "DVD"),
        ]),
        new Product("28605d66-d794-4a09-8452-0278abd690c6", "Windows 7", [
        new Medium("2", "DVD"),
        new Medium("3", "Download")
        ])
        ]),
    Selected: ko.observable(),
    Medium: ko.observable()
};


ko.applyBindings(viewModel);

$(document).ready(function() {
      $('select').selectmenu({
          style: 'dropdown',
          width: 230
      });
});