Question

I am looking to get some custom validation attribute in MVC 3 to fire only when I submit and not when the input loses focus.

Here is my custom validation attribute.

 #region Password Match Validation Attribute
    public sealed class PasswordPresent : ValidationAttribute, IClientValidatable
    {
        private const string _defaultErrorMessage = "Current Password no present";
        private string _basePropertyName;
        public PasswordPresent(string basePropertyName)
            : base(_defaultErrorMessage)
        {
            _basePropertyName = basePropertyName;
        }
        public override string FormatErrorMessage(string name)
        {
            return string.Format(_defaultErrorMessage, name, _basePropertyName);
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var basePropertyInfo = validationContext.ObjectType.GetProperty(_basePropertyName);
            var oldPassword =  (string)basePropertyInfo.GetValue(validationContext.ObjectInstance, null);
            var newPassword = (string)value;

            if (!string.IsNullOrEmpty(newPassword) && string.IsNullOrEmpty(oldPassword))
            {
                var message = FormatErrorMessage(validationContext.DisplayName);
                return new ValidationResult(message);
            }
            return null;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules
            (ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule();
            rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());

            //This string identifies which Javascript function to be executed to validate this 
            rule.ValidationType = "passwordpresent";
            rule.ValidationParameters.Add("otherfield", _basePropertyName);
            yield return rule;
        }
    }
    #endregion

Here is the .js file for clientside validation

jQuery.validator.addMethod("passwordmatch", function (value, element, param) {

    if (value == null || value.length == 0) {
        return true;
    }
    return value == $(param).val(); ;

});


jQuery.validator.unobtrusive.adapters.add("passwordmatch", ["otherfield"], function (options) {
    options.rules["passwordmatch"] = "#" + options.params.otherfield;
    options.messages["passwordmatch"] = options.message;
});

Here is my Model

public class UserSettingsModel
    {

        [Display(Name = "Old Password")]
        [PasswordPresent("NewPassword",ErrorMessage = "Please enter in a New Password")]
        public string CurrentPassword { get; set; }

        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "New password")]
        public string NewPassword { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm new password")]
        [PasswordsMatch("NewPassword",ErrorMessage = "Confirm password and New Password do not match")]
        public string ConfirmPassword { get; set; }

    }

And here is my View.

@model Data.Models.UserSettingsModel
   <div id="UserSettings">
 @using (Ajax.BeginForm("UpdateSettings", "AccountManagement", new AjaxOptions() {UpdateTargetId = "UserSettings", HttpMethod = "Post" }))
 {
        @Html.ValidationSummary(true)

        <div class="tabs" id="userTab3">
            <fieldset>
                <div>
                    <h3>
                        Change Password</h3>
                    <div class="editor-label">
                        @Html.LabelFor(model => model.CurrentPassword)
                    </div>
                    <div class="editor-field">
                        @Html.EditorFor(model => model.CurrentPassword)
                        @Html.ValidationMessageFor(model => model.CurrentPassword)
                    </div>

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

                <p>
                    <input type="submit" value="Save & Continue" name="btnsubmit" />
                </p>
            </fieldset>
        </div>
 }
 </div>
Was it helpful?

Solution

Assuming you're using the jQuery Validate plugin, you'll need to modify it to bind to only the submit button/form submission. Check this thread out:

jQuery validate rule ONLY AT SUBMIT

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