Datetimepicker`s slowness - jquery-ui

I would like to ask you for advice.
On one page I have many jQuery UI datepicker`s. They are visible in Bootstrap Modal when user click on button.
Unfortunately this page is loading very slow(Especially in IE8). I know that datepicker in IE8 is causing slowness but sometime I receive that script stop working.
This is my datetimepicker in Knockout like a custom bindingHandlers
ko.bindingHandlers.datetimepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().datetimepickerOptions || {};
$(element).datetimepicker(options);//Line 5
//handle the field changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
observable($(element).datetimepicker("getDate"));
});
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).datetimepicker("destroy");
});
},
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
current = $(element).datetimepicker("getDate");
if (value - current !== 0) {
// LINE 23 $(element).datetimepicker("setDate", value);
}
}
};
I comment Line 23 because before I had the same issue with performance. But then I had the picker like that
<input data-bind="datetimepicker: date,datepickerOptions: { minDate: new Date() }"/>
When I comment it everything works great.
Now I change the do (because I want to have visible datepicker when the modal is shown) and I have the same issue.
When I comment LINE 5 there is no slowness but also my datepicker is not vissible.
Can I call the binding of the datepicker's when user click on button to see the Modal? In this way the binding for datepicker's woudn't be initialized during the page loading?
If I change the jQuery UI datepicker to bootstrap datepicker, there will be some changes in performance?

You could potentially "lazily" initialize your datepicker's. For example, to go along with your existing datepicker binding, you could create a lazyDatepicker binding.
Something like:
ko.bindingHandlers.lazyDatepicker = {
init: function(element, valueAccessor, allBindingsAccessor) {
//keep the field's value in sync until the datepicker binding has been initialized
var updater = ko.computed(function() {
var options = ko.unwrap(allBindingsAccessor()),
value = $.datepicker.formatDate(options.dateFormat || "mm/dd/yy", ko.unwrap(valueAccessor()));
$(element).val(value);
});
//use "one" so this only fires a single time on initial focus
$(element).one("focus", function() {
//binding will now keep value in sync
updater.dispose();
//apply the actual datepicker
ko.applyBindingAccessorsToNode(element, {
datepicker: valueAccessor,
datepickerOptions: function() { return allBindingsAccessor.get("datepickerOptions"); }
})
});
}
};
Really this just applies the datepicker binding when the field is focused. I also put some logic in there to keep the field up-to-date with the model until the datepicker is actually initialized (the updater computed).
Here is a fiddle: http://jsfiddle.net/rniemeyer/GvLfV/

Related

MVC 4 - Knockout custom binding and date format

