0

I am trying to implement MVC 3 RemoteValidatorAttribute for the first time. But it is not firing and I don't know what I am doing wrong.

I have a Create view with the following*

@model Demo.Models.Entity
@using Demo.Models;
...
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
...
@using (Html.BeginForm("Create", "Entities", FormMethod.Post, new { enctype = "multipart/form-data", role = "form" })) 
{
    @Html.ValidationSummary(false)
    ...
    <table>
        <tr class="editor-table-detail-row">
            <th>Purchase Date</th>
        </tr>
        @foreach(EntityDetail detailItem in Model.details)
        {
            Html.RenderPartial("_DetailEditorRow", detailItem);
        }
    </table>
    ...
}
...

The partial view code is as follows*

@model Demo.Models.EntityDetail

<tr class="editor-table-detail-row">
@using (Html.BeginCollectionItem("details"))
{
    <td>
        @Html.EditorFor(model => model.purchaseDate, "BootstrapDefaultDatePicker")
        @Html.ValidationMessageFor(model => model.purchaseDate)
    </td>
    <td>
        <a href="#" class="delete-table-row">Delete</a>
    </td>
}
</tr>

I create a ValidationController as follows*

using System;
using System.Web.Mvc;

namespace PostalRepairs.Controllers
{
    public class ValidationController : Controller
    {
        [HttpPost]
        public JsonResult ValidateDateNotFuture(DateTime date)
        {
            if (date <= DateTime.Now) 
                return Json(true);

            return Json(false);    
        }
    }
}

And the EntityDetailClass is as follows * using System; using System.ComponentModel.DataAnnotations; using System.Collections.Generic; using System.Web.Mvc;

namespace Demo.Models
{
    public class EntityDetail 
    {
        ...
        [Display(Name = "Purchase Date")]
        [Remote("ValidateDateNotFuture", "Validation", HttpMethod = "Post", ErrorMessage = "The {0} cannot be in the future.")]
        [Required]
        public DateTime? purchaseDate { get; set; }
        ...        
    }
}

*I have removed the lines not involved in the behavior I am trying to reproduce and change model, controller, view and attribute name for confidential issues. The only real names are EntityDetail.purchaseDate and all the code in ValidationController class.

But when I test the solution the purchase date is accepting invalid dates (according to business rules, purchase date should not be in the future). If a place a breakpoint inside ValidateDateNotFuture controller action method the break point never stops execution so I am guessing the action is never being called.

Can anyone give me some lights?

BTW I was trying to limit the purchase date datepicker but this jquery code is not working. If I can limit the input then the remote validator would not be necessary. I am using a bootstrap template in this project

$("#add-details-table-item").click(function () {
    $.ajax({
        url: this.href,
        cache: false,
        success: function (html) {
            $("tr.editor-table-detail-row:last").after(html);
            $("tr.editor-table-detail-row:last").find(".default-date-picker").datepicker({
                maxDate: '+0'
            });
        }
    });
    return false;
});

$("tr.editor-table-detail-row .default-date-picker").each(function () {
    $(this).datepicker({
        maxDate: '+0'
    });
});

I have tried with .datepicker({ maxDate: 0 }); .datepicker({ maxDate: '0' }); .datepicker({ maxDate: '+0' }); .datepicker({ maxDate: $.now() });

And no luck.

Oscar Ibarra
  • 11
  • 1
  • 6
  • Possible duplicate of [Remote Validation for LIST of MODELs](http://stackoverflow.com/questions/27513472/remote-validation-for-list-of-models) –  Jun 03 '16 at 12:25
  • Side note; Using a `RemoteAttribute` to check that the date is not greater that todays date is an unnecessary waste of resources. Add an additional (readonly) property to your view model (say `DateTime MaxDate { get { return DateTime.Today; } }`) and include a hidden input for it, and add a [foolproof](http://foolproof.codeplex.com/) `[LessThan("MaxDate")]` or similar attribute to your `purchaseDate` property so that you get both client side (without a server call) and server side validation (currently you would need to repeat the code in your controllers POST method) –  Jun 04 '16 at 06:30
  • I solved this through jQuery it was endDate instead of maxDate. Now the calendar restricts correctly the user input. – Oscar Ibarra Jun 14 '16 at 10:54
  • Without the `[LessThan("MaxDate")]` you need to repeat the validation code again on the server (never rely on client side validation alone) –  Jun 14 '16 at 10:58
  • Ok. But I have a question with server side validation you mean validation inside HttpPost controller action? What should I put in the first parameter of ModelState.AddModelError method? Remember I am dealing with a list of models. I guess I need an index or something like that to bind correctly to exact element of the list. – Oscar Ibarra Jun 16 '16 at 02:50
  • Yes, Client side validation is a nice bonus but anyone can override it. You must always validate the data on the server. The easiest way to do that is using a `ValidationAttribute`, and using a conditional validation attribute such as the foolproof `[LessThan]` means you get both client side (without your script) and server side validation out of the box. –  Jun 16 '16 at 02:55
  • I dont find any LessThanAttribute in which namespace it is? I am using MVC3 – Oscar Ibarra Jun 16 '16 at 02:59
  • You need to install the [foolproof](http://foolproof.codeplex.com/) Nuget package –  Jun 16 '16 at 03:00
  • I will give it a try. In the meantime, do you know an answer for the question "What should I put in the first parameter of ModelState.AddModelError method?" when dealing with list of models? I am trying another more complex validation that includes accessing the database and knowing the answer to this question can help me to solve both problems. – Oscar Ibarra Jun 16 '16 at 03:12
  • That's all done automatically for you if you use validation attributes. But if you really crazy and want to write it yourself, then `ModelState.AddModelError("[0].SomeProperty", "your error")` assuming your model is a collection of objects containing a property named `SomeProperty` and you and to add an error for the first one –  Jun 16 '16 at 03:17
  • LOL we programmers are crazy by nature dont you? Maybe the [0] approach does not work for me because my collection does not use a consecutive index. What I really dont know is how to get the current element index. But right now stackoverflow is telling me to avoid extended discussions in comments and dont have enough reputation to chat. <> :( – Oscar Ibarra Jun 16 '16 at 03:34

0 Answers0