I've set up my kendo ui grid to read data from an MVC action that returns JSON. I'm using the free version of Kendo and not the MVC specific, due to cost.
The issue is that when the page loads and does the initial population of the grid it doesn't show the loading spinner. After grid is populated and I go to another page or sort a column it shows up.
If I set the height parameter of the grid, I get the initial spinner but the grid only shows one row (should have shown 20).
Does anyone know why you have to set the height parameter? Or any way of getting the spinner to work without setting the height.
My kendo javascript kode:
$("#grid").kendoGrid({
dataSource: new kendo.data.DataSource({
transport: {
read: url,
parameterMap: function (options) {
var result = {
pageSize: options.pageSize,
skip: options.skip,
take: options.take,
page: options.page,
};
if (options.sort) {
for (var i = 0; i < options.sort.length; i++) {
result["sort[" + i + "].field"] = options.sort[i].field;
result["sort[" + i + "].dir"] = options.sort[i].dir;
}
}
return result;
}
},
requestStart: function () {
//kendo.ui.progress($("#loading"), true); <-- this works on initial load, but gives two spinners on every page or sort change
},
requestEnd: function () {
//kendo.ui.progress($("#loading"), false);
},
pageSize: 20,
serverPaging: true,
serverSorting: true,
schema: {
total: "total",
data: "data"
},
}),
height: "100%", <-- I want to avoid this as it renders the grid way to small
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
columns: [
{
field: "PaymentRefId",
title: "Id"
},
{
field: "DueDate",
title: "Due Date"
},
{
field: "Credit",
title: "Amount"
},
{
field: "InvoiceGroupId",
title: " ",
sortable: false,
template: 'See details'
}
],
});
I had this same issue. It actually is rendering the spinner / progress bar, but because the grid content area initially has no height, you can't see it. This worked for me. Give it a shot:
// This forces the grids to have just al little height before the initial data is loaded.
// Without this the loading progress bar / spinner won't be shown.
.k-grid-content {
min-height: 200px;
}
The solution var to use a variable to tell me if the dataset load was the initial one or not. It's not a perfect solution, but it's the only one I've been able to make work.
var initialLoad = true;
$("#grid").kendoGrid({
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
columns: [
{
field: "PaymentRefId",
title: "Id"
},
{
field: "DueDate",
title: "Due Date"
},
{
field: "Credit",
title: "Amount"
},
{
field: "InvoiceGroupId",
title: " ",
sortable: false,
template: 'See details'
}
],
});
var ds = new kendo.data.DataSource({
transport: {
read: url,
parameterMap: function (options) {
var result = {
pageSize: options.pageSize,
skip: options.skip,
take: options.take,
page: options.page,
};
if (options.sort) {
for (var i = 0; i < options.sort.length; i++) {
result["sort[" + i + "].field"] = options.sort[i].field;
result["sort[" + i + "].dir"] = options.sort[i].dir;
}
}
return result;
}
},
requestStart: function () {
if (initialLoad) <-- if it's the initial load, manually start the spinner
kendo.ui.progress($("#invoiceGroupGrid"), true);
},
requestEnd: function () {
if(initialLoad)
kendo.ui.progress($("#invoiceGroupGrid"), false);
initialLoad = false; <-- make sure the spinner doesn't fire again (that would produce two spinners instead of one)
},
pageSize: 20,
serverPaging: true,
serverSorting: true,
schema: {
total: "total",
data: "data"
},
});
Chances are, because you are creating and setting the datasource in the grid's initialization, the grid loads so fast that you don't see a load spinner. If you look at all the web demos for kendogrid on their website, you rarely see the initial load spinner. On large remote datasources that take longer to load, you would see it.
If I set the height parameter of the grid, I get the initial spinner but the grid only shows one row (should have shown 20)
It's not that it only shows one row. It's because it failed to read it your height property value so it defaulted to as small as possible. Height takes in a numeric pixel value and does not accept percentages. It couldn't read your value, so it probably took longer to initialize the grid, which allowed you to see the load spinner. Instead, height should be set like height: 400, for example. But this is besides the point.
If you really want the user to see a load spinner on start, try loading the datasource outside of the grid initialization. Basically, load the grid first, and load the datasource after so that there is slightly more delay between the grid rendering and datasource setting.
$("#grid").kendoGrid({
//kendoGrid details... but exclude dataSource
});
var ds = new kendo.data.DataSource({
//DataSource details...
});
And then set the datasource like this:
var grid = $("#grid").data("kendoGrid");
grid.setDataSource(ds);
grid.refresh();
However, I think this would still load pretty fast.
Another last resort if you still really want the spinner is to trick the user into thinking it's taking longer to load and manually call the load spinner like you've tried. Call kendo.ui.progress($("#loading"), true);, execute a small delay function for say 250ms and then turn the load spinner off, and then call grid.setDataSource(ds); and refresh.
Related
I am having trouble making a select required in ExtJS.
I tried with allowBlank: false, even afterredner methods but nothing works, I can submit the form with no value in that select.
The code to generate the field is as follows:
OldType: function () {
return {
xtype: 'xEasyGridCombo',
allowBlank: false,
required: true,
valueField: 'fe_code',
displayField: 'fe_name',
dropPanelConfig: {
width: 480,
height: 200
},
searchFieldList: ['fe_code', 'fe_name'],
gridConfig: {
table: 'type_store',
idColumn: 'fe_id',
hasBottomBar: true,
rowLimit: 40,
tools: [],
conditions: [],
forceColumns: ['fe_code', 'fe_name'],
forceSelectFieldsQuery: ' DISTINCT fe_code, CONCAT(fe_name, \'[\', fe_code, \']\') fe_name ',
xColumns: [],
storeBaseParams: {}
},
listeners: {
afterrender: function () {
let oGrid,
sDivision = this.findParentByType('panel').find('KeyNr1', 'Divsion')[0].getValue();
// making sure the grid is rendered
this.getGridList();
oGrid = this.gridList.findByType('uxgrid')[0];
oGrid.store.baseParams.filter = Ext.util.JSON.encode([{
"field": "fe_tip",
"value": (sDivision === '02') ? 'F-GAZ' : 'F-ELEC'
}]);
//store from server try
oGrid.store.reload();
}
}
};
},
What am I doing wrong ? I can't even make it have a default value.
Thanks in advance and happy Holidays !
In the modern toolkit, the formpanel has a beforesubmit event. you can check if the value is selected or not. If you return a false from this event the form will not be submitted.
in the classic toolkit the event is beforeaction.
For some reason I need to define a hidden column when using KendoUI grid:
var fields = {
ID: { type: "string", editable: true, nullable: false },
HideID : { type: "string", editable: false, nullable: false ,hidden: true },
Name: { type: "string", editable: true, nullable: false }
};
var ColumnsDefine = [
{ field: "ID", title: "ID", width: 100 },
{ field: "HideID", hidden: true },
{ field: "Name", title: "Name", width: 100 }
];
I change the HideID column value using JavaScript (operate the dataItem) without editing the grid's record.
And the JavaScript code to change the hidden field is like below (it's inside a command-click function)
var tr = $(e.target).closest("tr");
var data = this.dataItem(tr);
data.HideID = "123";
Now the problem is when I click the default update button, the background update method is not being called because I didn't make changes to any visible column. But if I modify any visible columns and click update, both the HideID and another field will be updated successfully in the background.
What should I do to notify the KendoUI grid that its data has been changed and fire the update method by clicking the update button?
Your grid dataItem will be a kendo.data.ObservableObject; you need to set your HideID property in such a way that the kendo framework sees the change, using it's set() method:
var tr = $(e.target).closest("tr");
var data = this.dataItem(tr);
data.set("HideID","123");
Once you've done that, you should find that it's dirty field is set to true. That signals to the datasource that this object has changes which need to be saved via the update method.
See also this article which gives a good explanation of how the observableObject can be used for binding https://docs.telerik.com/kendo-ui/framework/mvvm/observableobject#set-field-values
Hope this helps!
Following is a kendo grid sample with detailInit:
My requirement is that on sorting a column in a particular sub-grid(detailInit), its header i.e. FirstName field should be changed like shown below:
Just that particular sub-grid's header should be changed. I have tried by registering onclick event in databound function of detailInit but unable to find the column header and change it :
$("th[role='columnheader']").on("click", function (ev) {
// access clicked column in sub- grid
// change master row's title
};
Please someone suggest me a solution as I am new to kendo grid, js, HTML, so not aware of many functions.
Any help would be much appreciated.
Please find my code below :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.common.min.css" />
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.rtl.min.css" />
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.silver.min.css" />
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.mobile.all.min.css" />
<script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.3.1028/js/kendo.all.min.js"></script>
</head>
<body>
<div id="grid"></div>
<script>
var element = $("#grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Employees"
},
pageSize: 6,
serverPaging: true,
serverSorting: true
},
height: 450,
sortable: true,
pageable: true,
detailInit: detailInit,
dataBound: function () {
this.expandRow(this.tbody.find("tr.k-master-row").first());
},
columns: [
{
field: "FirstName",
title: " "
}
]
}).on("click", ".btn-refresh", function (e) {
debugger;
var childGrid = $(e.target).closest(".k-grid").data("kendoGrid");
childGrid.dataSource.read();
});
function detailInit(e) {
$("<div/>").appendTo(e.detailCell).kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Orders"
},
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize: 6,
filter: { field: "EmployeeID", operator: "eq", value: e.data.EmployeeID }
},
scrollable: false,
sortable: true,
pageable: true,
toolbar: [{ text: "Refresh", className: "btn-refresh" }],
columns: [
{ field: "OrderID", width: 70 },
{ field: "ShipCountry", title: "Ship Country", width: 100 },
{ field: "ShipAddress", title: "Ship Address" },
{
field: "ShipName", title: "Ship Name", width: 200
}
]
});
}
</script>
</body>
</html>
There are, at least, two main ways to do this. However, I didn't understand if you want to:
a) Clear all the "updated" texts, letting only the last clicked with it
b) Keep all them tracked, putting the text as the user sorts the grids
Anyway, let's see both strategies.
Using jQuery only
a)
element.on('click', "th[role='columnheader']", function(e) {
// always remove all, to put again in the right place
$("strong[attr-id=updated]").remove();
var firstNameCell = $(this)
.closest("tr.k-detail-row") // Finds the closest detail row ...
.prev("tr.k-master-row") // ... in order to get the first previous row of class "k-master-row" (which stores the FirstName)
.find("td[role='gridcell']"); // and, then, get the td gridcell
firstNameCell.append("<strong attr-id='updated'> - Address updated</strong>");
});
b)
element.on('click', "th[role='columnheader']", function(e) {
var firstNameCell = $(this)
.closest("tr.k-detail-row")
.prev("tr.k-master-row")
.find("td[role='gridcell']");
// Check if the msg already exits, to not duplicate it
if (!(firstNameCell).find('strong[attr-id=updated]').length) {
firstNameCell.append("<strong attr-id='updated'> - Address updated</strong>");
}
});
The attr-id helps to identify the text element along the page, once it's not a good practice using id (only once per page).
Using KendoUI JavaScript objects
That's not the best way, since you cannot append HTML like we did with jQuery approach. Also, you'll have to refresh the whole table every time a sort is made.
That's why I'll show only case b)
element.on('click', "th[role='columnheader']", function(e) {
var masterRow = $(this)
.closest("tr.k-detail-row")
.prev("tr.k-master-row"); // Finds the closest master row ...
var rowIndex = $("tr.k-master-row").index(masterRow); // ... gets the index of it among all the others
kendoGrid = element.data('kendoGrid');
var firstName = kendoGrid.dataSource._data[rowIndex].FirstName; // gets current name based on the index
if (!firstName.includes('Address updated')) {
selectedCell = rowIndex; // sets the index to be used when grid refreshes
kendoGrid.dataSource._data[rowIndex].FirstName = firstName + " - Address updated";
kendoGrid.refresh(); // refreshed the whole grid
}
});
Still, in order to make KendoUI to expand the right row every time its grids are refreshed, you have to create the global variable selectedCell and check at dataBound function whether it has a value or not:
dataBound: function () {
if (selectedCell) {
this.expandRow(this.tbody.find("tr.k-master-row:eq(" + selectedCell + ")"));
} else {
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
},
Here, you can see more about Kendo Grid refreshing: Reloading/refreshing Kendo Grid
Hope it helps! :)
I have a function that creates a kendo grid which has the button to download it as a ".xlsx" file.
There is a dropdown that when is changed, calls this function again.
function CreateGrid(result) {
var chartSeries = result.ChartData;
var gName = $("#dropdown1 option:selected").text();
// Create Grid
$("#grid1").kendoGrid({
toolbar: ["excel"],
excel: {
fileName: "Grid1_"+gName+".xlsx",
filterable: true,
allPages: true
},
columns: [
{ field: "column1", width: "90px", title: "<strong>Item1</strong>" },
{ field: "column2", width: "80px", title: "<strong>Item2</strong>" },
{ field: "column3", width: "120px", title: "<strong>Item3</strong>", format: "{0:c2}" }
],
groupable: false,
resizable: true,
pageable: false,
scrollable: true,
filterable: false,
sortable: true,
pageSize: 50
});
// Set Grid data source
$("#grid1").data("kendoGrid").setDataSource(
new kendo.data.DataSource({
//Set the data of the grid as the result array of object.
data: result.ChartData
})
);
}
The problem is, when i click in the button to download the file, it downloads every grid previously made when I want only the current one.
For example, i created the grid once, then i changed the dropdown and the grid changed to the values corresponding to the new dropdown value, but when I click in the button, it downloads 2 files, from the first grid made and the one showing.
If I change the dropdown again, then the values will change according to the dropdown value but if I click to download the file,it downloads the previous 2 files + the one in the grid.
It seems that even thought i cant see the previous grids anymore, they are still there so I want to know how can I destroy/erase/clean them.
I would suggest you to remove the grid before creating a new one. This function would delete it and also would return you the current data in the grid, if you want to re-assign it:
function removeGrid(g) {
var tmp = [];
try {
tmp = g.data("kendoGrid").dataSource.data();
} catch (e) { }
var container = g.parent();
g.remove();
container.append("<div id='" + g.attr("id") + "' class='" + g.attr("class") + "'></div>");
return tmp;
}
Then you could call it like this:
var gName = $("#dropdown1 option:selected").text();
removeGrid($("#grid1"));
// Create Grid
$("#grid1").kendoGrid({
...
}
i have a kendoui grid which list claims. one of the columns is lenders which is a foreign key reference to the lenders table. what i want is to be able to display the lender name in the grid instead of its id reference.
ive setup the lenders datasource as follows
var dsLenders = new kendo.data.DataSource({
transport: {
read: {
url: "../data/lenders/",
dataType: "jsonp"
},
parameterMap: function(options, operation) {
if (operation === "read") {
return options;
}
}
}
});
and the grid looks like this
$("#gridClaims").kendoGrid({
dataSource: claimData,
autoSync:true,
batch: true,
pageable: {
refresh: true,
pageSizes: true
},
filterable: true,
sortable: true,
selectable: "true",
editable: {
mode: "popup",
confirmation: "Are you sure you want to delete this record?",
template: $("#claimFormPopup").html()
},
navigable: true, // enables keyboard navigation in the grid
toolbar: ["create"], // adds insert buttons
columns: [
{ field:"id_clm", title:"Ref", width: "80px;" },
{ field:"status_clm", title:"Status", width: "80px;" },
{ field:"idldr_clm", title:"Lender", values: dsLenders },
{ field:"type_clm", title:"Claim Type"},
{ field:"value_clm", title:"Value", width: "80px;", format:"{0:c2}", attributes:{style:"text-align:right;"}},
{ field:"created", title:"Created", width: "80px;", format: "{0:dd/MM/yyyy}"},
{ field:"updated", title:"Updated", width: "80px;", format: "{0:dd/MM/yyyy}"},
{ field:"user", title:"User" , width: "100px;"},
{ command: [
{text: "Details", className: "claim-details"},
"destroy"
],
title: " ",
width: "160px"
}
]
});
however its still displaying the id in the lenders column. Ive tried creating a local datasource and that works fine so i now is something to do with me using a remote datasource.
any help would be great
thanks
Short answer is that you can't. Not directly anyway. See here and here.
You can (as the response in the above linked post mentions) pre-load the data into a var, which can then be used as data for the column definition.
I use something like this:-
function getLookupData(type, callback) {
return $.ajax({
dataType: 'json',
url: '/lookup/' + type,
success: function (data) {
callback(data);
}
});
}
Which I then use like this:-
var countryLookupData;
getLookupData('country', function (data) { countryLookupData = data; });
I use it in a JQuery deferred to ensure that all my lookups are loaded before I bind to the grid:-
$.when(
getLookupData('country', function (data) { countryLookupData = data; }),
getLookupData('state', function (data) { stateLookupData = data; }),
getLookupData('company', function (data) { companyLookupData = data; })
)
.then(function () {
bindGrid();
}).fail(function () {
alert('Error loading lookup data');
});
You can then use countryLookupData for your values.
You could also use a custom grid editor, however you'll probably find that you still need to load the data into a var (as opposed to using a datasource with a DropDownList) and ensure that the data is loaded before the grid, because you'll most likely need to have a lookup for a column template so that you're newly selected value is displayed in the grid.
I couldn't quite get ForeignKey working in any useful way, so I ended up using custom editors as you have much more control over them.
One more gotcha: make sure you have loaded your lookup data BEFORE you define the column. I was using a column array that was defined in a variable I was then attaching to the grid definition... even if the lookup data is loaded before you use the grid, if it's defined after the column definition it will not work.
Although this post past 2 years, I still share my solution
1) Assume the api url (http://localhost/api/term) will return:
{
"odata.metadata":"http://localhost/api/$metadata#term","value":[
{
"value":2,"text":"2016-2020"
},{
"value":1,"text":"2012-2016"
}
]
}
please note that the attribute name must be "text" and "value"
2) show term name (text) from the foreign table instead of term_id (value).
See the grid column "term_id", the dropdownlist will be created if added "values: data_term"
<script>
$.when($.getJSON("http://localhost/api/term")).then(function () {
bind_grid(arguments[0].value);
});
function bind_grid(data_term) {
$("#grid").kendoGrid({
dataSource: ds_proposer,
filterable: true,
sortable: true,
pageable: true,
selectable: "row",
columns: [
{ field: "user_type", title: "User type" },
{ field: "user_name", title: "User name" },
{ field: "term_id", title: "Term", values: data_term }
],
editable: {
mode: "popup",
}
});
}
</script>
For those stumbling across this now, this functionality is supported:
https://demos.telerik.com/aspnet-mvc/grid/foreignkeycolumnbinding