MVC4 Validation happens after submit

449 views Asked by At

I have some issues with my MVC4 applications - the form validation happens only after submit.

I want the form to be validated before submission. This is (part) of my view

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    Html.EnableClientValidation();
    Html.EnableUnobtrusiveJavaScript();
    <fieldset>
    <legend>Offer</legend>
    <div class="editor-label">
        @Html.LabelFor(model => model.HotelName)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.HotelName)
        @Html.ValidationMessageFor(model => model.HotelName)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.LocationName)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.LocationName)
        @Html.ValidationMessageFor(model => model.LocationName)
     </div>

I also have in my web.config

    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />

And these are all the scripts included in my page

    <script type="text/javascript" length="7" src="/Scripts/jquery/jquery-2.0.3.js?cdv=1">
    <script type="text/javascript" length="7" src="/Scripts/jquery/jquery-2.0.3.min.js?cdv=1">
    <script type="text/javascript" length="7" src="/Scripts/jquery/jquery.cookies.js?cdv=1">
    <script type="text/javascript" length="7" src="/Scripts/language.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jqueryval/jquery.validate.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jqueryval/jquery.validate.min.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jqueryval/jquery.validate.unobtrusive.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jqueryval/jquery.validate.unobtrusive.min.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jquery-ui/jquery-ui-1.10.3.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jquery-ui/jquery-ui-1.10.3.min.js?cdv=1">
    <script type="text/javascript" src="/Scripts/file-upload/jquery.fileupload.js?cdv=1">
    <script type="text/javascript" src="/Scripts/file-upload/jquery.fileupload-process.js?cdv=1">
    <script type="text/javascript" src="/Scripts/file-upload/jquery.fileupload-main.js?cdv=1">
    <script type="text/javascript" src="/Scripts/file-upload/jquery.fileupload-validate.js?cdv=1">
    <script type="text/javascript" src="/Scripts/file-upload/jquery.iframe-transport.js?cdv=1">
    <script type="text/javascript" src="/Scripts/jquery.jcrop.min.js?cdv=1">
    <script type="text/javascript" src="/Scripts/imagemodel.js?cdv=1">

As far as I know the validation is done with jquery unobtrusive. The weird thing is that if I manually run $("form").valid() from console, it returns true, but if I have the "required" attribute on the then $("form").valid() triggers correctly.

Is there a way to add the "required" attribute to the neccesary inputs? Or perhaps there is another way to do client side validation.

Thanks

1

There are 1 answers

0
florinszilagyi On BEST ANSWER

The solution I have come to, is to create an extension for the HtmlHelper class that creates custom validated controls, where the validation attributes are added to the generated HTML.

  public static MvcHtmlString ValidatedTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> attributes)
    {
        var message = GetMessage(htmlHelper, expression);
        return htmlHelper.TextBoxFor(expression, new Dictionary<string, object>(attributes)
            {
                { "data-val", "true" },
                { "data-val-required", message ?? "Must not be empty"},
            });
    }

 private static string GetMessage<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        PropertyInfo[] props = metadata.ContainerType.GetProperties();

        string message = null;
        var info = props.First(prop => prop.Name == metadata.PropertyName);
        var attribute = info.GetCustomAttribute(typeof (RequiredAttribute)) as RequiredAttribute;
        if (attribute != null)
        {
            message = attribute.ErrorMessage;
            if (string.IsNullOrEmpty(message))
            {
                var resource = attribute.ErrorMessageResourceType;
                var resourceName = attribute.ErrorMessageResourceName;

                if (resource == null || resourceName == null)
                    return null;

                message = new ResourceManager(resource).GetString(resourceName);
            }
        }

        return message;
    }