Adding External filters for Kendo UI Grid - kendo-ui

What i want to achieve is:
Have a Master Grid. Clicking on a row of this grid, i want to filter the rows of the ChildGrid.
What i have done so far:
function updateChildGridRows(field, operator, value) {
// get the kendoGrid element.
var gridData = $("#childGrid").data("kendoGrid");
var filterField = field;
var filterValue = value;
// get currently applied filters from the Grid.
var currFilterObj = gridData.dataSource.filter();
// if the oject we obtained above is null/undefined, set this to an empty array
var currentFilters = currFilterObj ? currFilterObj.filters : [];
// iterate over current filters array. if a filter for "filterField" is already
// defined, remove it from the array
// once an entry is removed, we stop looking at the rest of the array.
if (currentFilters && currentFilters.length > 0) {
for (var i = 0; i < currentFilters.length; i++) {
if (currentFilters[i].field == filterField) {
currentFilters.splice(i, 1);
break;
}
}
}
if (filterValue != "") {
currentFilters.push({
field: filterField,
operator: "eq",
value: filterValue
});
}
gridData.dataSource.filter({
filters: currentFilters
}); }
I got this code from the following jsfiddle:
http://jsfiddle.net/randombw/27hTK/
I have attached the MasterGrid's Change event to MasterGridSelectionChange() method. From there i am calling my filter method.
But when i click on the MasterGrid's row, all of the rows in my ChildGrid are getting removed.
One thing i can understand is, if i give wrong column name in the filter list, all the rows will be removed. But even though i have given correct ColumnName, my rows are getting deleted.
Sorry for the long post.
Please help me with this issue, as i am stuck with this for almost 4 days!
Thanks.

You can define ClientDetailTemplateId for the master grid and ToClientTemplate() for the Child grid
read Grid Hierarchy for a example

Related

Row selection dynamically for next page and reverse back in kendo grid

Anyone please tell me how can i select next consecutive row from first page to second page of my kendo grid and reverse back to the previous page ? Kendo Grid API just only gives me information on 'select' and from there I have no clue at all how to implement my desired selection. What I have now is only selecting the row of the selected/active cell. Any insight/references are also appreciated. So far I haven't came across with any examples or article.
var data = $("#grid").data('kendoGrid');
var arrows = [38,40];
data.table.on("keydown", function (e) {
if (arrows.indexOf(e.keyCode) >= 0) {
setTimeout(function () {
data.clearSelection();
data.select($("#grid_active_cell").closest("tr"));
},1);
}
});
http://dojo.telerik.com/eSUQO
var data = $("#grid").data('kendoGrid');
var arrows = [38,40];
var navrow_uid; ** add this tracking variable;
data.table.on("keydown", function (e) {
if (arrows.indexOf(e.keyCode) >= 0) {
setTimeout(function () {
data.clearSelection();
// break this up
// data.select($("#grid_active_cell").closest("tr"));
// fetch next row uid and compare to tracker
var nextrow = $("#grid_active_cell").closest("tr");
var uid = nextrow.data('uid');
if (navrow_uid == uid ) {
console.log("last navigable row");
data.dataSource.page(1+data.dataSource.page());
// best option here would be to set auto-page flag for databound event handler
} else {
data.select(nextrow);
navrow_uid = uid;
}
},1);
}
});
You will want to add a grid data bound handler, and have that check the aut-page flag to see if you need to select first or last row of page.

Retain expanded rows after databinding Kendo UI grid

