One way to customize validation in ASP.NET MVC is by using IClientValidatable

My question is similar to the ones asked here and here, but in my question, I have used a different implementation. Below are the codes showcasing my implementations:

Model:

public class Department {

    public long Id { get; set; }

    [IsDateAfter("Date2", true, ErrorMessage = "O My")]
    public DateTime Date1 { get; set; }
    public DateTime Date2 { get; set; }
    public string Name1 { get; set; }
    public string Name2 { get; set; }

}

Custom Validator:

public sealed class IsDateAfter : ValidationAttribute, IClientValidatable {

    private readonly string testedPropertyName;
    private readonly bool allowEqualDates;

    public IsDateAfter(string testedPropertyName, bool allowEqualDates = false)
  {
        this.testedPropertyName = testedPropertyName;
        this.allowEqualDates = allowEqualDates;
    }

    protected override ValidationResult IsValid(object value, ValidationContext
 validationContext) {
        var propertyTestedInfo = 
validationContext.ObjectType.GetProperty(this.testedPropertyName);
        if (propertyTestedInfo == null) {
            return new ValidationResult(string.Format("unknown property
 {0}", this.testedPropertyName));
        }

        var propertyTestedValue =
 propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

        if (value == null || !(value is DateTime)) {
            return ValidationResult.Success;
        }

        if (propertyTestedValue == null || !(propertyTestedValue is
 DateTime)) {
            return ValidationResult.Success;
        }

        // Compare values
        if ((DateTime)value >= (DateTime)propertyTestedValue) {
            if (this.allowEqualDates) {
                return ValidationResult.Success;
            }
            if ((DateTime)value > (DateTime)propertyTestedValue) {
                return ValidationResult.Success;
            }
        }

        return new
 ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> 
GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
        var rule = new ModelClientValidationRule {
            ErrorMessage = this.ErrorMessageString,
            ValidationType = "isdateafter"
        };
        rule.ValidationParameters["propertytested"] =
 this.testedPropertyName;
        rule.ValidationParameters["allowequaldates"] =
 this.allowEqualDates;
        yield return rule;
    }
}

Script:

$.validator.unobtrusive.adapters.add(
'isdateafter', ['propertytested', 'allowequaldates'], function (options) {
    options.rules['isdateafter'] = options.params;
    options.messages['isdateafter'] = options.message;
});
$.validator.addMethod("isdateafter", function (value, element, params) {
alert(params.propertytested);
var startdatevalue = $('input[name="' + params.propertytested + '"]').val();
if (!value || !startdatevalue) return true;
return (params.allowequaldates) ? Date.parse(startdatevalue) <= Date.parse(value) :
 Date.parse(startdatevalue) < Date.parse(value);
}, '');

And My _Layout page (Master page)

<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript">
 </script>
<script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript">
 </script>
<script src="@Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript">
 </script>
<script src="@Url.Content("~/Scripts/MicrosoftMvcValidation.js")" 
 type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" 
 type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript">
 </script>
<script src="@Url.Content("~/Scripts/jQuery.IsDateAfter.js")" 
 type="text/javascript"></script>
</head>
<body>
<div class="page">
    <div id="header">
        <div id="title">
            <h1>
                My MVC Application</h1>
        </div>
        <div id="logindisplay">
            @Html.Partial("_LogOnPartial")
        </div>
        <div id="menucontainer">
            <ul id="menu">
        <li>@Html.ActionLink("Departments", "Index", "Department")</li>
            </ul>
        </div>
    </div>
    <div id="main">
        @RenderBody()
    </div>
    <div id="footer">
    </div>
</div>
</body>
</html>

In the Edit And Create View pages, the other script sources are as follows:

<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>

A part of Create Page Dom:

<fieldset>
<legend>Department</legend>
<div class="editor-label">
<label for="Date1">Date1</label>
</div>
<div class="editor-field">
<input id="Date1" class="text-box single-line valid" type="text" value="" name="Date1"
 data-val-required="The Date1 field is required." data-val-isdateafter-
 propertytested="Date2" data-val-isdateafter-allowequaldates="False" data-val-
isdateafter="O My" data-val="true">
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-
  for="Date1"></span>
</div>
<div class="editor-label">
<label for="Date2">Date2</label>
</div>
<div class="editor-field">
<input id="Date2" class="text-box single-line valid" type="text" value="" name="Date2"
 data-val-required="The Date2 field is required." data-val="true">
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-
for="Date2"></span>
</div>

Even though I tried to implement it similarly to the approach mentioned here, it did not work on the client side and requires a postback. I have not found any other alternative such as registering it in global.asax like mentioned here. Does anyone have a solution to this issue? I am quite confused as I have tried two different methods but none of them gave me the desired outcome.

Answer №1

Your script inclusions are not correct. In the _Layout file, you have included scripts in the wrong order:

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jQuery.IsDateAfter.js")" type="text/javascript"></script>

The jquery.validate.min.js and jquery.validate.js are essentially the same script, with the former being minified. However, without including the jquery.validate.unobtrusive.js script (which is added later in your view), your custom jQuery.IsDateAfter.js script will encounter errors as it won't recognize the $.validator.unobtrusive.adapters object that you are using. The correct arrangement of scripts in your layout should be:

<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<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>

If the jQuery.IsDateAfter.js script is used across multiple views, you can also include it at the end of the layout. Otherwise, add it to the specific view:

<script src="@Url.Content("~/Scripts/jQuery.IsDateAfter.js")" type="text/javascript"></script>

This should be the only script included in the view. Remove any other jquery.* script inclusions from your Edit and Create View pages.

Note: I have removed all Microsoft*.js scripts from your Layout as they are outdated and should not be used in ASP.NET MVC 3.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Grab the value of a button's name in a React component when clicked

Exploring ways to access the name attribute of a button in React upon clicking. An attempt was made at achieving this using the following code block: export function TestButton(props){ function logName() { console.log(this.name) } retu ...

Obtain information using AJAX calls with jQuery Flot

Having an issue with jQuery Flot that I need help resolving. PHP output (not in JSON format): [[1, 153], [2, 513], [3, 644]] ~~ [[1, 1553], [2, 1903], [3, 2680]] Here is the jQuery call: $.ajax({ url: 'xxx.php', success: function (dat ...

Learn how to deactivate the pause button with just one click and re-enable it once the popup appears using Angular2 and Typescript

Can anyone assist with solving an issue I am facing with a timer and a pause button? I need the pause button to be disabled once clicked, until a popup appears, then it should become enabled again. My code snippet is provided below: HTML: <button md-i ...

Trying to modify the chosen option while filtering an ajax source using select2?

I am currently integrating the select2 library within a Bootstrap 4 modal in the following manner: <div class="form-group" id="fg-jbInd"> <label for="jbIndustry" class="control-label"gt;Industry * <sele ...

Obtaining Serialized Data

Using the JavaScript serializer to send data to JavaScript: var jsSerializer = new JavaScriptSerializer(); var result = (from c in dt.AsEnumerable() select new { Latitude = c.F ...

Understanding how to open a PNG file in the client-side browser and transform it using PNGJS in React

Utilizing React JS for my application development is a current focus of mine. I have a solid understanding of how to import images within the client/browser folder structure. For example: import maze_text from '../../mazes/images/maze_text.png&apos ...

Working with Javascript objects and arrays

Need assistance with manipulating/updating a JavaScript array. Hoping for some help. The initial array looks like this: array('saved_designs'=array()); In Javascript JSON format: {"saved_design":{}} I plan on adding a label and its associa ...

Issue with Navigation Scrolling Feature on Wordpress

I am in the process of implementing a 'scroll-nav' for my website. To achieve this, I decided to separate the Navigation into two sections and incorporate some jQuery: <nav class="main-nav clearfix"> <?php wp_nav_menu(array('th ...

How to retrieve the first option selected in Material-UI React?

Hey there! I am currently working with React Material UI select. I have a question - how can I set the first option of items as selected without triggering the onChange method? When I change an option, it triggers the onChange method and adds an attribut ...

Tips for retrieving multiple data outputs from an ajax success function

Within my project, I have two separate JavaScript files named myJs1.js and myJs2.js. One of the methods in myJs1.js is invoking a method from myJs2.js. My goal is to retrieve the values r1 and r2 into the results (within myJs1.js). I attempted to achiev ...

Exploring the Difference Between Dot and Bracket Notation in Internet Explorer

I'm encountering a strange problem in IE8 when attempting to retrieve an element using the following code: window.frames.frames[0].name; // obtain the name of the inner iFrame object No complicated logic, but when the script runs, IE7-8 interprets i ...

Creating a JSON array using looping technique

I am attempting to construct a JSON array using a loop where the input className and value will serve as the JSON obj and key. However, I am facing difficulties in creating one and cannot seem to locate any resources on how to do so. Below is an example sn ...

The process of importing jQuery into a project involves importing

I have a website with jQuery and JavaScript functionality. I am including the necessary libraries in the head section of my HTML page: <link rel="stylesheet" href="http://code.jquery.com/ui/1.8.18/themes/base/jquery-ui.css" type="text/css" media="all" ...

How can I configure my React Project to direct users to example.com/login.html when they land on the root URL?

My goal is to verify a user's identity through a third-party authentication server. The redirect_uri indicates that after the user logs in, they will be redirected to example.com/login.html. Inside the login.html file, there will be specific html/scr ...

Creating a standalone module using webpack that can be accessed through a script element

When setting the library target to 'umd' in the package.json file, the expectation was that the outputs would be usable via a <script> tag and if no module system was available it would be attached to the window. However, this does not seem ...

JQuery selector is successfully working while vanilla JavaScript is not functioning as expected

This problem is unique because I am experiencing issues with querySelector and querySelectorAll in my JavaScript code. While JQuery works fine, vanilla JS does not work as expected. I would appreciate any insights on why this might be happening. Thank you ...

Facing problem with implementing NgMoudleFactoryLoader for lazy loading in Angular 8

A situation arose where I needed to lazy load a popups module outside of the regular router lazy-loading. In order to achieve this, I made the following adjustments: angular.json "architect": { "build": { ... "options": { ... "lazyM ...

How can I update the source of an HTML video element seamlessly without causing any glitches?

I'm attempting to create a video call interface that plays videos generated based on user responses. I want the ability to seamlessly switch between the currently displayed video and the next generated video without the HTML collapsing and rebuilding ...

Leveraging Iframes for efficient user authentication within an Angular application

Incorporating an Iframe into one of my templates for authentication has presented certain challenges. Case in point: When a user finishes a training session, they must verify their identity by authenticating with a ping identity server that will redirect ...

JavaScript is throwing an error because `csv[i]` has not

When I try to import a CSV file using JavaScript, the dataset imports successfully into my program. However, I keep encountering the error csv[i] not defined (line 57). I attempted to add var i = 0; just before that line, but the error persists. Any sugg ...