Kendo UI validator fails in grid (message doesn't disappear) - validation

I have to validate some data in kendoUI grid widget.
Seems there is a bug in validator component.
Steps to reproduce:
0. Open and run http://jsfiddle.net/Upw9j/2/
here's the code (some part is missing here due to SO limitations):
$(document).ready(function () {
var crudServiceBaseUrl = "http://demos.telerik.com/kendo-ui/service",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/Products",
dataType: "jsonp"
},
update: {
url: crudServiceBaseUrl + "/Products/Update",
dataType: "jsonp"
},
destroy: {
url: crudServiceBaseUrl + "/Products/Destroy",
dataType: "jsonp"
},
create: {
url: crudServiceBaseUrl + "/Products/Create",
dataType: "jsonp"
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) };
}
}
},
batch: true,
pageSize: 20,
schema: {
model: {
id: "ProductID",
fields: {
ProductID: { editable: false, nullable: true },
ProductName: {
validation: {
required: true,
productnamevalidation: function (input) {
if (input.is("[name='ProductName']") && input.val() != "") {
input.attr("data-productnamevalidation-msg", "/^\d{1,}$/");
return /^\d{1,}$/.test(input.val());
}
return true;
}
}
},
UnitPrice: { type: "number", validation: { required: true, min: 1} },
Discontinued: { type: "boolean" },
UnitsInStock: { type: "number", validation: { min: 0, required: true} }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 430,
toolbar: ["create"],
columns: [
"ProductName",
{ field: "UnitPrice", title: "Unit Price", format: "{0:c}", width: "100px" },
{ field: "UnitsInStock", title: "Units In Stock", width: "100px" },
{ field: "Discontinued", width: "100px" },
{ command: ["edit", "destroy"], title: " ", width: "172px"}],
editable: "inline"
});
});
Click Edit at any row
Set the cursor on ProductName field, input "2s" (without quotes), press Tab
The tooltip will appear, saying "/^d{1,}$/" (it's a RE, which is matched against field value)
Press Shift+Tab, input "2" (w/o quotes), press Tab, message will disappear.
Repeat steps 3-4 several times. After 2-3 iterations you'll find that message doesn't disappear when field contains valid value. "Update" button behaves correctly.
Is it really a bug or am I doing something wrong? How to work it around?

Yes, this is a bug. I don't know where the official bug tracking page is, but this is a forum thread that details more precisely what's happening: Kendo UI Error on Grid Custom Validation
Basically, when the custom validation fails the input, the datasource model is not updated. So when you re-enter the same (and correct input), it checks against the last correct value, and because it's the same, the validation doesn't fire. In your case, you can verify that if you change the numbers everytime, it still works (2s -> 2 -> 2s -> 3 -> 2s -> 4 etc... this works)
You can also reproduce the custom validation bug right on their demo page. Change Chai to chai to Chai again and the message will still show.
Telerik hasn't fixed it yet and I'm not sure of any easy fixes. You can try to update the data model yourself in the validator function, but this is potentially bad as it gives the user the ability to save bad input into your back end.
Personally (and unfortunately), I just avoided custom validation altogether and ended up using server side validation.

Related

How to get value id from dataSource by row Kendo UI Grid

Help me code How to get value id from dataSource by row and change to current value default (1)
in line: var date = dataSource.get(1);
console.log(date.ProductName)
My full source:
<div id="grid"></div>
<script>
$(document).ready(function () {
var crudServiceBaseUrl = "https://demos.telerik.com/kendo-ui/service",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/Products",
dataType: "jsonp"
},
update: {
url: crudServiceBaseUrl + "/Products/Update",
dataType: "jsonp"
},
destroy: {
url: crudServiceBaseUrl + "/Products/Destroy",
dataType: "jsonp"
},
create: {
url: crudServiceBaseUrl + "/Products/Create",
dataType: "jsonp"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true,
pageSize: 20,
schema: {
model: {
id: "ProductID",
fields: {
ProductID: { editable: false, nullable: true },
ProductName: { validation: { required: true } },
UnitPrice: { type: "number", validation: { required: true, min: 1} },
Discontinued: { type: "boolean" },
UnitsInStock: { type: "number", validation: { min: 0, required: true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
selectable: true,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
"ProductName",
{ field: "UnitPrice", title: "Unit Price", format: "{0:c}", width: "120px" },
{ field: "UnitsInStock", title:"Units In Stock", width: "120px" },
{ field: "Discontinued", width: "120px", editor: customBoolEditor },
{ command: ["edit", "destroy"], title: " ", width: "250px" }],
editable: "inline",
edit: function () {
var date = dataSource.get(1);
console.log(date.ProductName)
}
});
});
</script>
Now, when click edit, all rows only get fields of id 1. I want corresponding id instead of the default id 1.
edit
Fired when the user edits or creates a data item.
The event handler function context (available via the this keyword)
will be set to the widget instance.
EVENT DATA
e.container jQuery The jQuery object of the edit container
element, which wraps the editing UI. Depending on the Grid edit mode,
the container is different:
"incell" edit mode - the container element is a table cell
"inline" edit mode - the container is a table row
"popup" edit mode - the container is a Kendo UI Window element, which provides an easy way to obtain a reference to the Window widget object, e.g. to attach additional events.
e.model kendo.data.Model The data item which is
going to be edited. Use its isNew method to check if the data item is
new (created) or not (edited).
e.sender kendo.ui.Grid The widget instance which fired the event.
$("#grid").kendoGrid({
columns: [
{ field: "id" },
{ field: "name" },
{ field: "age" },
{ command: "edit" }
],
dataSource: {
data: [
{ id: 1, name: "Jane Doe", age: 30 },
{ id: 2, name: "John Doe", age: 33 }
],
schema: {
model: {
id: "id",
fields: {
"id": { type: "number" }
}
}
}
},
editable: "popup",
toolbar:["create"],
edit: function(e) {
console.log(e.model.id);
console.log(e.model.name);
}
});
Working example: edit event
Documentation: grid edit event

Kendo UI call custom service for delete

How can I call custom service for deleting a row in Kendo UI grid.This custon service should have a confirmation dialog option that can be customized.
Any thoughts on this is highly appreciative
You should customize the kendo.data.DataSource 'destroy' attribute to specify the URL and update the kendoGrid 'delete' command code for the custom confirmation.
Example code
$(document).ready(function () {
var windowTemplate = kendo.template($("#windowTemplate").html());
var crudServiceBaseUrl = "http://demos.kendoui.com/service",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/Products",
dataType: "jsonp"
},
update: {
url: crudServiceBaseUrl + "/Products/Update",
dataType: "jsonp"
},
destroy: {
url: crudServiceBaseUrl + "/Products/Destroy",
dataType: "jsonp"
},
create: {
url: crudServiceBaseUrl + "/Products/Create",
dataType: "jsonp"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true,
pageSize: 20,
schema: {
model: {
id: "ProductID",
fields: {
ProductID: { editable: false, nullable: true },
ProductName: { validation: { required: true } },
UnitPrice: { type: "number", validation: { required: true, min: 1} },
Discontinued: { type: "boolean" },
UnitsInStock: { type: "number", validation: { min: 0, required: true } }
}
}
}
});
var window = $("#window").kendoWindow({
title: "Are you sure you want to delete this record?",
visible: false, //the window will not appear before its .open method is called
width: "400px",
height: "200px",
}).data("kendoWindow");
var grid = $("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 430,
toolbar: ["create"],
columns: [
"ProductName",
{ field: "UnitPrice", title: "Unit Price", format: "{0:c}"},
{ field: "UnitsInStock", title:"Units In Stock"},
{ field: "Discontinued"},
{ command: [
{name: "edit"},
{name: "Delete",
click: function(e){ //add a click event listener on the delete button
var tr = $(e.target).closest("tr"); //get the row for deletion
var data = this.dataItem(tr); //get the row data so it can be referred later
window.content(windowTemplate(data)); //send the row data object to the template and render it
window.open().center();
$("#yesButton").click(function(){
grid.dataSource.remove(data) //prepare a "destroy" request
grid.dataSource.sync() //actually send the request (might be ommited if the autoSync option is enabled in the dataSource)
window.close();
})
$("#noButton").click(function(){
window.close();
})
}
}
]}],
editable: {
mode: "inline"
}
}).data("kendoGrid");
});
Taken from:
http://docs.telerik.com/kendo-ui/web/grid/how-to/Editing/custom-delete-confirmation-dialog
You can set the delete option in your datasource to a function and do anything you want from that point. Without a sample of your service, I can't help you getting started but I can link you to the documentation.