This is my first time working with Kendo UI. I have a Kendo UI grid with child nodes. I want to retain the expanded rows after databinding. Right now its getting collapsed after a row is added in the child
I have tried suggestion from here
dataBound: function() {
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
But this expands the first row only.
How to retain rows? What am I missing?
Codepen
After a lot of playing around with your code example in CodePen, I believe I've come up with an elegant solution that works.
Having worked with Kendo UI for over three years, I've become pretty familiar with some of its inner workings. As such, I'm going to take advantage of one of these - the data-uid attribute. Kendo UI puts these on all <tr> elements in its grid. I chose this attribute because I know that when we call grid.expandRow() we're going to need to fashion a valid jQuery selector to pass in as a parameter. This eliminates the need for us to add our own attributes or classes and the code to handle them.
First, we need to define a variable to hold our row reference. We'll call it expandedRowUid. To set its value, we hook into the detailExpand event of the grid. So, when the user expands a row, we store its data-uid number.
var expandedRowUid;
var grid = $('#grid').kendoGird({
// ...
detailExpand: function(e) {
expandedRowUid = e.masterRow.data('uid');
}
});
Then, whenever a change is made that causes the master grid to re-bind to its data, we hook into the dataBound event of the grid and re-expand the row that has a data-uid equal to the one stored in expandedRowUid.
var grid = $('#grid').kendoGird({
// ...
detailExpand: function(e) {
expandedRowUid = e.masterRow.data('uid');
},
dataBound: function() {
this.expandRow($('tr[data-uid=' + expandedRowUid + ']'));
}
});
Here is the working CodePen example.
NOTE: This will only re-expand the last row that was expanded before the data bind is triggered. So, if you expand rows 4, 5, and 2 in that order, and then trigger a data bind, only row 2 will be re-expanded. You can obviously extend this functionality to handle use cases like that though.
GridDetailExpand: function (e) {
var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
var data = grid.dataItem(e.masterRow);
addToArray(expandedRows, data.UniqueIdOfYourDataInGrid);
},
GridDetailCollapse: function (e) {
var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
var data = grid.dataItem(e.masterRow);
removeFromArray(expandedRows, data.UniqueIdOfYourDataInGrid);
}
And then on databound
var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
$.each(grid.tbody.find('tr.k-master-row'), function () {
var data = grid.dataItem(this);
if (isInArray(expandedRows, data.UniqueIdOfYourDataInGrid)) {
grid.expandRow(this);
}
});
Functions required:
var expandedRows = [];
function addToArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) return;
}
arr.push(value);
}
function removeFromArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) {
delete arr[i];
return;
}
}
}
function isInArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) return true;
}
return false;
}
Hope this helps ... took me a while to figure it out...
Solution for Retaining Last Expanding row in the parent grid after records added in the child grid get refreshed.
detailInit: function (e) {
//Get Parent Grid Last expanded Row index
lastRowIndex = $(e.masterRow).index(".k-master-row");
},
dataBound: function () {
//Check any parent grid row is expanded based on row index
if (lastRowIndex != null && lastRowIndex != undefined){
//find the Grid row details based on row index
var row = $(this.tbody).find("tr.k-master-row:eq(" + lastRowIndex + ")");
//If expand Row exists then it will expanded
this.expandRow(row);
}
else {
//None of the Parent Grid row is expanded then,default First row is expanded
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
}

Filtering crossfilter dimension using dropdown

I am trying to filter my row chart by selecting values in a dropdown.
I do this by creating a dimension and applying a filter to that dimension based on selected values in the dropdown.
The row chart has to display average values, to do this I created ReduceAdd/Remove/Initial functions.
The average values are working as intended.
However, when I filter my dimension used for the dropdown, it seems to add duplicate values to my row chart.
Example code: http://jsfiddle.net/sy9xA/4/
var dropDownFilterDimension;
function ReduceAdd(p, v) {
var value = v.value;
++p.countAvg;
p.totalAvg += value;
return p;
}
function ReduceRemove(p, v) {
var value = v.value
--p.countAvg;
p.totalAvg -= value;
return p;
}
function ReduceInitial() {
return {countAvg: 0, totalAvg: 0};
}
function filterDropdown(dropDownID){
dropDown = document.getElementById(dropDownID);
dropDownFilterDimension.filterAll();
values = $(dropDown).val();
if( values != null ){
dropDownFilterDimension.filter(function(d) { if (values.indexOf(d) > -1) {return d;} });
}
dc.redrawAll();
}
Here for example, when "banana" is selected for filtering. ReduceRemove is called for all non selected values, but in addition ReduceAdd is called for banana (even though it is already in it).
So now when after selecting banana, apple is selected. Banana still has some value.
Can someone explain why this is happening? Or how i can avoid this from happening?
Thanks in advance!
Robert
I don't have fully understand what you are doing also because the jsfddle doesn't show nothing more than the js.
I can tell how I do:
you have a dimension associated to a dc chart (ex chartDim)
you have a group that calculate the average associated to a dc chart (ex averageGroup)
you have a dropdown with a set of values to be use as filter (#myDropDown)
d3.select('#myDropDown')
.on('change', function(){
chartDim.filter(this.value)
dc.redrawAll();
})
the call of dc.redrawAll() will update not only the chart but also the averageGroup and everything should go fine. If the dropDown has is own dimension just filter this one instead of the chartDim

Assigning functions to multiple slickgrids

Please help to solve this very annoying problem. I am using a for loop to iterate over an array of data and create multiple grids. It is working well but the filter function is not binding properly (it only binds to the LAST grid created) Here is the code:
// this function iterates over the data to build the grids
function buildTables() {
// "domain" contains the dataset array
for (i = 0; i < domains.length; i++) {
var dataView;
dataView = new Slick.Data.DataView();
var d = domains[i];
grid = new Slick.Grid('#' + d.name, dataView, d.columns, grids.options);
var data = d.data;
// create a column filter collection for each grid - this works fine
var columnFilters = columnFilters[d.name];
// this seems to be working just fine
// Chrome console confirms it is is processed when rendering the filters
grid.onHeaderRowCellRendered.subscribe(function (e, args) {
$(args.node).empty();
$("<input type='text'>")
.data("columnId", args.column.id)
.val(columnFilters[args.column.id])
.appendTo(args.node);
});
// respond to changes in filter inputs
$(grid.getHeaderRow()).delegate(":input", "change keyup", function (e) {
var columnID = $(this).data("columnId");
if (columnID != null) {
// this works fine - when the user enters text into the input - it
// adds the filter term to the filter obj appropriately
// I have tested this extensively and it works appropriately on
// all grids (ie each grid has a distinct columnFilters object
var gridID = $(this).parents('.grid').attr('id');
columnFilters[gridID][columnID] = $.trim($(this).val());
dataView.refresh();
}
});
//##### FAIL #####
// this is where things seem to go wrong
// The row item always provides data from the LAST grid populated!!
// For example, if I have three grids, and I enter a filter term for
// grids 1 or 2 or 3 the row item below always belongs to grid 3!!
function filter(row) {
var gridID = $(this).parents('.grid').attr('id');
for (var columnId in grids.columnFilters[gridID]) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
var header = grid.getColumns()[grid.getColumnIndex(columnId)];
//console.log(header.name);
}
}
return true;
}
grid.init();
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(filter); // does it matter than I only have one dataView instance?
dataView.endUpdate();
grid.invalidate();
grid.render();
In summary, each function seems to be binding appropriately to each grid except for the filter function. When I enter a filter term into ANY grid, it returns the rows from the last grid only.
I have spent several hours trying to find the fault but have to admit defeat. Any help would be most appreciated.
yes, it matters that you have only one instance of dataView. and also sooner or later you will come up to the fact that one variable for all grids is also a bad idea
so add a var dataView to your loop, it should solve the problem

How to get a jqGrid cell value when editing

How to get a jqGrid cell value when in-line editing (getcell and getRowData returns the cell content and not the actuall value of the input element).
General function to get value of cell with given row id and cell id
Create in your js code function:
function getCellValue(rowId, cellId) {
var cell = jQuery('#' + rowId + '_' + cellId);
var val = cell.val();
return val;
}
Example of use:
var clientId = getCellValue(15, 'clientId');
Dodgy, but works.
Here is an example of basic solution with a user function.
ondblClickRow: function(rowid) {
var cont = $('#grid').getCell(rowid, 'MyCol');
var val = getCellValue(cont);
}
...
function getCellValue(content) {
var k1 = content.indexOf(' value=', 0);
var k2 = content.indexOf(' name=', k1);
var val = '';
if (k1 > 0) {
val = content.substr(k1 + 7, k2 - k1 - 6);
}
return val;
}
After many hours grief I found this to be the simplest solution. Call this before fetching the row data:
$('#yourgrid').jqGrid("editCell", 0, 0, false);
It will save any current edit and will not throw if there are no rows in the grid.
As you stated, according to the jqGrid documentation for getCell and getRowData:
Do not use this method when you editing the row or cell. This will return the cell content and not the actual value of the input element
Since neither of these methods will return your data directly, you would have to use them to return the cell content itself and then parse it, perhaps using jQuery. It would be nice if a future version of jqGrid could provide a means to do some of this parsing itself, and/or provide an API to make it more straightforward. But on the other hand is this really a use case that comes up that often?
Alternatively, if you can explain your original problem in more detail there may be other options.
Try this, it will give you particular column's value
onSelectRow: function(id) {
var rowData = jQuery(this).getRowData(id);
var temp= rowData['name'];//replace name with you column
alert(temp);
}
Basically, you have to save the row before you access the cell contents.
If you do, then you get the value for the cell instead of the markup that comes when the cell is in edit mode.
jQuery.each(selectedRows, function(index, foodId) {
// save the row on the grid in 'client array', I.E. without a server post
$("#favoritesTable").saveRow(foodId, false, 'clientArray');
// longhand, get grid row based on the id
var gridRow = $("#favoritesTable").getRowData(foodId);
// reference the value from the editable cell
foodData += foodId + ":" + gridRow['ServingsConsumed'] + ',';
});
Hi, I met this problem too. Finally I solved this problem by jQuery. But the answer is related to the grid itself, not a common one. Hope it helps.
My solution like this:
var userIDContent = $("#grid").getCell(id,"userID"); // Use getCell to get the content
//alert("userID:" +userID); // you can see the content here.
//Use jQuery to create this element and then get the required value.
var userID = $(userIDContent).val(); // var userID = $(userIDContent).attr('attrName');
you can use this directly....
onCellSelect: function(rowid,iCol,cellcontent,e) {
alert(cellcontent);
}
This is my solution:
function getDataLine(grida, rowid){ //vykradeno z inineeditu a vohackovano
if(grida.lastIndexOf("#", 0) === 0){
grida = $(grida);
}else{
grida = $("#"+grida);
}
var nm, tmp={}, tmp2={}, tmp3= {}, editable, fr, cv, ind;
ind = grida.jqGrid("getInd",rowid,true);
if(ind === false) {return success;}
editable = $(ind).attr("editable");
if (editable==="1") {
var cm;
var colModel = grida.jqGrid("getGridParam","colModel") ;
$("td",ind).each(function(i) {
// cm = $('#mygrid').p.colModel[i];
cm = colModel[i];
nm = cm.name;
if ( nm != 'cb' && nm != 'subgrid' && cm.editable===true && nm != 'rn' && !$(this).hasClass('not-editable-cell')) {
switch (cm.edittype) {
case "checkbox":
var cbv = ["Yes","No"];
if(cm.editoptions ) {
cbv = cm.editoptions.value.split(":");
}
tmp[nm]= $("input",this).is(":checked") ? cbv[0] : cbv[1];
break;
case 'text':
case 'password':
case 'textarea':
case "button" :
tmp[nm]=$("input, textarea",this).val();
break;
case 'select':
if(!cm.editoptions.multiple) {
tmp[nm] = $("select option:selected",this).val();
tmp2[nm] = $("select option:selected", this).text();
} else {
var sel = $("select",this), selectedText = [];
tmp[nm] = $(sel).val();
if(tmp[nm]) { tmp[nm]= tmp[nm].join(","); } else { tmp[nm] =""; }
$("select option:selected",this).each(
function(i,selected){
selectedText[i] = $(selected).text();
}
);
tmp2[nm] = selectedText.join(",");
}
if(cm.formatter && cm.formatter == 'select') { tmp2={}; }
break;
}
}
});
}
return tmp;
}
I have a solution:
1. Using this.value to get the current editing value in the editing row.
2. Save the cell value to a hidden field when the cell lost its focus.
3. Read the hidden field when you need.
The code:
colModel="[
{ name: 'Net', index: 'Net', editable:true, editoptions: { dataEvents: [ { type: 'focusout', fn: function(e) {$('#HiddenNet').val(this.value);} }] }, editrules:{custom:true,}},
{ name: 'Tax', index: 'Tax', editable:true, editoptions: { dataEvents: [ { type: 'focus', fn: function(e) {this.value=$('#HiddenNet').val(); } }] }, editrules:{custom:true}}
]"
Good Luck
You can get it from the following way...!!
var rowId =$("#list").jqGrid('getGridParam','selrow');
var rowData = jQuery("#list").getRowData(rowId);
var colData = rowData['UserId']; // perticuler Column name of jqgrid that you want to access
In my case the contents of my cell is HTML as result of a formatter. I want the value inside anchor tag. By fetching the cell contents and then creating an element out of the html via jQuery I am able to then access the raw value by calling .text() on my newly created element.
var cellContents = grid.getCell(rowid, 'ColNameHere');
console.log($(cellContents));
//in my case logs <h3>The Value I'm After</h3>
var cellRawValue = $(cellContents).text();
console.log(cellRawValue); //outputs "The Value I'm After!"
my answer is based on #LLQ answer, but since in my case my cellContents isn't an input I needed to use .text() instead of .val() to access the raw value so I thought I'd post this in case anyone else is looking for a way to access the raw value of a formatted jqGrid cell.
its very simple write code in you grid.php and pass the value to an other page.php
in this way you can get other column cell vaue
but any one can make a like window.open(path to pass value....) in fancy box or clor box?
$custom = <<<CUSTOM
jQuery("#getselected").click(function(){
var selr = jQuery('#grid').jqGrid('getGridParam','selrow');
var kelr = jQuery('#grid').jqGrid('getCell', selr, 'stu_regno');
var belr = jQuery('#grid').jqGrid('getCell', selr, 'stu_school');
if(selr)
window.open('editcustomer.php?id='+(selr), '_Self');
else alert("No selected row");
return false;
});
CUSTOM;
$grid->setJSCode($custom);
I think an extension of this would get it for you.
retrieving-original-row-data-from-jqgrid
I think a better solution than using getCell which as you know returns some html when in edit mode is to use jquery to access the fields directly. The problem with trying to parse like you are doing is that it will only work for input fields (not things like select), and it won't work if you have done some customizations to the input fields. The following will work with inputs and select elements and is only one line of code.
ondblClickRow: function(rowid) {
var val = $('#' + rowid + '_MyCol').val();
}
I've got a rather indirect way. Your data should have an unique id.
First, setting a formatter
$.extend(true, $.fn.fmatter, {
numdata: function(cellvalue, options, rowdata){
return '<span class="numData" data-num="'+rowdata.num+'">'+rowdata.num+'</span>';
}
});
Use this formatter in ColModel. To retrieve ID (e.g. selected row)
var grid = $("#grid"),
rowId = grid.getGridPara('selrow'),
num = grid.find("#"+rowId+" span.numData").attr("data-num");
(or you can directly use .data() for latest jquery 1.4.4)
In order to get the cell value when in-line editing you need to capture this event(or another similar event, check documentation):
beforeSaveCell: function (rowid, celname, value, iRow, iCol) { }
In the value parameter you have the 'value' of the cell that was currently edited.
To get the the rest of the values in the row use getRowData()
I lost a lot of time with this, hope this helps.
My workaround is to attach an object containing orignal values to each tr element in the grid. I've used afterAddRecord callback to get my hands on the values before jqGrid throws them away and jQuery's "data" method to store them in the work.
Example:
afterInsertRow: function( rowid, rowdata, rowelem ) {
var tr = $("#"+rowid);
$(tr).data("jqgrid.record_data", rowelem);
},
“rowelem” is the array of cell values from our JSON data feed or [jsonReader] (http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#jsonreader_as_function)
Then at any point I can fetch those attributes using:
$(tr).data(“jqgrid.record_data”).
More at: http://wojciech.oxos.pl/post/9423083837/fetching-original-record-values-in-jqgrid
I think that Aidan's answer is by far the best.
$('#yourgrid').jqGrid("editCell", 0, 0, false);
This commits any current edits, giving you access to the real value. I prefer it because:
You don't have to hard-code any cell references in.
It is particularly well suited to using getRowData() to get the entire grid, as it doesn't care which cell you've just been editing.
You're not trying to parse some markup generated by jqGrid which may change in future.
If the user is saving, then ending the edit session is likely the behaviour they would want anyway.
Before i was getting :
html tag of the textbox something like
but Here is the solution to get the value from that particular column, working and tested
function getValue(rowId, cellId) {
var val = $("[rowId='"+rowId+"'][name='"+cellId+"']").val();
return val;
}
var values = getValue(rowId, 'cellid');
I obtain edit value using javascript:
document.getElementById('idCell').value
I hope this info useful for someone.
I needed the original value before the formatter, so this is what I did:
{
name: 'Slot', title: false, formatter: function (cellValue, options, rowObject) {
rowObject['SlotID'] = cellValue; // <--- This saves the original ID
if (somelogic) {
return someString;
} else {
return someOtherString;
}
}
},
{ name: 'SlotID', hidden: true }
Now SlotID contains the original ID. Also, you don't need to have SlotID property on your original model.
try subscribing to afterEditCell event it will receive (rowid, cellname, value, iRow, iCol) where value is your a new value of your cell
You can use getCol to get the column values as an array then index into it by the row you are interested in.
var col = $('#grid').jqGrid('getCol', 'Sales', false);
var val = col[row];

Resources