<input id='deadline' type='text' data-bind='jqueryui: "datepicker"' />
<input id='search'data-bind='jqueryui: { widget: "autocomplete",options: { source: searchCompletions(),delay: 500 } },value: searchString' />
(function( $ ) {
$.widget( "myWidget", {
// These options will be used as defaults
options: { clear: null },
// Set up the widget _create: function() {
this._bindViewModel();
ko.applyBindings(this, this.element.get(0));
},
_bindViewModel:function(){
var countryViewModel= ko.observable({
name:ko.observable(),
code:ko.observable(),
flag:ko.observable()
});
}
});
}( jQuery ) );
I recently joined a project that makes extensive use of jQuery UI Widgets -- not just the standard ones, but also its own custom ones as a general architecture for holding view-layer code.We're adding Knockout to the mix and wanted to create a single, reusable binding for UI widgets. Since several other people here seem to be working with jQuery UI, I thought I'd share what we've come up with. Comments and feedback are very much welcome, and please feel free to use this in your own projects.Here's the Knockout custom binding code: https://gist.github.com/889400.Here's a fiddle with some demonstrations: http://jsfiddle.net/medmunds/4Xjtq/This simple example attaches the jQuery UI datepicker widget to an input field, with all of datepicker's default options:
<input id='deadline' type='text' data-bind='jqueryui: "datepicker"' />
You can also pass jQuery UI options in the binding -- and the real power comes from using Knockout observables in those options. Here's a slightly-more complex example that does just that (and also uses KO's 'value' binding for the contents of the input field):
<input id='search'data-bind='jqueryui: { widget: "autocomplete",
options: { source: searchCompletions(),delay: 500 } },value: searchString' />
In this example, searchCompletions would be a ko.observableArray in your viewModel, used to provide the possibilities for jQuery UI's autocomplete widget. The options are not only passed to the UI widget at creation time, but they're also updated on the widget whenever they change. So long as searchPossibilities is a Knockout observable, whenever you update searchPossibilities in your viewModel, they're automatically updated in the autocomplete widget. (The fiddle above includes a version of this example: switching the 'category' will change the autocompletions for the 'product' field using a ko.dependentObservable.)We've been working with this for a couple of weeks now. Some observations:
- This approach seems to work well with jQuery UI Widgets that are designed to enhance existing HTML with little additional code (e.g., button, buttonset, datepicker, autocomplete).
- I think it's less attractive for some of the other jQuery UI Widgets. E.g., the example fiddle includes a slider bound to a ko.observable value, but I think the code in that binding is particularly ugly and really doesn't belong in the HTML. For real-world use, I'd probably want to create a custom KO binding specifically for the slider to hide all of this.
- The code hasn't been extensively tested (and we haven't tried all of the jQuery UI Widgets), so I'm sure there are bugs lurking. E.g., autocomplete seems to have a weird interaction with KO's value binding if you use the mouse in the autocomplete menu -- but it works fine if you use the keyboard (and, oddly, datepicker doesn't have the same problem). Draggable seems to work, but resizable doesn't. Etc.
Also, one big caveat: the jQuery UI Widgets created this way will never get destroyed. This may or may not be a problem for you. (It is for us, as we're using them inside some deeply-nested foreach templates that get updated frequently, meaning Knockout is constantly creating and deleting DOM elements with these widgets attached. Our current solution involves modifying Knockout to call a new 'destroy' method in custom bindings, so that code's not included here. Perhaps some of you will have ideas for a better approach.)
Is it possible to bind two widgets to the same div, for example drag and resize?
<input data-bind="value: my_date, jqueryui: { widget: 'mask', options: '99-99-9999' }, jqueryui: 'datepicker'" />
$('.datepicker').mask("99-99-9999").datepicker();