I am trying to implement a custom validator to require that a user enter a certain number of rows in my grid. I am applying the validation attribute to the IEnumerable<T> that provides the rows for my grid. The validation code gets called on the server side, but on the client side I don't see the data- properties anywhere in the page. Is it possible to run a client-side validator for the grid as a whole? If so, what do I need to do so that the client-side code is run? I'm guessing that because there is no direct reference from the grid to the property, that the client-side validation is not being wired up. Is there a way to work around this? Could I bind the grid directly to the property somehow instead of going through the .Read() AJAX method to get the data?
Here is my validation attribute:
Here is the JavaScript piece:
Here is my grid definition:
Any help would be appreciated.
Thanks,
Brian
Here is my validation attribute:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class RequiredCountAttribute : ValidationAttribute, IClientValidatable { public const int NotRequiredCount = -1; private int minCount; private int maxCount; public string MinErrorMessage { get; set; } public string MaxErrorMessage { get; set; } public RequiredCountAttribute(int minCount, int maxCount = NotRequiredCount) : base() { this.minCount = minCount; this.maxCount = maxCount; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { IEnumerable list = (IEnumerable)value; int count = 0; foreach (object o in list) count++; if (count < minCount) { string errorMessage = FormatErrorMessage(validationContext.DisplayName); return new ValidationResult(errorMessage); } if (maxCount != NotRequiredCount && count > maxCount) { string errorMessage = FormatErrorMessage(validationContext.DisplayName); return new ValidationResult(errorMessage); } } return ValidationResult.Success; } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule(); rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()); rule.ValidationType = "requiredcount"; rule.ValidationParameters.Add("mincount", minCount); if (maxCount != NotRequiredCount) rule.ValidationParameters.Add("maxcount", maxCount); yield return rule; } }Here is the JavaScript piece:
(function ($, kendo) { $.extend(true, kendo.ui.validator, { rules: { // custom rules requiredCount: function (input, params) { //check for the rule attribute if (input.filter("[data-val-requiredcount]").length && input.val()) { var minCount = $(input).attr('data-val-requiredcount-mincount'); var maxCount = $(input).attr('data-val-requiredcount-maxcount'); if (input.val() < minCount) return false; if (maxCount !== undefined && input.val() > maxCount) return false; } return true; } }, messages: { //custom rules messages requiredCount: function (input) { // return the message text return input.attr("data-val-requiredcount"); } } });})(jQuery, kendo);Here is my grid definition:
@(Html.Kendo().Grid<AccountManagement.Business.ViewModels.Areas.DM.RehireDocumentSettingViewModel>() .Name("DocumentSettings") .Columns(columns => { columns.Bound(ds => ds.Form) .ClientTemplate("#= data.Form.Description #" + "<input type='hidden' name='DocumentSettings[#= index(data)#].Form.FormID' value='#= data.Form.FormID #' />" ); columns.Bound(ds => ds.DocumentDateType) .ClientTemplate("#= DocumentDateType.Description #" + "<input type='hidden' name='DocumentSettings[#= index(data)#].DocumentDateType.RehireDocumentDateType' value='#= DocumentDateType.RehireDocumentDateType #' />" ); columns.Bound(ds => ds.RemoveIfOlderThanDays) .ClientTemplate("#= RemoveIfOlderThanDays #" + "<input type='hidden' name='DocumentSettings[#= index(data)#].RemoveIfOlderThanDays' value='#= RemoveIfOlderThanDays #' />" ); columns.Command(command => command.Destroy()); } ) .ToolBar(toolbar => { toolbar.Create().Text(AccountManagement.Resources.AccountManagementResources.AddRehireDocumentSettingButtonText); }) .Navigatable() .Sortable() .Scrollable() .Editable(editable => editable.Mode(GridEditMode.InCell)) .DataSource(dataSource => dataSource .Ajax() .Batch(true) .ServerOperation(false) .Events(events => events.Error("error_handler")) .Model(model => { model.Id(ds => ds.Form.FormID); model.Field(ds => ds.Form).DefaultValue( ViewData["defaultForm"] as AccountManagement.Business.ViewModels.Areas.DM.FormViewModel); model.Field(ds => ds.DocumentDateType).DefaultValue( new AccountManagement.Business.ViewModels.Areas.DM.RehireDocumentDateTypeViewModel() { RehireDocumentDateType = AccountManagement.Models.RehireDocumentDateType.DateTypeNotSpecified } ); } ) .Read("RehireDocumentSetting_Read", "RehireSetup") ) )Any help would be appreciated.
Thanks,
Brian