2

I have the following view model

public class FormViewModel
{
    [Required]
    public DateTime? LocalFrom { get; set; }

    [Required]
    public DateTime? LocalTo { get; set; }
}

then in the controller I have the following action

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index([Bind(Include = "LocalFrom,LocalTo")] FormViewModel model)
{
    if (ModelState.IsValid)
    {
        var presenter = new ManagePresenter(model);
        return View(presenter);
    }
    return View(model); // here model.LocalFrom, model.LocalTo should be null
}

Here is my HTML form

<form class="form-horizontal" action="/Manage/Index" method="post">

    @Html.AntiForgeryToken()
    <div class="form-group">
        <label class="control-label col-sm-2" for="LocalFrom">From</label>
        <div class="col-sm-10">
            <input type="datetime" class="form-control" id="LocalFrom" name="LocalFrom" value="@Model.LocalFrom" required>
        </div>
    </div>

    <div class="form-group">
        <label class="control-label col-sm-2" for="LocalTo">To</label>
        <div class="col-sm-10">
            <input type="datetime" class="form-control" id="LocalTo" name="LocalTo" value="@Model.LocalTo)" required>
        </div>
    </div>

    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-primary">Submit</button>
        </div>
    </div>

</form>

I am not sure if making nullable property required is logical or not here. I basically want to populate the input with the name LocalFrom in the view with blank when Model.LocalFrom is null or with the correct value when Model.LocalFrom is not null.

Problem

Then ModelState.IsValid is always returning false even we all the required values are present and valid.

When I make LocalFrom and LocalTo not nullable I the ModelState becomes valid. but in the view will display the time of the beginning of time like so

enter image description here

How can I pass null value to the view and make the ModelState to validate correctly?

Jaylen
  • 39,043
  • 40
  • 128
  • 221
  • These might help you: http://stackoverflow.com/a/39094061/2912943 and http://stackoverflow.com/questions/12048838/hiding-the-default-value-for-a-date – Jeff Guillaume Sep 13 '16 at 20:13
  • @JeffGuillaume I already have my DateTime property nullable. but the problem is the ModelState.IsValid is always false – Jaylen Sep 13 '16 at 20:17
  • I edited my comment above to add another link, did you check that one too? – Jeff Guillaume Sep 13 '16 at 20:22
  • I am not able to duplicate your issue locally or in [dotNetFiddle](https://dotnetfiddle.net/GWuRUi). Seems to work fine in the fiddle, with the exception that you should use `DisplayFormat` as @JeffGuillaume suggests in his first link. – stephen.vakil Sep 13 '16 at 20:28
  • try to delete `required` at view. – Hadee Sep 13 '16 at 21:01

1 Answers1

3

If you want to allow null values, then you need to remove the [Required] attribute from your DateTime properties. A [Required] attribute means that the value cannot be null so if you submit an empty value (null) then ModelState will be invalid.

Removing the attributes means that submitting a valid date or null will be valid, but submitting an invalid date will still result in ModelState being invalid.

In addition, you generating your html manually, and as a result you are not getting correct 2-way model binding (which is why you see the default value for DateTime when you return the view). Your view should be

<div class="form-group">
    @Html.LabelFor(m => m.LocalFrom, new { @class="control-label col-sm-2" }) // assumes you add [Display(Name = "From")] to the property
    <div class="col-sm-10">
        @Html.TextBoxFor(m => m.LocalFrom)
        @Html.ValidationMessageFor(m => m.LocalFrom)
    </div>
</div>

As a side note, you should remove the unnecessary [Bind] attribute. You're using a view model, which means you're already protected from over-posting attacks.

Finally, include the jquery.validate.js and jquery.validate.unobtrusive.js scripts in your view so that you get client side validation that matches your server side validation attributes and the appropriate error message is displayed in the view.

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
  • I have a question about your note regarding the jQuery libraries. Does microsoft use this jquery validation plugin https://jqueryvalidation.org/? or do they have their own? Additionally, what is the `jquery.validate.unobtrusive.js` for or what does it do for me? – Jaylen Sep 14 '16 at 19:59
  • The scripts required for client side validation are `jquery-{version}.js`, `jquery.validate.js` and `jquery.validate.unobtrusive.js`. When you apply a validation attribute that implements `IClientValidatable` (e.g. a `[Required]` attribute), the `HtmlHelper` methods will render a series of `data-val-*` attributes for the input. When the page is rendered, `jquery.validate.unobtrusive.js` reads those attributes and adds rules to `jquery.validate.js` which in turn checks the values of the inputs and displays error messages if not valid. –  Sep 14 '16 at 22:36