I'm currently building a grid that goes against the general way Progress mean to use their Grid but I'm hoping this is possible (I'm currently stumped).
The requirement is simple enough: show input field(s) in the client template of the grid across all rows. When clicking on a command button - ensure the input field(s) are valid before continuing.
Any which way I try the below instance, the kendo validator will not recognise either the data source schema's model field validation, OR any attributes on the input field(s) themselves.
Ultimately I want to get the pattern
/data-val-regex
HTML5/unobtrusive validation working.
Any help would be appreciated.
The Grid I have is coded as;
$(function() {
var Data = [];
jQuery("#grdData").kendoGrid({
"dataBound": grdData_Bound,
"editable": "inline",
"columns": [{
"title": "Id",
"field": "Id",
"template": "#=FieldValueEditor(data, \"HiddenField\", \"Id\", \"\")#",
"hidden": true
}, {
"title": "Name",
"field": "Name",
"template": "#=FieldValueEditor(data, \"TextField\", \"Name\", \".+\")#"
}, {
"title": "Description",
"field": "Description"
}, {
"title": "Requirements",
"field": "Requirements"
}, {
"title": "Icon",
"field": "Icon"
}, {
"title": "Type",
"field": "Type"
}, {
"title": "ActionText",
"field": "ActionText"
}, {
"title": "ActionWarning",
"field": "ActionWarning"
}, {
"title": "Timeout",
"field": "Timeout"
}, {
"title": "Retention",
"field": "Retention"
}, {
"title": "Active",
"field": "Active"
}, {
"title": "New Requirements",
"field": "NewRequirements",
"template": "#=FieldValueEditor(data, \"TextField\", \"NewRequirements\", \".+\")#"
}, {
"title": "",
"field": "Commands",
"command": [{
"text": "Save Requirements",
"name": "SaveRequirements",
"click": grdData_Command
}, {
"text": "Save Name",
"name": "SaveName",
"click": grdData_Command
}, ]
}, ],
"dataSource": {
"type": (function() {
if (kendo.data.transports['aspnetmvc-ajax']) {
return 'aspnetmvc-ajax';
} else {
throw new Error('The kendo.aspnetmvc.min.js script is not included.');
}
}
)(),
"transport": {
"read": {
"url": "/Action/View/1/62/Data",
"data": AntiForgeryToken
}
},
"pageSize": 4,
"schema": {
"data": "Data",
"total": "Total",
"errors": "Errors",
"model": {
"id": "Name",
"fields": {
"Id": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"Name": {
"type": "string",
"validation": {
"required": true,
"pattern": ".+"
}
},
"Description": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"Requirements": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"Icon": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"Type": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"ActionText": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"ActionWarning": {
"type": "string",
"validation": {
"required": true,
"pattern": ""
}
},
"Timeout": {
"type": "object",
"validation": {
"required": true,
"pattern": ""
}
},
"Retention": {
"type": "number",
"validation": {
"required": true,
"pattern": ""
}
},
"Active": {
"type": "boolean",
"validation": {
"required": true,
"pattern": ""
}
},
"NewRequirements": {
"type": "string",
"validation": {
"required": true,
"pattern": ".+"
}
},
"Commands": {
"type": "object",
"validation": {
"required": true,
"pattern": ""
}
},
}
}
}
}
});
});
With this Grid, for certain cells, it calls the FieldValueEditor
method to grab the Client Template;
function FieldValueEditor(data, fieldType, columnName, validationExpression) {
var wrapper = {
ColumnName: columnName,
ValidationExpression: validationExpression,
Data: data
};
var raw = $(`#${fieldType}-editor`).html();
var proxy = kendo.template(raw);
var html = proxy(wrapper);
return html;
}
This in turn, renders one of the following script templates depending on the field type;
<script type="text/html" id="HiddenField-editor">
<input type="hidden" class="hidden-field" data-bind="value:#:ColumnName#" />
</script>
<script type="text/html" id="TextField-editor">
<input type="text" class="text-field" data-bind="value:#:ColumnName#" />
</script>
<script type="text/html" id="DateField-editor">
<input type="date" class="date-field" data-bind="value:#:ColumnName#" />
</script>
<script type="text/html" id="CheckField-editor">
<input type="checkbox" class="check-field" data-bind="value:#:ColumnName#"/>
</script>
Additionally, I do have some dataBound
logic, ensuring the data item(s) are bound to each row;
function grdData_Bound(e) {
jQuery(".text-field").kendoTextBox({});
jQuery(".date-field").kendoDatePicker({});
$grid = $("#grdData");
var grid = $grid.data("kendoGrid");
$grid.find('tr.k-master-row').each(function() {
var $row = $(this);
$row.kendoValidator().data('kendoValidator');
var model = grid.dataItem($row);
kendo.bind($row, model);
});
$grid.focus();
}
When activating either of the two command buttons Save Name
or Save Requirements
, the validator from $row
returns true when calling validate
function grdData_Command(e) {
var $row = $(e.currentTarget).closest('.k-master-row');
var validator = $row.data('kendoValidator');
if (validator.validate()) {
//always goes in here, no matter how I setup the validation
} else {
//never goes in here
}
}
This was a stupid mistake on my part.
In short, I was unaware that the pattern
attribute does not get triggered by the kendoValidator.validate
method if the field is empty. When using an empty field it appears you must use required; which ultimately makes sense and gives you the option of having an optional but strict regular expression.
The fix was to pass in required/pattern pattern parameters to the client template like so -
<script type="text/html" id="TextField-editor">
<input type="text" class="text-field" data-bind="value:#:ColumnName#" #if(Required){# required#}##if(Pattern){# pattern="#=Pattern#" #}# validationMessage="Please enter a valid value" />
</script>
..and it simply works!