Question

As the default editors that MVC3 provides for DateTime are not HTML5 friendly, I have coded the following custom Editor Template:

(DateTime.cshtml)

@model DateTime?

<input type="date" value="@{ 
    if (Model.HasValue) {
        @Model.Value.ToISOFormat() // my own extension method that will output a string in YYYY-MM-dd format
    }
}" />

Now, this works fine, but then I had the problem of the dates not being correctly parsed, being that the ISO dates are not not parsed with the default DateTime binding. So, I implemented my own binder:

public class IsoDateModelBinder: DefaultModelBinder
{
    const string ISO_DATE_FORMAT = "YYYY-MM-dd";

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (string.IsNullOrEmpty(value.AttemptedValue))
            return null;

        DateTime date;
        if (DateTime.TryParseExact(value.AttemptedValue, ISO_DATE_FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out date));
            return date;

        return base.BindModel(controllerContext, bindingContext);
    }
}

And I have registered it (Global.asax.cs):

System.Web.Mvc.ModelBinders.Binders.Add(typeof(DateTime), new IsoDateModelBinder());
System.Web.Mvc.ModelBinders.Binders.Add(typeof(DateTime?), new IsoDateModelBinder());

However, when the custom edit template is in place, the custom binder won't get called at all. I had removed it from the solution and the custom binder is correctly called -- although at that point the format is wrong because the custom editor hadn't provide the correct controls.

So, what am I missing?

Was it helpful?

Solution

Turns out that I got it working. I suspected of an interference between both capabilities, but actually it was not.

The problem is in the editor template, it was incomplete. For the form to send back the values, they need to have a value (of course) and a name. If the name is not present, the value won't be posted back to the server, and, of course, the binder won't be called as there is no value to bind.

The correct template should look more something like this:

@model DateTime?

<input type="date" id="@Html.IdFor(model => model)" name="@Html.NameFor(model => model)" value="@{ 
    if (Model.HasValue) {
        @Model.Value.ToISOFormat()
    }
}" />

Furthermore, the ISO format string was wrong on my side, it should have been yyyy-MM-dd instead of YYYY-MM-dd.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top