Get all updated and newly created models together in a single url in server side

I am Using Kendo grid with batch edit. I want to get all Modified and newly created models together in a single url.
Say I have created 3 new row and also updated/edited 2 existing row in grid. Data source makes a HTTP request for every CRUD operation . The changed data items are sent by default as models and hit URL as I declared in “create” and update (transport) section of transport in datasource.I am getting models those are Modified (updated) in URL declared for ‘update’ in server side. And also find models those are newly created in URL declared for ‘create’….But I want to get all Modified and newly created models together in a single url.Is it possible to get all of the (both all modified and newly created) in a single URL?
Here is my Code for better understand.
$("#grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "LoadPerMeterCostsGridData",
type: "POST",
contentType: "application/json",
dataType: "json"
},
update: {
url: "UpdatePerMeterCostsData",
contentType: "application/json",
type: "POST",
dataType: "json"
},
create: {
url: "CreatePerMeterCostsData",
contentType: "application/json",
type: "POST",
dataType: "json",
},
parameterMap: function (data, operation) {
if (operation != "read") {
return kendo.stringify(data.models);
}
}
},
serverPaging: false,
pageSize: 10,
batch: true,
schema: {
model: {
id: "PerMeterCostID",
fields: {
PerMeterCostID: { editable: false },
DrillBitSizeID: { editable: true },
Form: { editable: true },
To: { editable: true },
PerMeterCost: { editable: true },
ContractID: { editable: false }
}
},
errors: "Errors"
},
error: function (e) {
alert(e.errors + "grid");
}
},
editable: true,
pageable: {
refresh: true,
pageSizes: true
},
toolbar: ["create",
"save",
"cancel"
],
sortable: true,
autoBind: false,
columns:
[
{ field: "PerMeterCostID", width: 50, hidden: true, title: "ID" },
{ field: "DrillBitSizeID", width: 100, hidden: true, title: "Consumable" },
{ field: "Form", width: 100, title: " Form " },
{ field: "To", width: 50, title: "To" },
{ field: "PerMeterCost", width: 100, title: "Per Meter Cost" },
{ field: "ContractID", width: 100, hidden: true, title: "ContractID" },
{ command: ["destroy"], title: "Action", width: "175px" }
]
});
$("#grid ").data("kendoGrid").dataSource.read();
You can set each CRUD action to use the same url, but using the same url: property for both Create and Update. However you will still minimally get TWO requests (albeit to the same url)
update: {
url: "UpdateOrCreateAction",
},
create: {
url: "UpdateOrCreateAction",
},
this is because internally the dataSource pushes all "new" items as defined by "items an Id Field set to the default value for the field" in an array, and all items with dirty set to true into a different array. Kendo then sends both arrays back to the server according to the url for the action. (something like this i'd imagine)
if ( model.isNew())
createdPile.push(model)
else if ( model.dirty === true)
updatedPile.push(model)
//send both piles to the server
The "easiest" way to avoid this is to make sure your new objects explicitly set their id fields to something other then the default, and set the models dirty prob to true.
you could do this by using the edit event to override the actions
grid.bind('edit', function(e){
if ( e.model.isNew() ) {
e.model.id = -1; //
e.dirty = true;
console.log(e.model.isNew()) // should be false
}
})
this is probably an extreme amount of overkill to avoid one additional request, and prone to error. I would advise that you use the same url for both actions, and just accept that you will get the created items in one batch, and the updated in another.

Kendo Grid Will not populate with server side data

I cannot get Kendo Grid to populate from server side data.
I have a grid builder function as as follows:
var build = function (carrier, date) {
var urlBase = 'my base url';
var datasource = new kendo.data.DataSource({
pageSize: 20,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
model: {
id: 'Id',
fields: {
StatementDate: { type: "string", editable: false },
CobDate: { type: "string", editable: false },
//lots more fields
Status: { type: "string", editable: false },
Matched: { type: "boolean", editable: true }
}
}
},
transport: {
read: function (options) {
var address = urlBase + '/' + carrier + '/' + date;
$.ajax({
url: address,
type: "POST",
data: JSON.stringify(options.data),
contentType: "application/json",
success: function (result) {
options.success(result);
},
error: function (result) {
options.error(result);
}
});
},
//update function omitted
parameterMap: function (data, operation) {
if (operation == "read") {
return JSON.stringify(data)
}
},
change: function (e) {
var data = this.data();
console.log(data.length); // displays "77"
}
}
});
return datasource;
};
return {
build: build
}
Grid Definition
elem.kendoGrid({
columns: [
{ field: "StatementDate", title: "State Date", width: 125 },
{ field: "CobDate", title: "COB Date", width: 100 },
//lots more fields
{ command: ["edit"], title: " ", width: "85px"}],
resizable: true,
sortable: true,
editable: "inline",
columnMenu: true,
filterable: true,
reorderable: true,
pageable: true,
selectable: "multiple",
change: this.onSelectedRecordChanged,
toolbar: kendo.template($('#' + templateName).html()),
scrollable: {
virtual: true
},
height: 800
});
I trigger the update via a button click. When I look at the response I see the data. Looks good but the grid will not show the data. It has previously worked fine when data was completely client side.
If I break point on the AJAX call back. I see the correct results.
The grid is bound with data bind. The datasource is a property on a viewmodel.
<div id="grid" data-bind="source: dataSource"></div>
At the start of the app. I create view model
var viewModel= kendo.observable(new GridViewModel(...
and bind
kendo.bind($('#grid'), viewModel);
If I look at the datasource attached to the grid, I see data for the page as expected
This has previously worked fine when data was client side.
I have tried using read() on datasource, and refresh() method on grid. Neither seems to work.
Example response content from server
{"Data":[{"Id": //lots more fields, 20 records],"Total":90375,"AggregateResults":null,"Errors":null}
Any help very much appreciated.
I found the cause in datasource schema missing
{ data: 'Data', total: 'Total' }

Kendo UI DataSource not triggering transport.destroy

I am using Kendo UI with ASP.NET Web API. There is a ProjectsController that has all the necessary methods.
My issue is that when I click on Delete button, Kendo UI grid will raise remove() event, but DataSource never invokes transport.destroy. Rather, it seems that tansport.create is being invoked. In transport.parameterMap I can see that the operation is create instead of destroy.
Here is a sample JavaScript code:
$(document).ready(function () {
var apiUrl = '/api/projects/';
var dataType = 'json';
var dataSource = new kendo.data.DataSource({
batch: true,
autoSync: false,
transport: {
read: {
url: apiUrl,
dataType: dataType,
type: "GET"
},
update: {
url: apiUrl,
dataType: dataType,
type: "PUT"
},
destroy: {
url: apiUrl,
type: "DELETE"
},
create: {
url: apiUrl,
contentType: "application/json;charset=utf-8",
dataType: dataType,
type: "POST"
},
parameterMap: function (data, operation) {
console.log("Operation: " + operation);
if (operation === "create" && data.models) {
for (var i in data.models) {
var model = data.models[i];
if (model.ProjectId === 0) {
return kendo.stringify(model);
}
}
} else if (operation === "destroy") {
console.log("Data.Models: " + data.models);
console.log("Data.id: " + data.ProjectId);
return { id: data.ProjectId };
}
return data;
}
},
schema: {
id: "ProjectId",
model: {
fields: {
ProjectId: { type: "number", editable: false, nullable: false, defaultValue: 0 },
ProjectName: { type: "string", validation: { required: true } },
Status: { type: "string", validation: { required: true } },
IsActive: { type: "boolean" }
}
}
},
pageSize: 10,
serverPaging: false,
serverFiltering: false,
serverSorting: false
});
$("#projectsGrid").kendoGrid({
dataSource: dataSource,
groupable: false,
sortable: true,
pageable: {
refresh: true,
pageSizes: true
},
pageSize: 10,
toolbar: ["create"],
editable: "popup",
columns: [
{ field: "ProjectId", width: 30, title: "ID" },
{ field: "ProjectName", width: 180, title: "Project" },
{ field: "Status", width: 90, title: "Status" },
{ field: "IsActive", width: 40, title: "Is Active", type: "boolean", template: '<input type="checkbox" #if (IsActive) {# checked="checked" #}# disabled="disabled" />' },
{ command: ["edit", "destroy"], title: "&nbsp", width: "80px" }
],
remove: function (e) {
console.log("Delete button clicked.");
console.log("Project ID: " + e.model.ProjectId);
//dataSource.remove(e.model);
//dataSource.sync();
}
});
});
Web API works fine when requests are issued via Fiddler, but Kendo UI Grid shows:
POST http://localhost:port/api/Projects
when it should be DELETE.
Thanks everyone in advance!
On your datasource, you have the batch flag set to true, this means the datasource will make the call only after you tell it to, e.g calling sync().
http://docs.kendoui.com/api/framework/datasource#configuration-batch
As well as
Make sure you have defined Id in the model, as OnaBai explained here Why does the KendoUI Grid Transport Create event gets raised multiple times, and even when the action is Update? , your id is outside the model, should be in :
model: {
id: "ProductID",
fields: {
ProductID: { editable: false, nullable: true },
}
}
if someone has defined the id in model as answered in above ,but dataSource not triggering transport.destroy yet ,below configuration could be helpful:
editable: {
..
mode: "inline", //or "popup
...
}
//or
editable: "inline" //or "popup"
http://www.telerik.com/forums/transport-destroy-of-grid-editor-is-not-working

Resources