This is a migrated thread and some comments may be shown as answers.

Whole-Grid Client-Side Validation

1 Answer 69 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Brian
Top achievements
Rank 1
Brian asked on 20 Feb 2014, 03:19 PM
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:
[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

1 Answer, 1 is accepted

Sort by
0
Accepted
Petur Subev
Telerik team
answered on 24 Feb 2014, 01:36 PM
Hello Brian,

Validation can only occur on input elements and editor widget, since when the Grid is in display mode there are not any input elements there wont be any validation. There is also not any work-around that could make the validation work this way.
Regarding the DataSource.Read() question - If I understand you correctly you want to bind the Grid without performing separate request? If so then you should initally fill the Grid like demonstrated here:

Html.Kendo().Grid(Model)
 
or
 
Html.Kendo().Grid<TheModelType>()
.BindTo(Model)


Kind Regards,
Petur Subev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Tags
Grid
Asked by
Brian
Top achievements
Rank 1
Answers by
Petur Subev
Telerik team
Share this question
or