Kendo treelist - trying to set a column template - kendo-ui

I'm working with a Kendo treelist widget, and disappointed to see there's no rowTemplate option as there is on the Kendo grid.
I see a columnTemplate option (i.e. http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#configuration-columns.template ), but this will affect the entire column.
However, I need to drill into each cell value and set a css color property based on a ratio ( i.e. If value/benchmark < .2, assign <span style='color:red;'> , but my color value is dynamic.
There's a dataBound: and dataBinding: event on the treelist, but I'm still trying to figure out how to intercept each cell value and set the color once I've done my calculation.
var treeOptions = {
dataSource: ds,
columns: colDefs,
selectable: true,
scrollable: true,
resizable: true,
reorderable: true,
height: 320,
change: function (e) {
// push selected dataItem
var selectedRow = this.select();
var row = this.dataItem(selectedRow);
},
dataBound: function (e) {
console.log("dataBinding");
var ds = e.sender.dataSource.data();
var rows = e.sender.table.find("tr");
}
};
and this is where I'm building out the `colDefs' object (column definitions):
function parseHeatMapColumns(data, dimId) {
// Creates the Column Headers of the heatmap treelist.
// typeId=0 is 1st Dimension; typeId=1 is 2nd Dimension
var column = [];
column.push({
"field": "field0",
"title": "Dimension",
headerAttributes: { style: "font-weight:" + 'bold' + ";" },
attributes : { style: "font-weight: bold;" }
});
var colIdx = 1; // start at column 1 to build col headers for the 2nd dimension grouping
_.each(data, function (item) {
if (item.typeId == dimId) {
// Dimension values are duplicated, so push unique values (i.e. trade types may have dupes, whereas a BkgLocation may not).
var found = _.find(column, { field0: item.field0 });
if (found == undefined) {
column.push({
field: "field2",
title: item.field0,
headerAttributes: {
style: "font-weight:" + 'bold'
}
,template: "<span style='color:red;'>#: field2 #</span>"
});
colIdx++;
}
}
});
return column;
}
**** UPDATE ****
In order to embed some logic within the template :
function configureHeatMapColumnDefs(jsonData, cols, model) {
var colDef = '';
var dimId = 0;
var colorProp;
var columns = kendoGridService.parseHeatMapColumns(jsonData, dimId);
// iterate columns and set color property; NB: columns[0] is the left-most "Dimension" column, so we start from i=1.
for (var i = 1; i <= columns.length-1; i++) {
columns[i]['template'] = function (data) {
var color = 'black';
if (data.field2 < 1000) {
color = 'red';
}
else if (data.field2 < 5000) {
color = 'green';
}
return "<span style='color:" + color + ";'>" + data.field2 + "</span>";
};
}
return columns;
}
Advice is appreciated.
Thanks,
Bob

In the databound event you can iterate through the rows. For each row you can get the dataItem associated with it using the dataitem() method (http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#methods-dataItem)
Once you have the dataitem, calculate your ration and if the row meets the criteria for color, change the cell DOM element:
dataBound: function (e) {
var that = e.sender;
var rows = e.sender.table.find("tr");
rows.each(function(idx, row){
var dataItem = that.dataItem(row);
var ageCell = $(row).find("td").eq(2);
if (dataItem.Age > 30) {
//mark in red
var ageText = ageCell.text();
ageCell.html('<span style="color:red;">' + ageText + '</span>');
}
}
DEMO
UPDATE: you can also do this with a template:
$("#treelist").kendoTreeList({
dataSource: dataSource,
height: 540,
selectable: true,
columns: [
{ field: "Position"},
{ field: "Name" },
{ field: "Age",
template: "# if ( data.Age > 30 ) { #<span style='color:red;'> #= data.Age # </span> #}else{# #= data.Age # #}#"
}
],
});
DEMO

Related

index mismatch after column is hidden in Datatable

Hello I am using data table and as per some business logic certain columns in my table are shown or hidden for that I am sending the aoColumns as JSon from Java side, but the problem I am facing is in rowCallBack functions
I am manipulating columns on indexes which is miss-matched when I hide columns
This is how I am manipulating columns:
$('td:eq(0)', nRow).html(""+nameTrimmed+ "");
my guess is hidden columns are not counted in the index and rowCallBack just manipulates any column that is visible on that index
I can not write different rowCallBack for every case to keep it generic
Is there any way I can include the hidden column in index count?
or may be modify columns in some other way apart from indexes.
Here is the code
$('#myTable').DataTable({
"dom": 't<"pagecontrol"lip>',
"bJQueryUI": true,
"sPaginationType": "simple",
"bServerSide": true,
"sAjaxSource": "${ctx}/getData?",
"bProcessing": true,
"oLanguage":
{
"sInfo": "<fmt:message key="DataTable.key.DT_SHOWING_ENTRIES" />",
"sInfoEmpty": "<fmt:message key="DataTable.key.DT_SHOWING_ENTRIES_EMPTY" />",
"oPaginate":
{
"sNext": '<i class="fa fa-caret-right"></i>',
"sLast": '<<',
"sFirst": '>>',
"sPrevious": '<i class="fa fa-caret-left"></i>'
}
},
"lengthMenu": [[50, 100, 150, 200], [50, 100, 150, 200]],
"rowCallback": function( nRow, dtoObj, iDisplayIndex, iDisplayIndexFull ) {
if (dtoObj.firstName != '' && !showDownloadButton) {
$("#participantDownloadButton").removeClass('hide');
showDownloadButton = true;
}
if(searchStringCount == dtoObj.searchStringCounter || dtoObj.searchStringCounter == 0) {
var name = dtoObj.firstName +" "+ dtoObj.lastName;
var nameTrimmed = trimStringByCharacters(name, 25);
$('td:eq(0)', nRow).html("<label title='"+name.trim()+"'>"+nameTrimmed+ "</label>");
//column 2 email
if(dtoObj.email!='') {
var email = trimStringByCharacters(dtoObj.email,20) ;
$('td:eq(1)', nRow).html("<label title='" + email + "'>" + email + "</label>");
}else{
$('td:eq(1)', nRow).html("");
}
//column 3 List name
var listName = dtoObj.eligibilityListName;
var listNameTrimmed = "";
if(listName!=null) {
listNameTrimmed = trimStringByCharacters(listName, 20);
}
$('td:eq(2)', nRow).html("<label title='"+listName+"'>"+listNameTrimmed+ "</label>");
var packageLevel = dtoObj.packageLevel;
var packageLevelTrimmed = trimStringByCharacters(packageLevel, 15);
$('td:eq(3)', nRow).html("<label title='"+packageLevel+"' data-participant-id='"+dtoObj.userId+"'>"+packageLevelTrimmed+ "</label>");
var durationUnit ='<fmt:message key="reports.filter.months"/>';
if (dtoObj.packageDuration == 1) {
durationUnit = '<fmt:message key="reports.filter.month"/>';
}
$('td:eq(4)', nRow).html(dtoObj.packageDuration +" "+ durationUnit);
// Add icons before status
var status = dtoObj.status;
var iconLink = getIconLinkByStatus(status);
// Add icons ends
if(dtoObj.status != null) {
$('td:eq(6)', nRow).html(iconLink + dtoObj.status);
} else {
$('td:eq(6)', nRow).html("");
}
}
},
"drawCallback": function() {
$(".dataTables_wrapper").children(".pagecontrol").find("#participantsTable_length label").contents().eq(0).replaceWith('<fmt:message key="rows.per.page"/> ');
$("#participantsTable").find(".dataTables_empty").html('<fmt:message key="no.data.in.table"/>');
//Code to diaply participant details view
$('#participantsTable tbody tr').on('click',function () {
var $tds = $(this).find('td');
var userId = $tds.eq(2).find('label').attr("data-participant-id");;
var status = $tds.eq(5).text();
var listName = $tds.eq(1).text();
showParticipantDetails(userId, status, listName);
});
},
"aoColumns": columnData //coming from server side
});

jqgrid select only one row per group

How can we allow the users to only select one row per group?
I have the following code.
var data = [
{ ActionItemId: "AAZ08702-0001104", StrarTime: "2007-10-01", Category: "General", CategoryDetails: "dummy text of industry. a galley of type ", TargetCategory: "200.00",
TargetDateCategory: "10.00", ActualCategory: "210.00"}
];
$("#jqGrid").jqGrid({
data: data,
datatype: "local",
colModel: [
{ label: 'Action Item ID', name: 'ActionItemId', key: true },
{ label: 'Start Time', name: 'StrarTime'},
{ label: 'Category', name: 'Category'},
{ label: 'Details', name: 'CategoryDetails', cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal;"' }},
{ label: 'Target <Category>', name: 'TargetCategory' },
{ label: 'Target Date <Category>', name: 'TargetDateCategory'}
],
loadonce: true,
viewrecords: true,
//width: 1000,
height: 400,
rowNum: 20,
rowList: [20, 30, 50],
rownumbers: true,
rownumWidth: 25,
multiselect: true,
shrinkToFit: false,
pager: "#jqGridPager",
grouping: true,
groupingView: {
groupField: ["Category"],
groupColumnShow: [true],
groupText: ["Category: <b>{0}</b>"],
groupOrder: ["asc"],
groupSummary: [false],
groupCollapse: false
}
});
I need to disable the ability to select multiple rows per column. is it possible?
Is there a setting in the grouping function to enable which will work as mu requirement? or should it be custom development?
Note: I have only added one column to avoid a very long code in the question
One of the possible implementation could be adding add callback which return false if another row from the same group is already selected. An example of the implementation is the following:
beforeSelectRow: function (rowid, e) {
var selarrrow = $(this).jqGrid("getGridParam", "selarrrow"),
$tr = $(e.target).closest("tr.jqgrow"),
otherIdsOfTheGroup;
if ($tr.length > 0) {
otherIdsOfTheGroup =
// get all rows of the group before the current
$tr.prevUntil("tr.jqgroup")
// add all rows of the group after the current
.add($tr.nextUntil("tr.jqgroup"))
// enum all the rows of the group without the current
.map(function () {
// test whether the rowid is already selected
if ($.inArray(this.id, selarrrow) >= 0) {
// add the rowid to the array of returned values
return this.id;
}
});
// otherIdsOfTheGroup contains the array of rowids of the rows
// from the same group, which are already selected
if (otherIdsOfTheGroup.length > 0) {
return false; // prevent selection
}
}
return true; // allow selection
}
See the demo
UPDATED: One can easy modify the aboce vode to unselect the previously selected rows from the same group. One need just call resetSelection for every rowid from otherIdsOfTheGroup array and return true from otherIdsOfTheGroup to allow selection:
beforeSelectRow: function (rowid, e) {
var $this = $(this),
selarrrow = $this.jqGrid("getGridParam", "selarrrow"),
$tr = $(e.target).closest("tr.jqgrow"),
otherIdsOfTheGroup;
if ($tr.length > 0) {
otherIdsOfTheGroup =
// get all rows of the group before the current
$tr.prevUntil("tr.jqgroup")
// add all rows of the group after the current
.add($tr.nextUntil("tr.jqgroup"))
// enum all the rows of the group without the current
.map(function () {
// test whether the rowid is already selected
if ($.inArray(this.id, selarrrow) >= 0) {
// add the rowid to the array of returned values
return this.id;
}
});
// otherIdsOfTheGroup contains the array of rowids of the rows
// from the same group, which are already selected
if (otherIdsOfTheGroup.length > 0) {
$.each(otherIdsOfTheGroup, function () {
$this.jqGrid("resetSelection", this);
});
}
}
return true; // allow selection
}
See the next demo. I included hiding of the column header of "Select All" button just to write less code. You can implement onSelectAll callback and allow to select only one (for example the first) row from every group.
I managed to solve this issue using the following code.
beforeSelectRow: function (id, e) {
var rowdata = $("#jqGrid").getRowData(id);
var category = rowdata.Category;
var selectedRowTR = $("#jqGrid").find("tr[id='" + id + "']");
var groupTRs = $("#jqGrid").find("tbody> tr.jqgrow > td[title='" + category + "']").parents("tr");
var ids = groupTRs.map(function () {
return this.id;
}).get();
var selectedIDs = $("#jqGrid").getGridParam("selarrrow");
var commonValues = [];
var i, j;
var arr1Length = ids.length;
var arr2Length = selectedIDs.length;
for (i = 0; i < arr1Length; i++) {
for (j = 0; j < arr2Length; j++) {
if (ids[i] === selectedIDs[j]) {
commonValues.push(ids[i]);
}
}
}
for (var i = 0; i < commonValues.length; i++) {
$("#jqGrid").jqGrid('setSelection', commonValues[i], false);
}
return true;
},
rowdata.Category; is the variable which the table is grouped. The only issue is that the user cannot untick what he/she has already selected in a group. so it works like a radio button set. But it works for my requirement.
hopefully we can improve this and introduce radio kind of behavior for grouping in jqgrid.
thanks everyone.

Pan and zoom in kendo boxplot chart

I am trying to use the pan and zoom functionality in kendo box plot chart, can this be achieved for box plot chart.
http://demos.telerik.com/kendo-ui/bar-charts/pan-and-zoom
You can apply the exact same methods to the boxplot.
DEMO
CODE:
// Minimum/maximum number of visible items
var MIN_SIZE = 6;
var MAX_SIZE = 18;
// Optional sort expression
// var SORT = { field: "val", dir: "asc" };
var SORT = {};
// Minimum distance in px to start dragging
var DRAG_THR = 50;
// State variables
var viewStart = 0;
var viewSize = MIN_SIZE;
var newStart;
// Drag handler
function onDrag(e) {
var chart = e.sender;
var ds = chart.dataSource;
var delta = Math.round(e.originalEvent.x.initialDelta / DRAG_THR);
if (delta != 0) {
newStart = Math.max(0, viewStart - delta);
newStart = Math.min(data.length - viewSize, newStart);
ds.query({
skip: newStart,
page: 0,
pageSize: viewSize,
sort: SORT
});
}
}
function onDragEnd() {
viewStart = newStart;
}
// Zoom handler
function onZoom(e) {
var chart = e.sender;
var ds = chart.dataSource;
viewSize = Math.min(Math.max(viewSize + e.delta, MIN_SIZE), MAX_SIZE);
ds.query({
skip: viewStart,
page: 0,
pageSize: viewSize,
sort: SORT
});
// Prevent document scrolling
e.originalEvent.preventDefault();
}
$("#chart").kendoChart({
dataSource: {
data: data,
pageSize: viewSize,
page: 0,
sort: { }
},
title: {
text: "Ozone Concentration (ppm)"
},
legend: {
visible: false
},
series: [{
type: "boxPlot",
lowerField: "lower",
q1Field: "q1",
medianField: "median",
q3Field: "q3",
upperField: "upper",
meanField: "mean",
outliersField: "outliers"
}],
categoryAxis: {
field: "year",
majorGridLines: {
visible: false
}
},
transitions: false,
drag: onDrag,
dragEnd: onDragEnd,
zoom: onZoom
});

KendoUI Multiselect Remove Multiple

I am using Kendo UI Multiselect:
http://demos.kendoui.com/web/multiselect/events.html
I have this Data:
var data =
[
{ text: "Shirt-Black", value: "1" },
{ text: "Shirt-Brown", value: "2" },
{ text: "Shirt-Blue", value: "3" },
{ text: "Cap-Green", value: "4" },
{ text: "Cap-Red", value: "5" },
{ text: "Cap-White", value: "6" },
{ text: "Jacket-Denim", value: "7" }
];
Now I want that if I select "Shirt-Brown" then rest entries for shirt i.e. "Shirt-Black" and "Shirt-Blue" should not appear in the list which means that the user should not be able to choose the Shirt of two colors.
Similarly, If a "Cap" of any color has been chosen then user should not be able to choose the "Cap" of any other color.
Is there any way to achieve this?
This is not build-in functionality. You can't even use dataSource filter() method because it will remove selected items from list as well.
However, this code will do what you're asking:
$("#select").kendoMultiSelect({
...
change: function(e) {
var dataItems = e.sender.dataItems();
var categories = [];
for(var i = 0; i < dataItems.length; i++){
var category = dataItems[i].text.substring(0, dataItems[i].text.indexOf('-'));
categories.push(category);
}
e.sender.ul.find('li').each(function(index, value){
var $li = $(value);
var hidden = false;
for(var i = 0; i < categories.length; i++){
var category = categories[i];
if ($li.text().match("^" + category)){
$li.css('display', 'none');
hidden = true;
}
}
if(!hidden){
$li.css('display', 'list-item');
}
});
}
});
Working KendoUi Dojo: http://dojo.telerik.com/AGisi

jqGrid Retain Invalid Cell Value After EditRules Pop Up

#Oleg - I am new to jqGrid.I have three issues. Urgent help required.
I am using jqGrid 3.8, inline edit mode.
I want to retain the invalid cell values after the pop up for invalid cell.
Also I want to set the focus back to the invalid cell.
I have "add row" and filter tool bar feature in my jqGrid. I have used Oleg's solution in creating drop down for filter tool bar (posted in another jQuery thread).
**
- Problem:
** I am calling setSearchSelect from afterSaveCell, because I want to add new values in filter drop down every time I add or delete column.(Note: column is a textbox). But the filter tool bar isn't getting refreshed even if I use
var sgrid = $("#list")[0];
sgrid.triggerToolbar();
See the code below for setting the toolbar.
<script type="text/javascript">
var mydata = [
{id:"1", Name:"Miroslav Klose", Category:"sport", Subcategory:"football"},
{id:"2", Name:"Michael Schumacher", Category:"sport", Subcategory:"formula 1"},
{id:"3", Name:"Albert Einstein", Category:"science", Subcategory:"physics"},
{id:"4", Name:"Blaise Pascal", Category:"science", Subcategory:"mathematics"}
],
grid = $("#list"),
getUniqueNames = function(columnName) {
var texts = grid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
},
buildSearchSelect = function(uniqueNames) {
var values=":All";
$.each (uniqueNames, function() {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function(columnName) {
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value:buildSearchSelect(getUniqueNames(columnName)),
sopt:['eq']
}
}
);
};
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name:'Name', index:'Name', width:200 ,editable:true},
{ name:'Category', index:'Category', width:200,editable:true },
{ name:'Subcategory', index:'Subcategory', width:200,editable:true }
],
sortname: 'Name',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
editurl: "clientArray",
multiselect: true,
pagination:true,
cellEdit: true,
cellsubmit: 'clientArray',
//ignoreCase: true,
pager: '#pager',
height: "auto",
enableSearch: true,
caption: "How to use filterToolbar better locally",
afterSaveCell: function(rowid,name,val,iRow,iCol) {
setSearchSelect(name);
jQuery("#list").('setColProp', name,
{
width:100
}
);
var sgrid = $("#list")[0];
sgrid.triggerToolbar();
alert(name);
},
loadComplete: function () {
setSearchSelect('Category');
}
}).jqGrid('navGrid','#pager',
{edit:false, add:false, del:false, search:false, refresh:true});
setSearchSelect('Category');
setSearchSelect('Subcategory');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt:['cn'],
dataInit: function(elem) {
$(elem).autocomplete({
source:getUniqueNames('Name'),
delay:0,
minLength:0
});
}
}
});
grid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"cn"});
function addRow(tableId){
var loopRow = document.getElementById("addRowsInput").value;
var recordCount = '';
var rwData = '';
//var selRowIds = getRowIDs('list');
var gridProducts = $("#list");
var resetFirstRow = jQuery("#list").getRowData( 1 );
jQuery("#list").setRowData( 1, resetFirstRow );
if(loopRow == null || loopRow == "" || loopRow == "Enter number of units to be added")
{
loopRow = 1;
}
for(i=0; i< loopRow; i++)
{
recordCount = jQuery("#list").getGridParam("records") ;
var emptydata = [
{id:(recordCount+1), Name:"", Category:"", Subcategory:""}]
gridProducts.jqGrid('addRowData', recordCount+1, emptydata[0]);
}
}
</script>
#Oleg - one more question on the solution you suggested. Sorry I tried myself to find it but couldn't.
In the buildSearchSelect: method , how can I include filter for empty string.
As explained above I have a "Add Row" button. So when the user wants to filter rows with empty columns I need a filter value.
The implementation of setSearchSelect function from my old answer work only if the searching toolbar not yet exist. If the toolbar exist one have to modify the options of the select element or autocomplete source of the jQuery UI autocomplete widget.
I extended the code. You can see the new version of the demo here. In the same way one could use inline editing instead of the cell editing.
Here is the modified JavaScript code:
var mydata = [
{id:"1", Name:"Miroslav Klose", Category:"sport", Subcategory:"football"},
{id:"2", Name:"Michael Schumacher", Category:"sport", Subcategory:"formula 1"},
{id:"3", Name:"Albert Einstein", Category:"science", Subcategory:"physics"},
{id:"4", Name:"Blaise Pascal", Category:"science", Subcategory:"mathematics"}
],
grid = $("#list"),
getUniqueNames = function(columnName) {
var texts = grid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
uniqueTexts.sort();
return uniqueTexts;
},
buildSearchSelect = function(uniqueNames) {
var values=":All";
$.each (uniqueNames, function() {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function(columnName) {
var $select = $('select#gs_'+columnName), un = getUniqueNames(columnName),
htmlForSelect = '<option value="">All</option>', i, l=un.length, val;
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value:buildSearchSelect(un),
sopt:['eq']
}
}
);
if ($select.length > 0) {
// The searching toolbar already exist. One have to update it manually
for (i=0;i<l;i++) {
val = un[i];
htmlForSelect += '<option value="'+val+'">'+val+'</option>';
}
$select.html(htmlForSelect);
}
},
setAutocomplete = function(columnName) {
var $input = $('input#gs_'+columnName), un = getUniqueNames(columnName);
grid.jqGrid('setColProp', columnName,
{
searchoptions: {
sopt:['cn'],
dataInit: function(elem) {
$(elem).autocomplete({
source:un,
delay:0,
minLength:0
});
}
}
});
if ($input.length > 0) {
// The searching toolbar already exist. One have to update the source
$input.autocomplete('option', 'source', un);
}
},
selectColumns = ['Category','Subcategory'], autocompleteColumns = ['Name'];
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name:'Name', index:'Name', width:200 ,editable:true},
{ name:'Category', index:'Category', width:200,editable:true },
{ name:'Subcategory', index:'Subcategory', width:200,editable:true }
],
sortname: 'Name',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
cellEdit: true,
cellsubmit: 'clientArray',
ignoreCase: true,
pager: '#pager',
height: "auto",
caption: "How to use filterToolbar better locally including local cell editing",
afterSaveCell: function(rowid,name,val,iRow,iCol) {
if ($.inArray(name,selectColumns) !== -1) {
setSearchSelect(name);
} else if ($.inArray(name,autocompleteColumns) !== -1) {
setAutocomplete(name);
}
}
}).jqGrid('navGrid','#pager',
{edit:false, add:false, del:false, search:false, refresh:true});
$.each(selectColumns,function() {
setSearchSelect(String(this));
});
$.each(autocompleteColumns,function() {
setAutocomplete(String(this));
});
grid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"cn"});

Resources