Hi, been using Kendo for a little while now, mostly the grid widget to replace many screens in the PLM application that I maintain.
My skill-set is primarily server-side Progresss/OpenEdge database design and development, but a big chunk of my time now is on client-side development.
Anyway, the attached pics indicate an issue I'm having now, which I'll also describe below.
I feed my grid using a JSON import - this loads without errors. The grids are defined, in most places, with all columns available for sorting. At the end of the data row, I implement custom function calls for edit and delete.
If the data is NOT sorted, then the edit and delete functions are processed, but if the data (doesn't matter which column) IS sorted, then there is a "_previousSelection" error shown on inspection (running this in Chrome on Windows 7, but also occurs in Firefox on Windows 8/10)
Perfectly happy to accept that I'm doing something wrong, but I don't know what !
Screenshots attached, code below - I downloaded and installed the latest kendo zip file before posting this, just in case it'd been found and resolved
-----------------------------------------------------------------------------------------------------------------------------------------------------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Brand Maintenance</title>
<link rel="stylesheet" type="text/css" href="http://osl12/css/grey_segoe.css">
<link rel="stylesheet" type="text/css" href="http://osl12/css/kendo/styles/kendo.common.min.css">
<link rel="stylesheet" type="text/css" href="http://osl12/css/kendo/styles/kendo.default.min.css">
<link rel="icon" href="http://osl12/images/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="http://osl12/images/favicon.ico" type="image/x-icon" />
<script type="text/javascript" language="javascript" src="http://osl12/scripts/jQuery.js"></script>
<script type="text/javascript" language="javascript" src="http://osl12/scripts/validation.js"></script>
<script type="text/javascript" language="javascript" src="http://osl12/scripts/kendo/js/jszip.min.js"></script>
<script type="text/javascript" language="javascript" src="http://osl12/scripts/kendo/js/kendo.all.min.js"></script>
<script type="text/javascript" language="javascript" src="http://osl12/scripts/kendo/js/cultures/kendo.culture.en-GB.min.js"></script>
</head>
<body class="right" style="margin-bottom:0px; margin-top:0px; margin-left:0px; margin-right:0px" >
<table width="100%" cellspacing="0px" cellpadding="0px" border="0px" class="title">
<tr> <td class="titletop" colspan="2"></td> </tr>
<tr>
<td height="25px" nowrap valign="middle" class="title" width="91%" align="center">Brand Maintenance </td>
<td height="25px" nowrap valign="middle" align="left">
<a href="javascript: wop('http://osl12/cgi-bin/wspd_cgi.sh/WService=prm_wrk/SystemManager?WEB_SCRN=SrchManager&STD_TARGET=WRONG','',config='screenX=100,screenY=100,left=100,top=100,height=600,width=600,toolbar=no,menubar=no,dependent=no,scrollbars=yes,resizable=yes,location=no,directories=no,status=no')"><img border="0" src="http://osl12/images/search.png" height="19px"></a>
<a class="helptext" href="javascript: wop('http://osl12/cgi-bin/wspd_cgi.sh/WService=prm_wrk/SystemManager?WEB_SCRN=HelpManager&WEB_FRAMES=NO&WEB_PROG=BrandMaint&MODE=ProgramInfo&WEB_CONTEXT=__AMP__WEB_SCRN__EQL__BrandMaint__AMP__BODY_CLASS__EQL__right__AMP__KENDO_MODE__EQL__YES__AMP__STD_TARGET__EQL__Right','',config='screenX=100,screenY=100,left=100,top=100,height=700,width=735,toolbar=no,menubar=no,dependent=no,scrollbars=yes,resizable=yes,location=no,directories=no,status=no')"><img border="0" src="http://osl12/images/info2.png" height="19px" width="19px"></a>
</td>
</tr>
<tr> <td class="titlebot" colspan="2"></td> </tr>
</table>
<div id="toolbar"></div>
<style>
html { font-family: "Segoe UI", Calibri, Arial, "Sans Serif"; font-size: 9pt }
.header-image { position:absolute;top:0;bottom:0;max-height:1920px;overflow:hidden;left: 0;right: 0;z-index:-1;border:10px solid #545351;}
.header {width: 100%;}
.header-image img {width: 100% !important;}
.info { color: #7777ff; border: none; }
.error { color: #ff7777; border: red; }
.k-grid-header { padding: 0 !important; }
.k-grid-content { overflow-y: visible; }
td.k-col-sort { background-color: #FFF6F1; color: black; }
td.k-alt-col-sort { background-color: #FFEDE3; color: black; }
</style>
<form method="post" name="Form1" target="Right" action="http://osl12/cgi-bin/wspd_cgi.sh/WService=prm_wrk/SystemManager?WEB_SCRN=BrandMaint&KENDO_MODE=YES">
<input type="hidden" name="MODE" value="EDIT">
<input type="hidden" name="WEB_FRAMES" value="">
<input type="hidden" name="SEL_BRAND" value="">
</form>
<script language="javascript" type="text/javascript">
var gSaveColumns = true;
var undeletable = [];
var extraCheck = [];
function getCode(evt,btn)
{
var grid = $("div#grid").data("kendoGrid");
var currentRow = $(evt.currentTarget).parent().parent();
grid.select(currentRow);
var selected = grid.dataItem(grid.select());
return selected.Brand;
}
function editButton(evt,btn)
{
document.Form1.SEL_BRAND.value = getCode(evt,btn);
document.Form1.MODE.value = "EDIT";
document.Form1.submit();
}
function deleteButton(evt,btn)
{
document.Form1.SEL_BRAND.value = getCode(evt,btn);
var makeSure = false;
for (var i=0; i<undeletable.length; i++)
{
if (document.Form1.SEL_BRAND.value == undeletable[i])
{
alert("This record can not be deleted");
return;
}
}
for (var i=0; i<extraCheck.length && ! makeSure; i++)
{
if (document.Form1.SEL_BRAND.value == extraCheck[i])
makeSure = true;
}
if ( ( ! makeSure && ! confirm("Are you SURE you want to DELETE this Brand ?" ) ) ||
( makeSure && ! confirm("Column configuration and formatting cleared" ) ) )
return;
document.Form1.MODE.value = "DELETE";
document.Form1.submit();
}
function resetForm()
{
document.Form1.SEL_BRAND.value = "";
}
function wipeIt()
{
window.localStorage.removeItem("prm_wrk_rjj_HQ_BrandMaint_Grid");
alert("Column configuration and formatting cleared");
window.location.reload(true);
}
function saveIt(param)
{
var grid = $("#grid").data("kendoGrid");
var options = grid.getOptions();
for (var c in options.columns)
{
var col = options.columns[c];
if (col && col.command)
options.columns.splice(c,1);
}
localStorage["prm_wrk_rjj_HQ_BrandMaint_Grid"] = kendo.stringify(options);
if (param != "n")
alert("Column configuration and formatting saved");
}
function exportToExcel()
{
var grid = $("#grid").data("kendoGrid");
if (typeof showHideForExport != "undefined")
showHideForExport("s");
grid.saveAsExcel();
if (typeof showHideForExport != "undefined")
showHideForExport("h");
}
function exportToPDF()
{
var grid = $("#grid").data("kendoGrid");
grid.saveAsPDF();
}
function newRecord(URL, windowName, windowArgs)
{
wop(URL,windowName,windowArgs);
}
function removeHTML(anchorText,searchValue)
{
var junk = "", startPosn = 0;
if (searchValue != "")
{
startPosn = anchorText.search(searchValue);
if (startPosn > -1)
{
startPosn = startPosn + searchValue.length;
junk = anchorText.substr(startPosn);
var junk2 = junk.split('"');
return junk2[0];
}
}
else
{
searchValue = "</a>";
startPosn = anchorText.search(searchValue);
if (startPosn > -1)
for (var i=StartPosn; i>0; i--)
{
if (anchorText.charAt(i) == ">")
return junk;
else
junk = anchorText.charAt(i) + junk;
}
}
}
function gridBound(e)
{
var grid = e.sender, sort = grid.dataSource.sort();
var gridTable = grid.table, cols = grid.columns;
for (var i in sort)
{
var index = -1;
for (var c in cols)
{
if (cols[c].field == sort[i].field)
{
index = c;
break;
}
}
if (index >= 0)
sortColumn(gridTable, index);
}
var filter = grid.dataSource.filter();
grid.thead.find(".k-header-column-menu.k-state-active").removeClass("k-state-active");
if (filter)
{
var filteredMembers = {};
setFilteredMembers(filter, filteredMembers);
grid.thead.find("th[data-field]").each(function()
{
var cell = $(this);
var filtered = filteredMembers[cell.data("field")];
if (filtered)
{
cell.find(".k-header-column-menu").addClass("k-state-active");
}
}
);
}
}
function setFilteredMembers(filter, members)
{
if (filter.filters)
{
for (var i = 0; i < filter.filters.length; i++)
{
setFilteredMembers(filter.filters[i], members);
}
}
else
{
members[filter.field] = true;
}
}
function sortColumn(table, fldIndex)
{
table.find("tbody[role=rowgroup]").children("tr").each(function ()
{
var thisRow = $(this);
var className = thisRow.hasClass('k-alt') ? 'k-alt-col-sort' : 'k-col-sort';
$(this).children("td:eq(" + fldIndex + ")").addClass(className);
}
);
}
function gridChange(e)
{
var cols = e.sender.columns, sort = e.sender.dataSource.sort();
if (! sort || sort.length == 0)
return; // no sort fields...
// Get Array or Sort indexes...
var sortIndex = [], select = e.sender.select();
for (var i in sort)
for (var c in cols)
if (cols[c].field == sort[i].field)
{
sortIndex.push(parseInt(c));
break;
}
// Add Col sort col CSS Class on selected rows...
if (_previousSelection)
_previousSelection.each(function()
{
// Go backwards as we're deleting...
for (var r = select.length - 1; r >= 0; r--)
if (select[r] == this)
{
select.splice(r, 1);
return true;
}
var tr = $(this);
var className = tr.hasClass('k-alt') ? 'k-alt-col-sort' : 'k-col-sort';
for (var i in sortIndex)
tr.find("td:eq(" + sortIndex[i] + ")").addClass(className);
}
);
// Remove Col sort col CSS Class on selected row...
select.each(function()
{
var tr = $(this);
var className = tr.hasClass('k-alt') ? 'k-alt-col-sort' : 'k-col-sort';
for (var i in sortIndex)
tr.find("td:eq(" + sortIndex[i] + ")").removeClass(className);
}
);
// Save for later...
_previousSelection = e.sender.select();
}
function post(_async, _url, _data, _dataType, _onstatus, _onfail, _onerror)
{
var _handler404 = function (r)
{
alert("Unable to communicate with the server. The path" + _url + "could not be contacted. Is the server running?")
}
var customstatus = { 200: function (r)
{
var response = r;
if (typeof r.responseText != "undefined")
{
var payloadtype = r.getResponseHeader("Content-Type");
if(payloadtype.indexOf("application/json") == 0)
response = JSON.parse(r.responseText);
}
if (_onstatus != null && typeof _onstatus[200] != "undefined")
_onstatus[200](response);
},
403: function (response)
{
window.location = "index.php?type=expired";
},
404: _handler404
}
$.ajax(
{
type: "POST",
async: _async,
url: _url,
dataType: _dataType,
data: JSON.stringify(_data),
statusCode: customstatus,
success: function (r) { },
//fail: _onfail,
//error: _onerror
fail: function(f) {
alert("No data found for selection criteria - or JSON/Ajax Failure");
},
error: function(e) {
alert("No data found for selection criteria - or JSON/Ajax Error!");
},
}
);
}
$(document).ready(function()
{
var toolbar = $("#toolbar").kendoToolBar(
{
items: [
{
type: "button",
text: "Export to Excel",
icon: "excel",
click: function () { exportToExcel(); }
},
{
type: "separator",
width: "50px"
}
, {
type: "button",
text: "Export to PDF",
icon: "pdf",
click: function () { exportToPDF(); }
},
{
type: "separator",
width: "50px"
}
, {
type: "button",
text: "Reset",
click: function () { wipeIt(); }
},
{
type: "separator",
width: "50px"
},
{
type: "button",
text: "Save",
click: function () { saveIt(); }
}
, {
type: "separator",
width: "50px"
},
{
type: "button",
text: "Create New",
click: function () { resetForm(); document.Form1.submit(); }
}
]
}
);
var _previousSelection = null;
dataSource = new kendo.data.DataSource(
{
transport:
{
read:function(options)
{
post(false,
"http://osl12/cgi-bin/wspd_cgi.sh/WService=prm_wrk/SystemManager?WEB_SCRN=BrandMaint&MODE=KendoData&OUTPUT_MODE=JSON&KENDO_MODE=YES",
{
"options": JSON.stringify(options)
},
"json",
{
200: function (response)
{
options.success(response);
}
}
)
},
parameterMap: function(options, operation)
{
if (operation !== "read" && options.models)
return {models: kendo.stringify(options.models)};
}
},
page: 1,
pageSize: 5,
serverSorting: true,
serverFiltering: true,
serverPaging: true, // enable server paging
schema:
{
data: function (response)
{
return response.data;
},
total: function (data)
{
if (data != null && data.status == "ERROR")
{
alert(data.message);
return 0;
}
return data.total;
},
model:
{
id: "Brands",
fields:
{
Brand: { },
Description: { },
FlagActive: { },
CreatedByOnAt: { },
UpdatedByOnAt: { }
}
}
}
}
);
var _filters = null,
_sorting = null,
_columns = [
{
field: "Brand",
title: "Brand",
filterable: true,
headerAttributes: { title: "Brand", style: "text-align:left;" },
attributes: { style: "text-align:left;" }
},
{
field: "Description",
title: "Description",
filterable: true,
headerAttributes: { title: "Description", style: "text-align:left;" },
attributes: { style: "text-align:left;" }
},
{
field: "FlagActive",
title: "Active ?",
filterable: true,
headerAttributes: { title: "Active ?", style: "text-align:right;" },
attributes: { style: "text-align:right;" }
},
{
field: "CreatedByOnAt",
title: "Created By/On/At",
filterable: false,
headerAttributes: { title: "Created By/On/At", style: "text-align:left;" },
attributes: { style: "text-align:left;" }
},
{
field: "UpdatedByOnAt",
title: "Updated By/On/At",
filterable: false,
headerAttributes: { title: "Updated By/On/At", style: "text-align:left;" },
attributes: { style: "text-align:left;" }
}
];
var localOptionsJSON = localStorage["prm_wrk_rjj_HQ_BrandMaint_Grid"];
if (localOptionsJSON)
{
var localOptions = JSON.parse(localOptionsJSON);
if (localOptions && localOptions.columns)
_columns = localOptions.columns;
_filters = localOptions.dataSource.filter ? localOptions.dataSource.filter : null;
_sorting = localOptions.dataSource.sort ? localOptions.dataSource.sort : null;
}
_columns.push( { command: [
{ name: "Edit", text: "Maintain Selected", click: function(e) { editButton(e, this); } }
, { name: "Delete", text: "Delete Selected", click: function(e) { deleteButton(e, this); } }
],
title: "",
width: "250px"
}
);
$("#grid").kendoGrid(
{
excel: {
fileName:"BrandMaint.xlsx",
allPages: false,
filterable:true
},
pdf: {
author:"rjj",
creator:"rjj",
date:new Date(),
fileName:"BrandMaint.pdf",
landscape:true,
paperSize:"A4",
subject:"BrandMaint",
title:"BrandMaint",
},
filterable:
{
extra: false,
operators:
{
string:
{
startswith: "Starts with",
contains: "Contains",
eq: "Is equal to",
neq: "Is not equal to"
}
}
},
reorderable: true,
columnMenu: true,
selectable: true,
resizable: true,
sortable:
{
mode: "single",
allowUnsort: true
},
pageable:
{
pageSize: 10,
pageSizes: [5, 10, 25, 50, 100]
},
columns: _columns,
change: function(e)
{
gridChange(e)
},
dataBound: function(e)
{
gridBound(e)
}
}
);
// Bind the data source to the grid...
grid = $("#grid").data("kendoGrid");
dataSource._filter = _filters;
dataSource.sortable = _sorting;
grid.setDataSource(dataSource);
grid = $("#grid");
grid.find(".k-grid-pager").insertBefore(grid.children(".k-grid-header"));
}
);
</script>
<div id="grid"></div>
</body>
</html>