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