I am trying to add a kendoToolTip to the cells of a specific column on my grid. Right now, the tooltip works, but it displays when hovering over any cell on the grid.
I want to get the specific cell index of the item im hovering over, so that I can only display the tooltip when hovering over cell index 9 for example.
The code i have always returns me cell index of -1. I can make it work with an onclick event, but i cannot get it to work with on hover.
Any help would be appreciated.
$("#samplerequest-grid").kendoTooltip({
filter: "td",
content: function(e) {
var grid = $("#samplerequest-grid").data("kendoGrid");
var dataItem = grid.dataItem(e.target.closest('tr'));
var rowIdx = $("tr", grid.tbody).index(dataItem);
var colIdx = $("td", dataItem).index(this); // Always returns -1
console.log("row:" + rowIdx + " col:" + colIdx + " msg: " + dataItem.sampleStatusMsg);
return dataItem.sampleStatusMsg;
}
});
UPDATE:
Thank you for the answers. They both would have worked, and i may change my solution to use them. Before seeing your answers i did find my own solution, which was to add a template to the cell and filter for that id.
Grid Column Declaration:
{
field: "sampleStatus",
title: "Sample Status",
width: "110px",
locked: true,
lockable: true,
template: "<span id='sampStatus'>#=getValue(sampleStatus)#</span>"
},
Controller function for tooltip
$("#samplerequest-grid").kendoTooltip({
filter: "#sampStatus",
content: function(e) {
var grid = $("#samplerequest-grid").data("kendoGrid");
var dataItem = grid.dataItem(e.target.closest('tr'));
return dataItem.sampleStatusMsg;
}
});
I think you're overcomplicating things here. You can get the indexes with:
e.target.index() the cell index;
e.target.closest('tr') the row index.
You content event should be:
content: function(e) {
var grid = $("#samplerequest-grid").data("kendoGrid");
var tr = e.target.closest('tr');
var dataItem = grid.dataItem(tr);
var rowIdx = tr.index();
var colIdx = e.target.index();
console.log("row:" + rowIdx + " col:" + colIdx + " msg: " + dataItem.sampleStatusMsg);
return dataItem.sampleStatusMsg;
}
Demo
The code to find the index will not work because you are searching for td elements in the context of the dataItem. Also, I don't think that the context of the content function is the current cell. This code should work to find the index:
var row = e.target.closest('tr');
var colIdx = $("td", row).index(e.target);
but IMHO a better approach is to add a class to the column cells and the same class to the filter:
https://dojo.telerik.com/#SiliconSoul/UbImUjOl
Related
I've got a two-row table (label row and data row) that gets filled in with all relevant information about a running service, however, about half of the cells are empty at any given time depending on which test is run.
I'm looking for a jquery statement that will find all empty cells and hide them along with the label for that cell. I've searched quite a bit and found this code that is meant to hide the empty cells
$('table#yourTable tr').each(function(){
if($(this).children('td:empty').length === $(this).children('td').length){
$(this).hide();
}
});
However, my "empty" cells are populated with " " and not truly empty. Is there a way to hide a cell and its associated label cell?
You can use .filter()
$(document).ready(function() {
var elems = $("tr").filter(function() {
return this.querySelector("td").innerHTML === " "
});
elems.hide();
})
following code will hide all of your not truly empty cell and it's label cell.
$(function () {
var $label = $('tr:first');
$('tr:last td').each(function (index, td) {
var $td = $(td);
if ($td.html() != ' ') return;
$td.hide();
$label.find('td:eq(' + index + ')').hide();
});
});
I have kendo grid and got lots of columns for looking a specific column i have to scroll a lot horizontally and deep down my eyes to see where is that column, can we a column search text box so when i enter column name it should scroll me there to that column or can we list all columns(names) in a dropdown above my kendo grid so by selecting that i can see that column highlighted or selected.
I tried finding it a lot but could not found, i have bought kendo grid.
Help me out.!!
Thanks !!
Try this code:
$("#grid").kendoGrid({
...
});
// Generate column list
var gridColumns = $("#grid").data("kendoGrid").options.columns,
htmlOptions = "";
for (var i = 0; i < gridColumns.length; i++) {
htmlOptions+= "<option value='" + i + "'>" + gridColumns[i].title + "</option>";
}
$("#column-list")
.append(htmlOptions)
.on("change", function() {
// get the grid
var grid = $("#grid").data("kendoGrid");
// Find the TH element inside the grid's THEAD based on chosen index
var chosenColumn = $(grid.element).find("thead th:eq(" + $(this).val() + ")");
// Scroll to the column by its offsetLeft property
scroll(chosenColumn[0].offsetLeft);
});
// Scroll function
var scroll = function(pos) {
$(".k-grid-content")[0].scrollLeft = pos;
}
HTML:
<select id="column-list"></select>
Demo. The snippet is self-explained in its own comments. If they aren't enough to you to understand, please tell me.
Reference:
scrollLeft
Okay, so we have some legacy code which uses Kendo UI Grids.
After sorting the grid, we need to be able to read the DataSource item which corresponds to each row, by iterating through the JQuery selected 'tr' list and then select the DataSource item based on the index of the row itself.
The problem exists in that the DataSource doesn't sort when the grid sorts, so you cannot simply get the index of each row and look up the corresponding DataSource item, like this...
$('td:nth-child(' + colIndex + ')', $('tbody', grid.element).eq(0)).each(
function (iIndex) {
var td = $(this);
var tr = td.parent();
var data = grid.dataSource.data()[iIndex];
if (data.Status.toLowerCase() !== 'c') {
totalBalanceDue = (totalBalanceDue - data.Payment) > 0 ? (totalBalanceDue - data.Payment) : 0;
};
td.html('$' + totalBalanceDue.formatMoney(2, '.', ','));
}
);
This is all not needed. All you need to use is the view() method of the dataSource.
Looks like I have to answer this question myself.
I have found, by scouring the documentation and the web, that the way I'm approaching this is not necessarily accurate. Instead of attempting to sort the array to match the rows of the gridview, I can use the data-uid attribute of the row, to get the corresponding dataitem from the DataSource.data() array, by using the dataSource.getByUid() function.
This is working just as I need it to.
$('td:nth-child(' + colIndex + ')', $('tbody', grid.element).eq(0)).each(
function (iIndex) {
var td = $(this);
var tr = td.parent();
//gets the corresponding dataitem for the selected row.
var data = grid.dataSource.getByUid(tr.data("uid"));
if (data.Status.toLowerCase() !== 'c') {
totalBalanceDue = (totalBalanceDue - data.Payment) > 0 ? (totalBalanceDue - data.Payment) : 0;
};
td.html('$' + totalBalanceDue.formatMoney(2, '.', ','));
}
);
I have a scenario with grid within grid implemented using the detailInit method. Here when user makes edit, i do some calculations that will change the data in the both parent and child. and then to refresh data, i will call the datasource.read to render data. this works and the data is displayed, however any detail grid which are expanded will be collapsed, is there any way i can prevent this from happening.
To answer this and another question:
"I figured out how to set the data in the master from the child BUT, the
whole table collapses the child grids when anything is updated, this is a
very annoying behavior, is there anyway I can just update a field in
the master table without it collapsing all the child elements?
(basically, update the column, no mass table update)"
in another thread at: telerik
This is extremely annoying behavior of the Kendo Grid and a major bug. Since when does a person want the sub-grid to disappear and hide a change that was just made! But this isn't the only problem; the change function gets called a Fibonacci number of times, which will freeze the browser after a significant number of clicks. That being said, here is the solution that I have come up with:
In the main grid
$('#' + grid_id).kendoGrid({
width: 800,
...
detailExpand: function (e) {
var grid = $('#' + grid_id).data("kendoGrid");
var selItem = grid.select();
var eid = $(selItem).closest("tr.k-master-row").attr('data-uid')
if (contains(expandedItemIDs, eid) == false)
expandedItemIDs.push(eid);
},
detailCollapse: function (e) {
var grid = $('#' + grid_id).data("kendoGrid");
var selItem = grid.select();
var eid = $(selItem).closest("tr.k-master-row").attr('data-uid')
for (var i = 0; i < expandedItemIDs.length; i++)
if (expandedItemIDs[i] == eid)
gridDataMap.expandedItemIDs.splice(i, 1);
},
Unfortunately globally we have:
function subgridChange() {
var grid = $('#' + grid_id).data("kendoGrid");
for (var i = 0; i < expandedItemIDs.length; i++)
grid.expandRow("tr[data-uid='" + expandedItemIDs[i] + "']");
}
function contains(a, obj) {
for (var i = 0; i < a.length; i++)
if (a[i] === obj) return true;
return false;
}
expandedItemIDs = [];
Now the 'subgridChange()' function needs to be called every time a change is made to the subgrid.
The problem is that the number of times the change function in the subgrid gets called increases exponentially on each change call. The Kendo grid should be able to call a stop propagation function to prevent this, or at least give the programmer access to the event object so that the programmer can prevent the propagation. After being completely annoyed, all we have to do is to place the 'subgridChange()' function in the subgrid 'datasource' like so:
dataSource: function (e) {
var ds = new kendo.data.DataSource({
...
create: false,
schema: {
model: {
...
}
},
change: function (e) {
subgridChange();
}
});
return ds;
}
I also had to place the 'subgridChange()' function in the Add button function using something like this
$('<div id="' + gridID + '" data-bind="source: prodRegs" />').appendTo(e.detailCell).kendoGrid({
selectable: true,
...
toolbar: [{ template: "<a class='k-button addBtn' href='javascript://'><span class='k-icon k-add' ></span> Add Product and Region</a>" }]
});
$('.addBtn').click(function (event) {
...
subgridChange();
});
When a user selects a row, record the index of the selected row. Then after your data refresh, use the following code to expand a row
// get a reference to the grid widget
var grid = $("#grid").data("kendoGrid");
// expands first master row
grid.expandRow(grid.tbody.find(">tr.k-master-row:nth-child(1)"));
To expand different rows, just change the number in the nth-child() selector to the index of the row you wish to expand.
Actually all that is needed is the 'subgridChange()' function in the main grid 'dataBound' function:
$('#' + grid_id).kendoGrid({
...
dataBound: function (e) {
gridDataMap.subgridChange();
}
});
Different but similar solution that i used for same problem:
expandedItemIDs = [];
function onDataBound() {
//expand rows
for (var i = 0; i < expandedItemIDs.length; i++) {
var row = $(this.tbody).find("tr.k-master-row:eq(" + expandedItemIDs[i] + ")");
this.expandRow(row);
}
}
function onDetailExpand(e) {
//refresh the child grid when click expand
var grid = e.detailRow.find("[data-role=grid]").data("kendoGrid");
grid.dataSource.read();
//get index of expanded row
$(e.detailCell).text("inner content");
var row = $(e.masterRow).index(".k-master-row");
if (contains(expandedItemIDs, row) == false)
expandedItemIDs.push(row);
}
function onDetailCollapse(e) {
//on collapse minus this row from array
$(e.detailCell).text("inner content");
var row = $(e.masterRow).index(".k-master-row");
for (var i = 0; i < expandedItemIDs.length; i++)
if (expandedItemIDs[i] == row)
expandedItemIDs.splice(i, 1);
}
function contains(a, obj) {
for (var i = 0; i < a.length; i++)
if (a[i] === obj) return true;
return false;
}
I am new to jqGrid and I need help with a scenario that I am not able to figure out.
I am able to make a cell un-editable using the following code:
jQuery("#updAssist").jqGrid('setCell',rowid,'precPsProg','','not-editable-cell');
Now I want to make the cell editable again based on some condition.
What class should I use to achieve that?
Is there a 'editable-cell' class that I can use?
You should remove 'not-editable-cell' class from the cell (<td> element)
td.removeClass('not-editable-cell');
You should select all cells (<td> element) which you want make editable.
I made the demo which demonstrate how to do this. The most important code fragment from the demo is
var grid = $("#list");
var getColumnIndexByName = function(gr,columnName) {
var cm = gr.jqGrid('getGridParam','colModel');
for (var i=0,l=cm.length; i<l; i++) {
if (cm[i].name===columnName) {
return i; // return the index
}
}
return -1;
};
var changeEditableByContain = function(gr,colName,text,doNonEditable) {
var pos=getColumnIndexByName(gr,colName);
// nth-child need 1-based index so we use (i+1) below
var cells = $("tbody > tr.jqgrow > td:nth-child("+(pos+1)+")",gr[0]);
for (var i=0; i<cells.length; i++) {
var cell = $(cells[i]);
//var cellText = cell.text();
var unformatedText = $.unformat(cell,{rowId:cell[0].id,
colModel:gr[0].p.colModel[pos]},pos);
if (text === unformatedText) { // one can use cell.text() instead of
// unformatedText if needed
if (doNonEditable) {
cell.addClass('not-editable-cell');
} else {
cell.removeClass('not-editable-cell');
}
}
}
};
grid.jqGrid({
datatype: "local",
...
cellEdit: true,
cellsubmit: 'clientArray',
loadComplete: function() {
changeEditableByContain(grid,'name','test',true);
}
});
$("#doEditable").click(function(){
changeEditableByContain(grid,'name','test',false);
});
$("#doNonEditable").click(function(){
changeEditableByContain(grid,'name','test',true);
});
In the demo the cells from the 'Client' column having the text "test" will be marked as "non-editable". Later one can make the cells "editable" or "non-editable" be clicking on the corresponding button.