I am using Asp.Net MVC 4 and Knockout in a form.
I have a date input that i wish to format.
I ended up with this solution :
http://jason-mitchell.com/web-development/binding-dates-using-knockout-moment-js/
My problem is when i submit the form, i don't have the date filled in the posted JSON.
I think the problem is located in the custom handler, but i can't find out :(
The update event fires only once at load.
View Code
#Html.TextBoxFor(Function(model) model.EndDate, New With {.data_bind = "date: EndDate"})
Custom binding Code
ko.bindingHandlers.date = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var value = valueAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
var allBindings = allBindingsAccessor();
// Date formats: http://momentjs.com/docs/#/displaying/format/
var pattern = allBindings.format || 'L';
var output = "";
if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
output = moment(valueUnwrapped).format(pattern);
}
if ($(element).is("input") === true) {
$(element).val(output);
} else {
$(element).text(output);
}
}
};
ko binding Code
var viewModel = ko.mapping.fromJS(#Html.Raw(Model.ToJson()));
ko.applyBindings(viewModel);
Note : the date format is working as expecting.
What am i doing wrong ? :(
Without seeing your ViewModel, I can only speculate. In your code, you are binding EndDate directly to your TextBox:
#Html.TextBoxFor(Function(model) model.EndDate, New With {.data_bind = "date: EndDate"})
Your EndDate observable doesn't know anything about this value. Therefore, if your EndDate observable looks something like this in your ViewModel:
this.EndDate = ko.observable();
Then it is unaware of the value that was bound directly to the TextBox by your ASP.NET MVC code. Therefore, when you apply your KO bindings, the EndDate value that was bound directly to the TextBox gets destroyed. If this is the case, you can either: (1) initialize the EndDate observable directly from the value bound from the server Model, or, (2) initialize the EndDate observable indirectly by using a custom KO binding that initializes the EndDate observable from the value that was bound directly to the TextBox.
Example 1
This example assumes the JavaScript is directly in your view. If your JavaScript is in a separate file (as is typically the case), then you would have to pass the Model data into your ViewModel using another technique such as JSON serialization on the client before binding your ViewModel.
this.EndDate = ko.observable('#Model.EndDate.ToString()');
Example 2
The sequential order of the KO binding parameters is important in this example. The new custom binding must be the first binding in order for this to work properly:
#Html.TextBoxFor(Function(model) model.EndDate, New With {.data_bind = "initInputFromView: EndDate, date: EndDate"})
And here is the code for the custom KO binding:
ko.bindingHandlers.initInputFromView = {
init: function (element, valueAccessor) {
// reads the value stored in the <input> value attribute and initializes the observable with that value
valueAccessor()(element.value);
}
};
At last, i found the solution !
The custom binding should look like that :
ko.bindingHandlers.date = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.value.init(element, valueAccessor,
allBindingsAccessor, viewModel, bindingContext);
var value = valueAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
var allBindings = allBindingsAccessor();
// Date formats: http://momentjs.com/docs/#/displaying/format/
var pattern = allBindings.format || 'L';
var output = valueUnwrapped;
if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
output = moment(valueUnwrapped).format(pattern);
}
if ($(element).is("input") === true) {
$(element).val(output);
} else {
$(element).text(output);
}
},
};
It uses the default value binding plus my custom date format.
Only on init because the update is managed by a datepicker which is correctly formated.

Custom binding for cleditor fails after sorting elements through knockout sortable

First up: check this fiddle.
I have sortable array of elements created with the Knockout sortable library. When I initially apply the binding the cleditor initializes fine.
However, when sortable elements are sorted, the cleditor fails to re-initialize (I'm not sure what happens but cleditor fails). The cleditor just displays "true" instead of actual value in Firefox, and nothing in all other browsers.
I'm trying to figure out where the problem is, whether it is on the custom binding, or jQuery-UI, or the Knockout sortable library?
I am not recieving any errors in my console.
ko.bindingHandlers.cleditor = {
init: function(element, valueAccessor, allBindingsAccessor) {
var modelValue = valueAccessor(),
allBindings = allBindingsAccessor();
var $editor = jQuery(element).cleditor({
height: 50,
controls: "bold italic underline | bullets numbering | undo redo"
});
$editor[0].change(function() {
var elementValue = $editor[0].doc.body.innerHTML;
if (ko.isWriteableObservable(modelValue)) {
modelValue(elementValue);
} else {
if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers'].cleditor) {
allBindings['_ko_property_writers'].cleditor(elementValue);
}
}
});
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()) || '',
$editor = jQuery(element).cleditor();
if ($editor[0].doc.body.innerHTML !== value) {
//$editor[0].doc.body.innerHTML = value;
$editor[0].doc.body.innerHTML = value;
$editor[0].focus();
}
}
};
How can I make the cleditor to work, even after the elements are sorted?
I found this resource, but I couldn't find anything wrong in code as said in that topic.
The link you provided was helpful. The CLEditor refresh method is the right way to update it after it's dragged. It just needs to be done at the correct time, using the sortable stop event.
stop: function(event, ui) {
$(ui.item).find("textarea").cleditor()[0].refresh();
}
http://jsfiddle.net/mbest/rh8c2/1/
I also worked to integrate this into your cleditor binding. In the init function:
jQuery(document).on('sortstop', function(event, ui) {
if (jQuery.contains(ui.item[0], element)) {
jQuery(element).cleditor()[0].refresh();
}
});
I also made a change in the update function to keep the <textarea> value in sync, because refresh updates the editor's value from the <textarea>:
$editor[0].updateTextArea();
http://jsfiddle.net/mbest/jw7Je/7/

