Are there any examples of using jquery-ui datepicker on a TextBox with Dotvvm 4.3? I can get the calendar to appear and I can select a date. The correct date is displayed in the text box, but when the form is submitted nothing is saved. I can type a date into the text box and submit and it is saved. I think my problem is Knockout JS value-binding related.
I guess that jquery ui datepicker doesnβt trigger the change event on the input when you select a value from the calendar. Can you post a snippet of a code so I can see how the syntax looks like?
I managed to get the value-binding to work by following your easepick and bootstrap datepicker examples.
I use viewModel.DateFormat.state to get the date format string from the viewmodel. There may be a better way to do this. I plan to change this and add a value-binding property to the DatePicker control.
I added a change event postback to update the viewmodel when a date is selected.
This is my binding handler
dotvvm.events.init.subscribe(function () {
ko.bindingHandlers["DatePicker"] = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
console.log('bindingHandler init');
$(element)
.datepicker({
dateFormat: viewModel.DateFormat.state,
onSelect: function (t,c) {
console.log("onSelect fired, Date: ", t);
// this will retrieve the property from the viewmodel
var prop = valueAccessor();
var date = dotvvm.serialization.parseDate(prop.state, false);
var selectedDate = $(this).datepicker("getDate");
if (date != selectedDate) {
if (ko.isWriteableObservable(prop)) {
console.log('update viewmodel and fire change event');
prop(selectedDate);
element.dispatchEvent(new Event("change"));
}
}
}
})
.on('change blur', function (e) {
console.log("change event fired:", $(this).val());
if (!$(element).val()) {
// if someone deletes the value from the textbox, set null to the viewmodel property
var prop = valueAccessor();
if (ko.isWriteableObservable(prop)) {
console.log('setting viewmodel proprty to null');
prop(null);
}
}
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
console.log('bindingHandler update');
// get the value from the viewmodel
var value = ko.unwrap(valueAccessor());
// if the value in viewmodel is string, convert it to Date
if (value && typeof value === "string") {
console.log('setting viewmodel value to: ' + value);
value = dotvvm.globalize.parseDotvvmDate(value);
}
// set the value to the control
if (value instanceof Date) {
console.log('setting date value to control');
$(element).datepicker("setDate", value);
}
}
};
});
This is my code control
using DotVVM.Framework.Binding;
using DotVVM.Framework.Binding.Expressions;
using DotVVM.Framework.Controls;
using DotVVM.Framework.Hosting;
using Newtonsoft.Json;
using System;
namespace AuctionDotVVMApp.Controls
{
public class DatePicker : HtmlGenericControl
{
[MarkupOptions(Required = true)]
public DateTime? Date
{
get { return (DateTime?)GetValue(DateProperty); }
set { SetValue(DateProperty, value); }
}
public static readonly DotvvmProperty DateProperty
= DotvvmProperty.Register<DateTime?, DatePicker>(c => c.Date, null);
public DatePicker() : base("input")
{
}
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context)
{
context.ResourceManager.AddCurrentCultureGlobalizationResource();
IValueBinding dateBinding = null;
foreach (var item in Properties)
if (item.Key == DateProperty)
dateBinding = item.Value as IValueBinding;
if (dateBinding == null)
{
// should never get here ???
var expression = dateBinding.GetKnockoutBindingExpression(this);
expression = "dotvvm.globalize.formatString(" + JsonConvert.ToString("M.d.yyyy") + ", " + expression + ")";
writer.AddKnockoutDataBind("myDatePicker", expression);
}
else
{
writer.AddKnockoutDataBind("DatePicker", this, DateProperty, renderEvenInServerRenderingMode: true);
}
base.AddAttributesToRender(writer, context);
}
protected override void OnPreRender(IDotvvmRequestContext context)
{
context.ResourceManager.AddRequiredResource("date-picker");
base.OnPreRender(context);
}
protected override void RenderBeginTag(IHtmlWriter writer, IDotvvmRequestContext context)
{
writer.RenderSelfClosingTag(TagName);
}
protected override void RenderEndTag(IHtmlWriter writer, IDotvvmRequestContext context)
{
}
}
}