Related
I'm having a problem finding a solution related to the Kendo Grid.
I am rendering a kendo dropdown list within a cell of a Kendo Grid. It appears to look fine and all, until the user focuses off or tabs off of the dropdown within the cell. The red hash shows that a change was made, but it's showing the data-value-field of the kendo DDL and not the text. Ok, I realize I can just use the same field from the DS in the dataTextField as I'm using in the dataValueField, but that won't work for me...because when I'm calling create or update, I need to be able to pass the primary key or ID of that selected item back into my web api controller.
Here is the grids DS
function loadContactGrid(vendorID) {
var contactsReadURL = null;
contactsReadURL = "/contacts/getcontacts/" + parseInt(vendorID);
contactGridDS = new kendo.data.DataSource({
transport: {
read: {
url: contactsReadURL,
type: 'GET',
contentType: "application/json; charset=utf-8",
},
update: {
url: "/contacts/UpdateContacts/",
type: 'PUT',
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function(xhRequest, ErrorText, thrownError) {
alert('ERROR!!!\n' + ' xhRequest: ' + xhRequest + '\n' + ' ErrorText: ' + ErrorText + '\n' + ' thrownError: ' + thrownError + '\n');
},
complete: function(e) {
$("#contactGrid").data("kendoGrid").dataSource.read();
}
},
destroy: {
url: "/contacts/DeleteContact/",
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "DELETE"
},
create: {
url: "/contacts/InsertContact/",
contentType: "application/json; charset=utf-8",
type: 'POST',
dataType: "json",
success: function(results) {
alert('Contacts successfully saved!');
},
error: function(xhRequest, ErrorText, thrownError) {
alert('ERROR!!!\n' + ' xhRequest: ' + xhRequest + '\n' + ' ErrorText: ' + ErrorText + '\n' + ' thrownError: ' + thrownError + '\n');
},
complete: function(e) {
$("#contactGrid").data("kendoGrid").dataSource.read();
}
},
parameterMap: function(options, operation) {
if (operation !== "read" && options) {
return JSON.stringify(options.models);
}
if (operation == "create") {
// send the created data items as the "models" service parameter encoded in JSON
return { models: kendo.stringify(data.models) };
}
}
},
batch: true,
scrollable: false,
pageSize: 8,
change: function(e) {
if (e.action == "itemchange" && e.field == "email") {
var model = e.items[0];
if (isEmailValid($('input[name=email]').val()) == false) {
e.items[0].receivereport = false;
}
}
if (e.action == "itemchange" && e.field == "contacttype") {
var model = e.items[0];
//setTimeout(function () {
//$('.k-dirty-cell').focusout(function() {
//alert($(this).text(textOverrideContactType(e.items[0].contacttype)));
//});
//textOverrideContactType(e.items[0].contacttype);
//}, 1000); attempting to change text in cell here failed
}
if (e.action === "remove") {
this.sync();
}
},
schema: {
model: {
id: 'contactid',
fields: {
roletyp_seq: { editable: false, nullable: false, required: true, type: 'string' },
contacttype: { editable: true, nullable: false, required: true, type: 'number' },
roletyp_pk: { editable: false, nullable: false, required: true, type: 'number' },
contactid: { editable: false, nullable: false, required: true, type: 'number' },
vendorid: { editable: false, nullable: false, required: true, type: 'number' },
prevrole_pk: {
editable: false,
nullable: true,
required: true,
type: "number",
}
}
}
},
});
And my grid
$("#contactGrid").kendoGrid({
dataSource: contactGridDS,
navigatable: true,
dataBound: mapContactTypes,
editable: true,
//editable: "inline",
//editable: "popup",
edit: function (input) {
if ($('input[name=receivereport]').is(':focus')) {
//detect if email is valid
//get input immediately before this one
if (isEmailValid($('input[name=receivereport]').parent().prev().text()) == false) {
// disable check box
// alert("invalid");
$('input[name=receivereport]').attr('disabled', 'true');
$('input[name=receivereport]').prop('checked', false);
} else {
// enable check box
// alert("valid");
$('input[name=receivereport]').removeAttr('disabled');
$('input[name=receivereport]').prop('checked', false);
}
}
//when user clicks into or out of a field, if the name in the respective row name is blank, alert the user
var grid = this;
var fieldName = grid.columns[input.container.index()].field;
if (isNameInContactGridPopulated(fieldName) == false) {
alert("You can't leave out a contact name in the row you are editing.");
//disable save button
$('.k-grid-save-changes').addClass('k-state-disabled');
$('.k-grid-save-changes').hide();
} else {
//do nothing
$('.k-grid-save-changes').removeClass('k-state-disabled');
$('.k-grid-save-changes').show();
}
if ($('input[name=contactname]').is(":focus") == true) {
//disable save button
if ($('input[name=contactname]').val() == '') {
$('.k-grid-save-changes').addClass('k-state-disabled');
$('.k-grid-save-changes').hide();
}
}
$('input[name=contactname]').keyup(function() {
if ($(this).val() == '') {
$('.k-grid-save-changes').addClass('k-state-disabled');
$('.k-grid-save-changes').hide();
}
});
$('input[name=contactname]').focusout(function () {
if ($(this).val() != '') {
$('.k-grid-save-changes').removeClass('k-state-disabled');
$('.k-grid-save-changes').show();
}
});
},
toolbar: ["save", "cancel"],
pageable: true,
columns: [
{ field: 'roletyp_seq', title: 'RT Seq.', hidden: true, attributes: { 'class': 'contactCell_roletyp_seq' } },
{ field: 'contacttype', title: 'Contact Type', hidden: false, attributes: { 'class': 'contactCell_contacttype' }, editor: loadContactTypeEditor, width: "200px", template: "#=textOverrideContactType(1)#" },
//{ field: 'contacttype', title: 'Contact Type', hidden: false, attributes: { 'class': 'contactCell_contacttype' }, editor: loadContactTypeEditor, width: "200px", template: "#=textOverrideContactType(contacttype)#" },
//{ field: 'contacttype', title: 'Contact Type', hidden: false, attributes: { 'class': 'contactCell_contacttype' }, editor: loadContactTypeEditor, width: "200px" },
{ field: 'prevrole_pk', title: 'prev role ID', hidden: true, attributes: { 'class': 'contactCell_prevrole_pk' } },
{ field: 'roletyp_pk', title: 'Role Type ID', hidden: true, attributes: { 'class': 'contactCell_roletyp_pk' } },
{ field: 'contactid', title: 'Contact ID', hidden: true, attributes: { 'class': 'contactCell_contactid' } },
{ field: 'vendorid', title: 'Vendor ID', hidden: true, attributes: { "class": 'contactCell_vendorid' } },
{ field: 'contactname', title: 'Name', hidden: false, attributes: { "class": 'contactCell_contactname' } },
{ field: 'workphone', title: 'Phone', hidden: false, attributes: { "class": 'contactCell_phone' } },
{ field: 'mobilephone', title: 'Cell', hidden: false, attributes: { "class": 'contactCell_mobilephone' } },
{ field: 'title', title: 'Title', hidden: false, attributes: { "class": 'contactCell_title' } },
{ field: 'email', title: 'Email', hidden: false, attributes: { "class": 'contactCell_email' } },
{ field: 'receivereport', title: 'Receive Reports?', hidden: false, attributes: { "class": 'contactCell_receivereport' }, template: '<input type="checkbox" #= receivereport ? "checked=checked" : "" # value="" disabled="disabled" ></input>' },
{ command: "destroy", title: " ", width: "100px" }
],
sortable: {
mode: 'single',
allowUnsort: false
}
});
Then, I have two functions below. 1 is the custom editor and the other is an attempt I considered to override the text displayed in the kendo ddl.
function loadContactTypeEditor(container, options) {
var contactTypeDS = new kendo.data.DataSource({
dataType: "json",
type: "GET",
transport: {
read: "/contacts/GetAllContactTypes/"
}
});
contactTypeDS.read();
$('<input class="contactTypeDropDown" required data-text-field="roletyp_dsc" data-value-field="roletyp_pk" data-bind="value:' + options.field + '"/>').appendTo(container).kendoDropDownList({
dataTextField: "roletyp_dsc",
dataValueField: "roletyp_pk",
autoBind: false,
select: function (e) {
//if (e.sender.text() != '') {
// $('#contactGrid_active_cell').html(e.sender.text());
//}
//if (e.sender.text() != '') {
// setTimeout(function() {
// $('.contactCell_contacttype').text(e.sender.text());
// }, 1000);
//}
//options.model[options.field] = e.sender.text();
},
//dataBound: function(){
// options.model[options.field] = e.sender.text();
//},
dataSource: contactTypeDS
});
}
function textOverrideContactType(roleId) {
//need to find a match on the passed in role/contact type ID and return it's match to "mask/overwrite" the text that's there after a user selects an item in the dropdown
$.ajax({
dataType: 'json',
type: 'GET',
url: "/contacts/GetAllContactTypes/",
contentType: 'application/json; charset=utf-8',
success: function (data) {
$.each(data, function (key, val) {
if (roleId == key) {
return val;
}
});
},
failure: function (error) {
alert("Error loading contact types.");
}
});
}
To summarize: I tried a few things with no avail. What is happening, is, the DDL renders just fine, and even when the user doesn't move off of that DDL, the proper "label" shows, but when that control loses focus, it shows the data-value-field. I can't have that, I need to be able to show the data-text-field. That's why I wrote that textoverride method. But I'm trying to call it within the grid, fields's template: and it's not working. It says it doesn't recognize that function. I don't get it; it's clearly declared. What am I supposed to pass in as the parameter, it's not exactly like the demo here...a bit different, as I'm populating the DDL with another remote data source.
http://demos.telerik.com/kendo-ui/grid/editing-custom
Here's the other thing; I need that data-value-field, ID, to persist and be passed into my web api controller when it gets called. Right now, as it stands, I'm only able to get the "text" to show in the controller and not the "ID." That ID will not be available to me in the read method. The stored procs that the CRUD is hitting is completely different. My stored proc for insert and update needs to get that contacttype ID as the number.
Thanks in advance. I'm sure I'm close...
From the provided information it seems that you need to make the column ForegnKey by setting the "values" option of the column. Please check the example below:
[demo] Grid: ForeignKey column
[documentation] Grid API: columns.values option
I actually ended up using another means to do this. The above still seems illusive to me. I ended up changing the values of a key in another row, that was already available, to get passed back into the controller. I tried the answers provided with no avail. Sorry!
I have Kendo UI inline Grid. It read and populate the grid properly. but when i press edit and changes in any column and press update then update event is not firing. and it also not calling controller method.
my view
$(document).ready(function () {
dataSource = new kendo.data.DataSource({
transport:
{
read:
{
url: "/Student/StudentGrid",
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "GET"
},
update:
{
url: "#Url.Action("EditStudentDetails")",
contentType: "application/json;charset=utf-8",
dataType: "json",
type: "POST"
},
parameterMap: function (options, operation) {
if (operation != "read" && options) {
if (operation != "destroy") {
return JSON.stringify({
studentViewModel: options
});
}
else if (operation == "destroy") {
return JSON.stringify({
id: options.Id
});
}
}
}
},
parse: function (test) {
if (test.success) {
if (test.type != "read") {
alert(test.message);
$("#grid").data("kendoGrid").dataSource.read();
}
return test.data;
}
else {
alert(test.message);
return [];
}
}
})
$("#grid").kendoGrid({
dataSource: dataSource,
filterable: true,
toolbar: ["create"],
sortable: true,
pageable: true,
columns: [
{
field: "Id",
width: 120,
visible: false
},
{
field: "Name",
title: "Student Name",
editor: AutocompleteName,
width: 180
},
{
field: "CourseName",
title: "Course Name",
editor: CourseDropDownEditor,
width: 200,
template: "#=CourseName#"
},
{
command: ["edit", "destroy"], title: " ", width: "250px"
}
],
editable: "inline"
});
What i did wrong in this and when i click on edit button it is changing to editable mode but when i click on update it is not working
Is any of your cell text has HTML tags like "<" or ">", remove them and click on update and check the update event fire.
I am new to Web API and Kendo UI. My requirement is InCell Editing. I have implemented this with below reference links. But my problem is In controller action method i am getting count of employee as 0. I am not any other things means edited rows.
http://demos.telerik.com/kendo-ui/grid/editing
http://demos.telerik.com/aspnet-mvc/grid/editing
and another way I tried with below reference. But here also in JQuery I am getting what I updated rows. but when passing data to controller through AJAX call in controller I am getting count as 0. Please can you help this.
http://stackoverflow.com/questions/17033025/kendo-grid-batch-editing-making-a-single-call-to-save
Here is my code:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/Employee/GetEmployee",
dataType: "json"
},
create: {
url: "/api/Employee/CreateEmployee",
dataType: "json",
type: "POST",
complete: function (jqXhr, textStatus) {
// Do something
}
},
update: {
url: "/api/Employee/Update",
dataType: "json",
type: "POST",
complete: function (jqXhr, textStatus) {
// Do something
}
},
destroy: {
url: "/api/Employee/DeleteEmployee",
dataType: "json",
type: "DELETE",
complete: function (jqXhr, textStatus) {
// Do something
}
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) };
}
}
},
batch: true,
pageSize: 12,
schema: {
model: {
id: "Id",
fields: {
Id: { editable: false, type: "number" },
EmployeeId: {
editable: true, type: "text", validation: {required: true },
},
EmployeeName: { validation: { required: true } }
}
}
}
});
if (container.find('#gridEmployee').data().kendoGrid)
container.find('#gridEmployee').data().kendoGrid.destroy();
container.find("#gridEmployee").kendoGrid({
dataSource: dataSource,
pageable: true,
// toolbar: [{ text: "Add new Employee", className: "btn btn-primary grid-add-new-record" }, { text: "Save", className: "btnKendoUiSave" }],
toolbar: ["create", "save", "cancel"],
columns: [
{
command: [
//define the commands here
{ name: "edit", text: " " }, { name: "destroy", text: " " }, { name: "update", text: " ", click: showDetails }], width: "200px"
},
{ field: "EmployeeId", title: "Employee Id", format: "{0:0}", headerAttributes: { "data-localize": "FIELD_NUMBER" } },
{ field: "EmployeeName", title: "Employee Name", headerAttributes: { "data-localize": "FIELD_NAME" } },
],
editable: true,
});
Web API Controller:
[HttpPost]
public System.Web.Mvc.JsonResult Update([System.Web.Mvc.Bind(Prefix = "models")]List<PlantEmployeeModel> Employees)
{
//
}
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: " ", 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
Main Problem
My current problem is the refresh progress when updating a grid datasource. I have change my code use the kendo.ui.progress in that way when requestStart event starts I ser the kendo.ui.progress to true. This activates the loading image when it end it calls the requestEnd.
The problem is that this event is hapenning for sorting and filtering. And I want it to only trigger for the read function of the dataSource. This problem makes the grid to use the progress endlessly.
Is there some way to filter in the requestStart and requestEnd only activate on the transport read?
My DataSource Code
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: url_Obtener_Periodo,
type: "POST"
},
parameterMap: function (options, operation) {
if (operation == "read" && options) {
return {
"periodo.Year": $("#periodo-anio").val(),
"periodo.Month": $("#periodo-mes").val(),
"Filtro": $("#Filtro").val()
};
}
}
},
requestStart: function (e) {
kendo.ui.progress($("#grid-container"), true);
},
requestEnd: function (e) {
kendo.ui.progress($("#grid-container"), false);
},
schema:{
model: {
id: "Codigo_De_Pedido",
fields: {
Codigo_De_Pedido: { type: "number" },
Fecha_Y_Hora_De_Creacion: { type: "date" },
UserName: { type: "string" },
Nombre_Del_Usuario: { type: "string" },
Codigo_Del_Vendedor: { type: "number" },
Nombre_Del_Vendedor: { type: "string" },
Is_Pedido_Closed: { type: "bool" },
Estado: { type: "string" }
}
}
},
pageSize: 10
});
The changes I did to solve the progress endlessly problem where 2.
Removing requestEnd function from the dataSource
Adding dataBound function to the Grid
Data Source Code
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: url_Obtener_Periodo,
type: "POST"
},
parameterMap: function (options, operation) {
if (operation == "read" && options) {
return {
"periodo.Year": $("#periodo-anio").val(),
"periodo.Month": $("#periodo-mes").val(),
"Filtro": $("#Filtro").val()
};
}
}
},
schema:{
model: {
id: "Codigo_De_Pedido",
fields: {
Codigo_De_Pedido: { type: "number" },
Fecha_Y_Hora_De_Creacion: { type: "date" },
UserName: { type: "string" },
Nombre_Del_Usuario: { type: "string" },
Codigo_Del_Vendedor: { type: "number" },
Nombre_Del_Vendedor: { type: "string" },
Is_Pedido_Closed: { type: "bool" },
Estado: { type: "string" }
}
}
},
pageSize: 10,
requestStart: function (e) {
kendo.ui.progress($("#grid-container"), true);
}
});
Kendo Grid Code
kendoGrid = $("#selectable-pedidos").kendoGrid({
dataSource: dataSource,
pageable: true,
sortable: true,
filterable: {
extra: false,
operators: {
string: {
startswith: "Comienza Con",
eq: "Es Igual A",
neq: "No Es Igual A"
}
}
},
dataBound: function (e) {
kendo.ui.progress($("#grid-container"), false);
},
columns: [
{ field: "Fecha_Y_Hora_De_Creacion", title: "Fecha y Hora", template: "#= kendo.toString(Fecha_Y_Hora_De_Creacion, 'dd/MM/yyyy hh:mm:ss tt') #" },
{ field: "Codigo_De_Pedido", title: "Código de Pedido" },
{ field: "Estado", filterable: true, title: "Estado" },
{ field: "Codigo_Del_Vendedor", title: "Código de Vendedor" },
{ field: "Nombre_Del_Vendedor", title: "Nombre de Vendedor" },
{
command: {
text: "Ver Detalle de Pedido",
click: function (e) {
$("#empty").append("<form method='POST' action='/HojaDeRuta/GetById/'><input type='hidden' name='Codigo_Pedido' value='"
+ this.dataItem($(e.currentTarget).closest("tr")).Codigo_De_Pedido + "' /><input type='submit' /></form>");
$("#empty input[type='submit']").click();
}
},
title: " "
}
]
}).data("kendoGrid");
There are a few things about your questions worth mentioning for those who read this:
Is there some way to filter in the requestStart and requestEnd only
activate on the transport read?
Yes, but it will not help you. The parameter of the event has a type property that will contain read, update, destroy or create.
statementEntriesDS.bind("requestStart", function (e) {
switch (e.type) {
case "create":
alert('-> event, type "create".');
break;
case "read":
alert('-> event, type "read".');
break;
case "update":
alert('-> event, type "update".');
break;
case "destroy":
alert('-> event, type "destroy".');
break;
}
});
Your example code doesn't specify serverFiltering or serverSorting so sorting and filtering wouldn't cause an remote action. You'll only get client-side sorting and filtering. However, if they are specified they're all going to result in a read and that wouldn't really help you.
That you would not have the requestEnd event fire sounds odd. You should probably add a handler for the error event and see if something is failing.
If you really want complete control over what's happening, you can specify a function for your read:
transport: {
read: function (options) {
kendo.ui.progress($gridContainer, true);
$.ajax({
url: carrierServiceBaseUrl + "/GetManualStatementsCarrierList",
contentType: 'application/json; charset=utf-8',
dataType: "json",
type: "POST",
success: function (result) {
// notify the data source that the request succeeded
options.success(result);
kendo.ui.progress($gridContainer, false); },
error: function (result) {
options.error(result); // Call the DataSource's "error" method with the results
kendo.ui.progress($gridContainer, false);
notification.show({
title: "ERROR:",
message: result.statusText
}, "error");
}
});
}
}