Knockout jQueryUI Autocomplete how to use input value if nothing selected from autocomplete list

I am using the custom binding provided in How to create an auto-complete combobox?
I want to allow the user to either select a value from the list of suggestions or enter a value that is not in the list of suggestions. How can I get the value of the input into my observable field?
For example, if the user types 'smi' the autocomplete list will show Smith and other surnames beginning with 'smi', however, if they do not select an option from the list, I just want to set the value of my observable field to be 'smi'. At present, the only way the observable propety is set is when the user selects an item from the list of suggestions.
I have the following code (HTML):
<input type="text" data-bind="
value: surname,
jqAuto: { autoFocus: true },
jqAutoSource: surnames,
jqAutoQuery: surnameAutocomplete,
jqAutoValue: surname"
/>
JavaScript view model (simplified):
var vm = {
surnames: ko.observableArray(),
surname: ko.observable(),
surnameAutocomplete: function (searchTerm, result) {
repository.surnameAutocomplete(searchTerm, result);
};
Solution:
I amended the custom binding handler in two places:
init: function - added the following
// New setting to allow / disallow a user to enter values that are in the autocomplete list.
forceSelection = allBindings.jqAutoForceSelection;
options change function - amended to the following
//on a change, make sure that it is a valid value or clear out the model value
options.change = function (event, ui) {
var currentValue = $(element).val();
// Start: new code, check new setting on whether to force user to make a selection
if (!forceSelection) {
writeValueToModel(currentValue);
return;
}
// End: new code
var matchingItem = ko.utils.arrayFirst(unwrap(source), function (item) {
return unwrap(inputValueProp ? item[inputValueProp] : item) === currentValue;
});
if (!matchingItem) {
writeValueToModel(null);
}
}
I also found that the first item in the autocomplete list was being automatically selected, but then noticed by setting autofocus: false solved my issue, e.g.,
<input type="text" data-bind="
jqAuto: { autoFocus: false }, /* This fixes the auto select issue */
jqAutoSource: surnames,
jqAutoQuery: surnameAutocomplete,
jqAutoValue: surname,
jqAutoForceSelection: false"
/>
If you look closely at the binding handler you're using, you will notice this section:
//on a change, make sure that it is a valid value or clear out the model value
options.change = function(event, ui) {
var currentValue = $(element).val();
var matchingItem = ko.utils.arrayFirst(unwrap(source), function(item) {
return unwrap(item[inputValueProp]) === currentValue;
});
if (!matchingItem) {
writeValueToModel(null);
}
What this section of the binding handler essentially does is check if the text the user entered into the text field matches something in the autocomplete dropdown, and if it doesn't, it clears the model value (which it sounds like what you want to change).
You can either try deleting this section or extend it to suit your purposes.

Knockout, CKEditor & Single Page App

I have a situation involving KnockoutJS & CKEditor.
Basically we've got part of our site that is 'single page' app style, currently it just involves 2 pages but will likely expand over time, currently it's just a 'listings' page and a 'manage' page for the items in the list.
The manage page itself requires some sort of rich text editor, we've gone with CKEditor for a company wide solution.
Because these 2 pages are 'single page' style obviously CKEditor can't register against the manage elements because they aren't there on page load - simple enough problem to fix. So as a sample I attached CKEditor on a click event which worked great. The next problem was that then the Knockout observables that had been setup weren't getting updated because CKEditor doesn't actually modify the textarea it's attached too it creates all these div's/html elements that you actually edit.
After a bit of googleing I found an example of someone doing this with TinyMCE - http://jsfiddle.net/rniemeyer/GwkRQ/ so I thought I could adapt something similar to this for CKEditor.
Currently I'm quite close to having a working solution, I've got it initialising and updating the correct observables using this technique (I'll post code at the bottom) and even posting back to the server correctly - fantastic.
The problem I'm currently experiencing is with the 'Single Page' app part and the reinitialisation of CKEditor.
Basically what happens is you can click from list to manage then save (which goes back to the list page) then when you go to another 'manage' the CKEditor is initialised but it doesn't have any values in it, I've checked the update code (below) and 'value' definitely has the correct value but it's not getting pushed through to the CKEditor itself.
Perhaps it's a lack of understanding about the flow/initialisation process for CKEditor or a lack of understanding about knockout bindings or perhaps it's a problem with the framework that's been setup for our single page app - I'm not sure.
Here is the code:
//Test one for ckeditor
ko.bindingHandlers.ckeditor = {
init: function (element, valueAccessor, allBindingsAccessor, context) {
var options = allBindingsAccessor().ckeditorOptions || {};
var modelValue = valueAccessor();
$(element).ckeditor();
var editor = $(element).ckeditorGet();
//handle edits made in the editor
editor.on('blur', function (e) {
var self = this;
if (ko.isWriteableObservable(self)) {
self($(e.listenerData).val());
}
}, modelValue, element);
//handle destroying an editor (based on what jQuery plugin does)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
var existingEditor = CKEDITOR.instances[element.name];
existingEditor.destroy(true);
});
},
update: function (element, valueAccessor, allBindingsAccessor, context) {
//handle programmatic updates to the observable
var value = ko.utils.unwrapObservable(valueAccessor());
$(element).html(value);
}
};
So in the HTML it's a fairly standard knockout 'data-bind: ckeditor' that applyies the bindings for it when the ViewModel is initialised.
I've put debugger; in the code to see the flow, it looks like when I load the first time it calls init, then update, when I go in the second time it hits the ko.utils.domNodeDisposal to dispose of the elements.
I've tried not destroying it which CKEditor then complains that something already exists with that name. I've tried not destroying it and checking for if it exists and initialising if it doesn't - that works the first time but the second time we have no CKEditor.
I figure there's just one thing I'm missing that will make it work but I've exhausted all options.
Does anyone have any knowledge on integrating these 3 things that can help me out?
Are there any knockout experts out there that might be able to help me out?
Any help would be much appreciated.
MD
For anyone interested I sorted it:
All it was was a basic order of execution, I just needed to set the value to the textarea html before it got initialised.
Note this uses a jquery adaptor extension to do the .ckeditor() on the element.
There is probably also a better way to do the 'blur' part.
This extension also doesn't work with options at the moment but that should be quite simple in comparison.
ko.bindingHandlers.ckeditor = {
init: function (element, valueAccessor, allBindingsAccessor, context) {
var options = allBindingsAccessor().ckeditorOptions || {};
var modelValue = valueAccessor();
var value = ko.utils.unwrapObservable(valueAccessor());
$(element).html(value);
$(element).ckeditor();
var editor = $(element).ckeditorGet();
//handle edits made in the editor
editor.on('blur', function (e) {
var self = this;
if (ko.isWriteableObservable(self)) {
self($(e.listenerData).val());
}
}, modelValue, element);
}
};
I've been working with this for a while now and ran again several problems with the .on("blur") approach. Namely, when people clicked in to the rich text and entered text then scrolled directly to the Save button on my form, the observable didn't get updated fast enough. There are a ton of ways to handle delays, but I wanted something more official. I dug in to the CKEditor documentation and found this gem: focusManager
This is built-in functionality that handles all the instances of focus and blur and allows you to hook up a true blur event to the control.
Here is my bindingHandler for rich text then
ko.bindingHandlers.richText = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var txtBoxID = $(element).attr("id");
var instance = CKEDITOR.instances[txtBoxID];
var options = allBindingsAccessor().richTextOptions || {};
options.toolbar_Full = [
['Source', '-', 'Format', 'Font', 'FontSize', 'TextColor', 'BGColor', '-', 'Bold', 'Italic', 'Underline', 'SpellChecker'],
['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'],
['Link', 'Unlink', 'Image', 'Table']
];
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
if (CKEDITOR.instances[txtBoxID]) { CKEDITOR.remove(CKEDITOR.instances[txtBoxID]); };
});
$(element).ckeditor(options);
//wire up the blur event to ensure our observable is properly updated
CKEDITOR.instances[txtBoxID].focusManager.blur = function () {
var observable = valueAccessor();
observable($(element).val());
};
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var val = ko.utils.unwrapObservable(valueAccessor());
$(element).val(val);
}
}
Building up on the work done in the other answers here's my solution:
handles changes using ckeditor's own change event (updates on keypress but not just that)
uses ckeditor's getData() so you don't get unwanted HTML like "magic line" and similar stuff
handles memory management (untested)
Code:
ko.bindingHandlers.ckeditor = {
init: function(element, valueAccessor, allBindingsAccessor, context) {
var options = allBindingsAccessor().ckeditorOptions || {};
var modelValue = valueAccessor();
var value = ko.utils.unwrapObservable(valueAccessor());
$(element).html(value);
$(element).ckeditor();
var editor = $(element).ckeditorGet();
//handle edits made in the editor
editor.on('change', function(e) {
var self = this;
if (ko.isWriteableObservable(self)) {
self($(e.listenerData).val());
}
}, modelValue, element);
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (editor) {
CKEDITOR.remove(editor);
};
});
},
update: function(element, valueAccessor, allBindingsAccessor, context) {
// handle programmatic updates to the observable
var newValue = ko.utils.unwrapObservable(valueAccessor());
if ($(element).ckeditorGet().getData() != newValue)
$(element).ckeditorGet().setData(newValue)
}
};
The markup I use (note the afterkeydown):
<textarea
id="editor1"
data-bind="ckeditor: text, valueUpdate: 'afterkeydown'"
></textarea>
Update: as requested in the comments, here is a minimal working Fiddle.
First post so let me know if I've done anything wrong
In my project, I gave visual feedback as to whether there were unsaved changes and so needed the observable updated on keyup. And on click for when a toolbar button was clicked. This also was consistent with me using valueUpdate:['afterkeydown','propertychange','input'] in my data-bind attributes.
Also, for performance, I used the callback method parameter of .ckeditor(callback,options) rather than .on(eventName,handler).
This is the custom binding I came up with:
ko.bindingHandlers.ckeditor = {
init: function (element, valueAccessor, allBindingsAccessor, context) {
// get observable
var modelValue = valueAccessor();;
$(element).ckeditor(function(textarea) {
// <span> element that contains the CKEditor markup
var $ckeContainer = $(this.container.$);
// <body> element within the iframe (<html> is contentEditable)
var $editorBody =
$ckeContainer.find('iframe').contents().find('body');
// sets the initial value
$editorBody.html( modelValue() );
// handle edits made in the editor - by typing
$editorBody.keyup(function() {
modelValue( $(this).html() );
});
// handle edits made in the editor - by clicking in the toolbar
$ckeContainer.find('table.cke_editor').click(function() {
modelValue( $editorBody.html() );
});
});
// when ko disposes of <textarea>, destory the ckeditor instance
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).ckeditorGet().destroy(true);
});
},
update: function (element, valueAccessor, allBindingsAccessor, context) {
// handle programmatic updates to the observable
var newValue = ko.utils.unwrapObservable(valueAccessor());
var $ckeContainer = $(element).ckeditorGet().container;
if( $ckeContainer ) {
// <span> element that contains the CKEditor markup
$ckeContainer = $($ckeContainer.$);
// <body> element within the iframe (<html> is contentEditable)
var $editorBody =
$ckeContainer.find('iframe').contents().find('body');
// if new value != existing value, replace it in the editor
if( $editorBody.html() != newValue )
$editorBody.html( newValue );
}
}
};
Justification:
I know I should probably use .getData() and .setData(html) instead of this rather hacky way of finding <body> and <table class="cke_editor"> within the iframe contents.
Reason being, for update: the condition within:
if( $(element).ckeditorGet().getData() != newValue )
$(element).ckeditorGet().setData( newValue )
was initially true due to HTML formatting that CKEditor does. And so, notified the user about a dirty record even though it wasn't. Very specific to me so I thought you should know, in case you were wondering why.
I just used this technique with CKEditor 4 to overwrite the existing (1-way) "html" binding with a 2-way binding. I'm using the inline CKEditor which may behave differently (not sure) than the full/static editor. I started with the "value" binding and tweaked it to work with the innerHTML instead:
ko.bindingHandlers.html = {
'init': function (element, valueAccessor, allBindingsAccessor) {
var eventsToCatch = ["blur"];
var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
var valueUpdateHandler = null;
if (requestedEventsToCatch) {
if (typeof requestedEventsToCatch == "string")
requestedEventsToCatch = [requestedEventsToCatch];
ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
}
valueUpdateHandler = function () {
var modelValue = valueAccessor();
var oldValue = ko.utils.unwrapObservable(modelValue);
var elementValue = element.innerHTML;
var valueHasChanged = (oldValue !== elementValue);
if (valueHasChanged)
modelValue(elementValue);
}
ko.utils.arrayForEach(eventsToCatch, function (eventName) {
var handler = valueUpdateHandler;
if (eventName.indexOf("after") == 0) {
handler = function () {
setTimeout(valueUpdateHandler, 0)
};
eventName = eventName.substring("after".length);
}
ko.utils.registerEventHandler(element, eventName, handler);
});
},
'update': function (element, valueAccessor) {
var newValue = ko.utils.unwrapObservable(valueAccessor());
var elementValue = element.innerHTML;
var valueHasChanged = (newValue !== elementValue);
if (valueHasChanged)
element.innerHTML = newValue;
}
};
Caveat: This should probably be updated to use CKEditor's own change event.
I rewrote this to update the observable on each keyup, instead of on blur. This is a lot more updates to the observable, but as long as you are saving with a button, this seems to work great so far!
//handle edits made in the editor
CKEDITOR.instances.thread_message.on('contentDom', function() {
CKEDITOR.instances.thread_message.document.on('keyup', function(e) {
var self = this;
if (ko.isWriteableObservable(self)) {
var ckValue = CKEDITOR.instances.element_id.getData();
self(ckValue);
//console.log("value: " + ckValue);
}
}, modelValue, element);
});
For the 'blur' part, I tried the code below and it seems to work
editor.on('blur', function (e) {
var self = this;
if (ko.isWriteableObservable(self)) {
var ckValue = e.editor.getData();
self(ckValue);
}
}, modelValue, element);
I think the 'Update' part is still needed if you "update" the observable from somewhere else (not through editing as this is taken care of by the 'blur')

