Hi,
Currently working on a grid project and cannot solve this particular bug.
Steps to recreate:
1. Create a new row by clicking on the create button
2. Delete a row by clicking on the delete button
3. Click on Create to create a new row and the JS console spits out: 'kendo.all.min.js:30 Uncaught TypeError: Cannot read property 'uid' of undefined'
- The create is blocked and the only way to create a new row after this is to refresh the browser.
The offending code block in the kendo source is:
cancelRow: function(){<br><span style="line-height: 1.5;">var e,t = this,<br>n=t._editContainer;<br>n&&(e = t._modelForContainer(n),<br>t._destroyEditable(),<br>t.dataSource.cancelChanges(e),<br>t._displayRow("popup"!==t._editMode()?n:t.tbody.find("["+pt.attr("uid")+"="+e.uid+"]")))},</span>My JS for this:
<p>$(document).ready(function () {<br><br> var MyKendoVar = MyKendoVar || {};<br><br> var projectDataSource = new kendo.data.DataSource(<br> {<br> transport: {<br> read:<br> function (options) {<br> apiService.projectsGet(function (result) {<br> options.success(result);<br> });<br> },<br><br> create: function (options) {<br> closeDialogue();<br> insertLoading();<br> apiService.projectsCreate(options.data, function (result) {<br> console.log(result.ProjectId + ", " + result.ProjectDescriptiveId);<br> options.success(result);<br> });<br><br> },<br><br> destroy: function (options) {<br> apiService.projectsDelete(options.data.ProjectId, function (result) {<br> options.success(result)<br> //window.location.reload(true);<br> });<br> },<br><br> update: function (options) {<br> closeDialogue();<br> insertLoading();<br> apiService.projectsUpdate(options.data.ProjectId, options.data, function (result) {<br> options.success(result);<br> });<br> },<br> },<br><br> sync: function (e) {<br> console.log("sync complete");<br> },<br><br> // schema configuration....<br> schema: {<br> errors: function (response) {<br> return response.myError;<br> },<br> model: {<br> id: "ProjectId",<br> fields: {<br> ProjectId: { type: "number", editable: false, nullable: true },<br> ProjectDescriptiveId: { type: "string", validation: { required: true, min: 4 } },<br> ProjectName: { type: "string", validation: { required: true, min: 4 } },<br> StartDate: { type: "date", validation: { required: true } },<br> StreetAddress: { type: "string", validation: { required: true, min: 4 } },<br> Suburb: { type: "string", validation: { required: true, min: 3 } },<br> State: { type: "string", validation: { required: true, min: 3 } },<br> Postcode: { type: "string", validation: { required: true, min: 4 } },<br> }<br> }<br> },<br><br> pageSize: 10,<br> sort: { field: "ProjectId", dir: "desc" }<br><br> });<br><br> $("#grid").kendoGrid({<br> dataSource: projectDataSource,<br> toolbar: [{ name: "create", text: "Create new project" }],<br> pageable: {<br> refresh: true<br> },<br> height: 650,<br> editable: {<br> mode: "popup",<br> template: kendo.template($("#updateTemplate").html())<br> },<br> columns: [<br> { field: 'ProjectName', title: 'Project Name' },<br> {<br> title: "Address",<br> template: "#= StreetAddress + ', ' + Suburb + ' ' + Postcode + ' ' + State #"<br> },<br> {<br> field: 'StartDate',<br> title: 'Start Date',<br> type: 'date',<br> format: '{0:dd-MM-yyyy}',<br> width: '110px'<br> },<br> { field: 'ProjectDescriptiveId', title: 'Project Code', width: '200px' },<br> {<br> command: [{ name: "edit" }, {<br> name: "Delete", text: "", click: function (e) { initalizeDeleteWindow(this.dataItem($(e.target).closest("tr"))); }<br> }], title: " ", width: "140px"<br> }],<br><br> /////////<br> edit: function () {<br> var $win = $('.k-window');<br><br> // set title<br> if (MyKendoVar.editorType === 'add') {<br> $win.find('.k-window-title').html("Create new project");<br> $win.find('.k-grid-update').html("Create");<br> }<br> else {<br> $win.find('.k-window-title').html("Update project details");<br> $win.find('.k-grid-update').html("Update");<br><br> }<br> },<br><br> dataBound: function () {<br> // add event listener to EDIT button<br> $('#grid > tbody > tr > td > a.k-button.k-button-icontext.k-grid-edit').on('click', function (evt) {<br> MyKendoVar.editorType = "edit";<br> });<br> $('body > section.section - container.top - margin > div > div.k - header.k - grid - toolbar > a').on('click', function (evt) {<br> MyKendoVar.editorType = "add";<br> })<br> }<br> })<br><br> $('#logout').on('click', function () {<br> $('#logoutForm').submit()<br> })<br><br> $('#modalCancel').on('click', closeModalAndOverlay);<br><br><br> function customModalShow() {<br> $('#modalOverlay, #customModal').show(200);<br> }<br><br> function overlayHide() {<br> $('#modalOverlay').hide(200);<br> }<br><br> function closeModalAndOverlay() {<br> $('#customModal, #modalOverlay').hide(200);<br> }<br><br> function closeModal() {<br> $('#customModal').hide(200);<br> }<br><br> function closeDialogue() {<br> $('.k-window').hide(200);<br> }<br><br> function initalizeDeleteWindow(dataItem) {<br> $('#modalTitlebarSpan').text("Delete project");<br> $('#contentParagraph').text("Do you really want to delete " + dataItem.ProjectName + "?");<br> $('#modalConfirm').text("Delete");<br> $('#modalConfirm').off();<br> $('#modalConfirm').on('click', function () { executeDelete(dataItem); });<br> customModalShow(); // show delete modal<br> }<br><br> function executeDelete(dataItem) {<br> console.log("doing remove()")<br> projectDataSource.remove(dataItem);<br> console.log("finishing remove and starting sync");<br> projectDataSource.sync();<br> console.log("finished sync");<br> closeModal();<br> insertLoading();<br> }<br><br> function insertLoading() {<br> $(".k-grid").prepend("<div class='k-loading-mask' style='width:100%;height:100%'><span class='k-loading-text'>Loading...</span><div class='k-loading-image'><div class='k-loading-color'></div></div></div>");<br> }<br>});</p><p>var apiService = {<br><br> settings: {<br> /// <field type="String" /><br> projectsEndpoint: settings.apiEndpoint + "projects"<br> },<br><br> projectsGet: function (successCallback) {<br> this.callApi(this.settings.projectsEndpoint, 'GET', null, null, successCallback);<br> },<br><br> projectsCreate: function (data, successCallback) {<br> this.callApi(this.settings.projectsEndpoint, 'POST', "application/json; charset=utf-8", data, successCallback);<br> $(".k-grid-update").addClass("k-state-disabled").removeClass("k-grid-update");<br> },<br><br> projectsDelete: function (projectId, successCallback) {<br> this.callApi(this.settings.projectsEndpoint + '/' + projectId, 'DELETE', "application/json; charset=utf-8", null, successCallback);<br> },<br><br> projectsUpdate: function (projectId, data, successCallback) {<br> this.callApi(this.settings.projectsEndpoint + '/' + projectId, 'PUT', "application/json; charset=utf-8", data, successCallback);<br> $(".k-grid-update").addClass("k-state-disabled").removeClass("k-grid-update");<br> },<br><br> callApi: function (path, method, contentType, data, successCallback, failureCallback) {<br> /// <param name="path" type="String" /><br> /// <param name="method" type="String" /><br> /// <param name="contentType" type="String" /><br> /// <param name="successCallback" type="Function" /><br> /// <param name="failureCallback" type="Function" /><br> $.ajax({<br> url: path,<br> type: method,<br> contentType: contentType,<br> data: JSON.stringify(data),<br> crossDomain: true,<br> beforeSend: function (request) {<br> request.setRequestHeader('Authorization', 'Bearer ' + settings.idToken);<br> },<br> success: function (result) {<br> successCallback(result);<br> $('#modalOverlay').hide(200);<br> $('.k-overlay').hide(200);<br> $(".k-loading-mask").remove();<br> $(".k-state-disabled").removeClass("k-state-disabled").addClass("k-grid-update");<br> },<br> error: function (request, status, error) {<br> if (request.status == 400) {<br> alert("There was a problem with your request: " + request.responseText);<br> }<br> else if (request.status == 401) {<br> alert("Looks like your login expired - Press Ok to go back to the login screen.");<br> window.location = '/';<br> }<br> else {<br> alert("Error: " + request.responseText)<br> }<br> $('#modalOverlay').hide(200);<br> $(".k-state-disabled").removeClass("k-state-disabled").addClass("k-grid-update");<br> $(".k-loading-mask").remove();<br> $('.k-overlay').hide(200);<br> }<br> });<br> }<br>};</p>var apiService = {
settings: {
/// <field type="String" />
projectsEndpoint: settings.apiEndpoint + "projects"
},
projectsGet: function (successCallback) {
this.callApi(this.settings.projectsEndpoint, 'GET', null, null, successCallback);
},
projectsCreate: function (data, successCallback) {
this.callApi(this.settings.projectsEndpoint, 'POST', "application/json; charset=utf-8", data, successCallback);
$(".k-grid-update").addClass("k-state-disabled").removeClass("k-grid-update");
},
projectsDelete: function (projectId, successCallback) {
this.callApi(this.settings.projectsEndpoint + '/' + projectId, 'DELETE', "application/json; charset=utf-8", null, successCallback);
},
projectsUpdate: function (projectId, data, successCallback) {
this.callApi(this.settings.projectsEndpoint + '/' + projectId, 'PUT', "application/json; charset=utf-8", data, successCallback);
$(".k-grid-update").addClass("k-state-disabled").removeClass("k-grid-update");
},
callApi: function (path, method, contentType, data, successCallback, failureCallback) {
/// <param name="path" type="String" />
/// <param name="method" type="String" />
/// <param name="contentType" type="String" />
/// <param name="successCallback" type="Function" />
/// <param name="failureCallback" type="Function" />
$.ajax({
url: path,
type: method,
contentType: contentType,
data: JSON.stringify(data),
crossDomain: true,
beforeSend: function (request) {
request.setRequestHeader('Authorization', 'Bearer ' + settings.idToken);
},
success: function (result) {
successCallback(result);
$('#modalOverlay').hide(200);
$('.k-overlay').hide(200);
$(".k-loading-mask").remove();
$(".k-state-disabled").removeClass("k-state-disabled").addClass("k-grid-update");
},
error: function (request, status, error) {
if (request.status == 400) {
alert("There was a problem with your request: " + request.responseText);
}
else if (request.status == 401) {
alert("Looks like your login expired - Press Ok to go back to the login screen.");
window.location = '/';
}
else {
alert("Error: " + request.responseText)
}
$('#modalOverlay').hide(200);
$(".k-state-disabled").removeClass("k-state-disabled").addClass("k-grid-update");
$(".k-loading-mask").remove();
$('.k-overlay').hide(200);
}
});
}
};
Any ideas would be appreciated.
@(Html.Kendo().Button() .Name("StartPracticeLinkButton") .Tag("a") .HtmlAttributes(new { href = Url.Action("Practice", "Practices", routeValues: new { id = Model.ID }) }) .Content("Start Now"))I am adding data to a spreadsheet using the following:
var spreadsheet = $scope.spreadsheet;spreadsheet.fromFile(newDataFile) .then(function () { // do something here });Is there a way to determine the number of rows prior to displaying the spreadsheet? The problem is that some users will want to upload ALL of their data, which may be several thousand rows. Others may only look at subsets. If I set the options.rows to a large number (say, 5000), there will usually be a huge number of extra rows. Even if I do that, there will eventually be some user with a spreadsheet that is 5001 rows, and row 5000 will be removed.
Thanks!

I have a scenario where the grid contains a small subset of the fields in a table. When I export to excel, I want to include the extra fields. But there are so many extra fields, and the export is used infrequently, that I don't want the overhead of always including them as hidden columns. What I'd like to do is construct the excel file on the server, and feed it back to the client. I have the grid set up to use the server proxy for the excel export as follows:
@(Html.Kendo().Grid<InstID2.Models.Institution>()
.Name("grdInstitutions")
.ClientDetailTemplateId("client-template")
.Pageable()
.Sortable()
.Filterable()
.ToolBar(t => t.Excel())
.Excel(excel => excel
.FileName("Kendo UI Grid Export.xlsx")
.Filterable(true)
.ProxyURL(Url.Action("Excel_Export_Save", "Default"))
.ForceProxy(true)
)
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Institution_Read", "Default"))
)
)
)
And I have the server proxy action as follows:
public ActionResult Excel_Export_Save(string contentType, string base64, string fileName)
{
var fileContents = Convert.FromBase64String(base64);
return File(fileContents, contentType, fileName);
}
So I have 2 questions:
1. To construct the excel file on the server, the server needs to know the current grid filters that are applied. Is there a way to pass the current filters in as a parameter to the ProxyURL? I've tried a few variations using a javascript function, but nothing has worked so far.
2. Since the server will be executing a query and constructing the excel file, the export data passed from the client (the "base64" parameter above) is not needed. Is there a way to make the client skip creating and sending the export data to the server? This is a minor issue as the parameter can simply be ignored. But it would improve performance if the client could skip that step since it is not needed.
Thanks,
Ray
Hi - I want to add counts on a grid, and am copying code I've used on another grid with no problems.
Here is my column definition for the field in question, it gives me an error that "count" is not defined.
{ field: "SchoolYear", title: "Assessment Year", aggregates: ["count"], footerTemplate: "Count: #=count#", groupFooterTemplate: "Count: #=count#", groupHeaderTemplate: " #=value# - Count: #=count#"},
If I remove the "#=count#", and have this it renders fine, just no count of course
{ field: "SchoolYear", title: "Assessment Year", aggregates: ["count"], footerTemplate: "Count: ", groupFooterTemplate: "Count: #=count#", groupHeaderTemplate: " #=value# - Count: #=count#"},
What I don't understand is why I can use "#=count#" in the groupFooter and groupHeader templates and it's fine.
Any ideas?
Thanks
Lisa
I want to ask the question about template for command button in TreeList. It seems it it ignored in case of TreeList, although it work fine in Grid (see attached picture).
columns: [ { field: "groupName", title: "Group", width: 100 }, { field: "vesselName", title: "Vessel", width: 100 }, { command: [ { name: "destroy", text: " ", template: "<a class='k-button k-grid-delete'><span class='glyphicon glyphicon-remove'></span></a>" } ], title: "Action", width: "15px" }],What I want to achieve by that template is just use another icon from bootstrap styles. Currently to achieve this (as workaround) I have to manipulate with DOM via jQuery, what of course not nice.
Does it not supported by design, or there is mistake in my code?
Hi
I'm just starting out integrating a few Kendo controls in my ASP.NET application. AT the moment I am just using the combobox and multiselect controls (and relevant datasource controls) with the Material theme. I have used the tool to create a custom minified js file and that works great. I had been hoping that there was a similar online tool to create the relevant CSS files. Please could you let me know if one exist, otherwise do I need to compile the less files myself?
Regards
Jon
I've been trying to add a Context Menu to a TreeView using this example.
The tree displays fine but the menu code generates an error: $(....).kendoContextMenu is not a function.
JS files included:
<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/bootstrap.min.js"></script>
<script src="/Scripts/kendo/kendo.all.min.js"></script>
<script src="/Scripts/kendo/kendo.aspnetmvc.min.js"></script>
TreeView and menu:
<ul id='tree'>
<li id="11">Item1
<ul>
<li id="1">Item1.1</li>
<li id="2">Item1.2 </li>
<li id="3">Item1.3 </li>
</ul>
</li>
<li id="4">Item2</li>
<li id="5">Item3</li>
</ul>
<ul id="menu">
<li>CREATE</li>
<li>DELETE</li>
</ul>
JS code:
$("#tree").kendoTreeView(
{
select: function(event) {
var $item = $(event.node);
var id = $item.attr('id');
}
});
$("#menu").kendoContextMenu({
// listen to right-clicks on treeview container
target: "#tree",
// show when node text is clicked
filter: ".k-in",
// handle item clicks
select: function(e) {
var button = $(e.item);
var node = $(e.target);
alert(kendo.format("'{0}' button clicked on '{1}' node", button.text(), node.text()));
}
});
Thanks,
Bill
Hi,
First off, new to a lot of this though I've made a lot of progress on my own. Unfortunately I'm maxed out with my limitations/lack of knowledge around several things. GREATLY appreciate some assistance.
Looking to create a Hierarchical Grid with CRUD functions (for both the parent and the child grid). Have not seen a demo/example anywhere or from anyone with a Hierarchy that has CRUD. That's the 1st half of the issue. 2nd half, I've been working on getting the CRUD functions (popup editing) to work in just a regular Grid but having trouble. Main trouble is I need to use not one, but two different Sharepoint lists (via REST) as the data source (one for the parent, one for the child). But even trying to just use one list for a standard grid, I cannot get the CRUD functions to work. Doing this all strictly through HTML/JS/CSS. No ASP.NET or C#. It's an internal sharepoint subsite.
The grid will populate from the list but the "Add New", "Edit", and "Delete" functions will not work correctly/save. Upon clicking "Add New Record" the popup opens and fill it out, but when I click "update" it does nothing and the window just remains opens. Screen shot is attached and posted code below. Greatly appreciate any assistance!
<title></title>
<link rel="stylesheet" href="https://home.hitachiconsulting.net/learning/PublishingImages/Dashboard/Kendo/kendo.common.min.css" />
<link rel="stylesheet" href="https://home.hitachiconsulting.net/learning/PublishingImages/Dashboard/Kendo/kendo.default.min.css" />
<script src="https://home.hitachiconsulting.net/learning/PublishingImages/Dashboard/Kendo/jquery.js"></script>
<script src="https://home.hitachiconsulting.net/learning/PublishingImages/Dashboard/Kendo/kendo.all.min.js"></script>
<div id="example">
<div id="grid"></div>
<script>
$(document).ready(function () {
var crudServiceBaseUrl = "https://home.hitachiconsulting.net/learning/curriculumdevelopers/_vti_bin/listdata.svc/EventsCourses",
dataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: {
url: crudServiceBaseUrl,
type: "GET",
dataType: "json",
contentType: "application/json;odata=verbose",
headers: {
"accept": "application/json;odata=verbose"
}
},
create: {
url: crudServiceBaseUrl,
type: "POST",
dataType: "json",
contentType: "application/json;odata=verbose",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
}
},
update: {
url: function (data) {
return crudServiceBaseUrl + "(" + data.ID + ")";
},
beforeSend: function (jqXhr, options) {
var data = JSON.parse(options.data);
jqXhr.setRequestHeader("If-Match", data.__metadata.etag);
},
type: "POST",
dataType: "json",
contentType: "application/json;odata=verbose",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"X-HTTP-Method": "MERGE"
},
},
destroy: {
url: function (data) {
return crudServiceBaseUrl + "(" + data.ID + ")";
},
type: "POST",
dataType: "json",
contentType: "application/json;odata=verbose",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"X-HTTP-Method": "MERGE",
"If-Match": "*"
}
},
parameterMap: function(data, type){
if (type === "update" && data["__deferred"]){
delete data["__deferred"];
}
return kendo.stringify(data);
}
},
batch: true,
pageSize: 10,
schema: {
data: "d.results",
model: {
id: "ID",
fields: {
ID: {editable: false, nullable: false },
Event: { type: "string", validation: { required: true } },
GlobalID: { type: "string" },
TrainingHours: { type: "number", validation: { required: true } },
Description: { type: "string", validation: {required: true } },
Objectives: { type: "string", validation: {required: true } },
DeliveryMethod: { type: "string", validation: { required: true } },
PrimarySubject: { type: "string", validation: { required: true } },
SecondarySubject: { type: "string", validation: { required: true } },
KeyWords: { type: "string", validation: { required: true } },
Curriculums: { type: "string", validation: { required: true } },
CourseDeveloper: { type: "string", validation: { required: true } },
SME: { type: "string", validation: { required: true } },
AddedToSensei: { type: "string", validation: { required: true } },
DateLastUpdated: { type: "string", validation: { required: true } },
Staus: { type: "string", validation: { required: true } },
SourceFiles: { type: "string", validation: { required: true } },
Notes: { type: "string", validation: {required: true } }
}
}
},
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 550,
toolbar: ["create" ],
columns: [
{ field: "Event", title: "Event Name" },
{ field: "GlobalID", title:"Event No./Global ID", width: "120px" },
{ field: "TrainingHours", title:"Training Hours", width: "120px" },
{ field: "Description", width: "120px" },
{ field: "Objectives" },
{ field: "DeliveryMethod", title: "Delivery Method" },
{ field: "PrimarySubject", title: "Primary Subject" },
{ field: "SecondarySubject", title: "Secondary Subject" },
{ field: "KeyWords", title: "Key Words" },
{ field: "CurriculumLibrary" },
{ field: "CourseDeveloper", title: "Curriculum Developer" },
{ field: "SME" },
{ field: "AddedToSensei", title: "Added to Sensei" },
{ field: "DateLastUpdated", title: "Date Last Updated" },
{ field: "Status" },
{ field: "SourceFiles", title: "Source Files" },
{ field: "Notes" },
{ command: ["edit", "destroy"], title: " ", width: "250px" }],
editable: {
mode:"popup",
update: true
}
});
});
dataSource.add( { Event: "New Event" });
datasource.sync() ;
</script>
</div>
var grid = $(ViewModel.gridName()).data("kendoGrid");//Reset all existing sorts/filters first. If the persisted view didn't have them set, the //existing state and persisted state are merged.grid.dataSource.sort({});grid.dataSource.filter({});grid.setOptions(JSON.parse(targetView.GridOptions()));
I'm using the setOptions method to restore the state previously obtained from grid.getOptions(). My data is small enough that I load it completely client side. When I call set options, the grid reloads the data from the server. It works fine, but it's unnecessary.
Is there an option to avoid reloading the data from the server after setOptions is called?