Change title when opening dialog from knockout binding

I have based my code on this example
http://jsfiddle.net/rniemeyer/WpnTU/
When you select an item I want the title of the dialog to have a observable's value
I managed to to it by creating another custom binding
ko.bindingHandlers.dialogOptions = {
update: function(element, valueAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor());
if (options ) {
$(element).dialog(options);
}
}
}
Added a new observable to viewmodel and set it when the item is selected
this.selectProduct = function(product) {
self.dialogOptions({ title: product.name() });
self.selectedProduct(product);
}
Working example: http://jsfiddle.net/WpnTU/76/
It works but I do not like it, it adds a new observable which is very coupled with the GUI, it would be much nicer if I could use the already exiting selectProduct observable and point out the name property in the GUI something like { title: selectProduct.name }
Here is a sample that moves the .dialog calls into the update function and unwraps the options, so that it will be triggered any time that something changes.
//custom binding to initialize a jQuery UI dialog
ko.bindingHandlers.jqDialog = {
init: function(element) {
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).dialog("destroy");
});
},
update: function(element, valueAccessor) {
var options = ko.toJS(valueAccessor());
if (options) {
$(element).dialog(options);
}
}
};
I added a computed observable to your sample just to handle the selectedProduct being null (could be done in-line).
http://jsfiddle.net/rniemeyer/Gt5Hw/

Resources