I have a checkbox column in my JqGrid which get loaded from DB, so it is either checked or not checked when it is loaded.
What i want is : If checkbox is being checked or uncheked by user i want to update DB in at same. I dont want user to press enter or anything. only 1 click and send action to DB
name: 'Aktiv', index: 'Aktiv', width: 100, edittype: 'checkbox', align: 'center',formatter: "checkbox", editable: true, formatoptions: {disabled : false}
You can set a click event handler inside of loadComplete:
loadComplete: function () {
var iCol = getColumnIndexByName ($(this), 'Aktiv'), rows = this.rows, i,
c = rows.length;
for (i = 1; i < c; i += 1) {
$(rows[i].cells[iCol]).click(function (e) {
var id = $(e.target).closest('tr')[0].id,
isChecked = $(e.target).is(':checked');
alert('clicked on the checkbox in the row with id=' + id +
'\nNow the checkbox is ' +
(isChecked? 'checked': 'not checked'));
});
}
}
where
var getColumnIndexByName = function(grid, columnName) {
var cm = grid.jqGrid('getGridParam', 'colModel'), i, l;
for (i = 1, l = cm.length; i < l; i += 1) {
if (cm[i].name === columnName) {
return i; // return the index
}
}
return -1;
};
Instead of the alert you should use jQuery.ajax to send information to the server about updating the checkbox state.
You can see a demo here.
A small correction in the loadComplete: function().
in the demo you can find that even after the checkbox is checked, if you click outside the checkbox in that cell, the value gets changed to 'false' from 'true'.
To avoid this, just give the focus exactly on the checkbox alone by doing the following.
for (i = 1; i < c; i += 1) {
$(('input[type="checkbox"]'),rows[i].cells[iCol]).click(function (e) {
var id = $(e.target).closest('tr')[0].id,
isChecked = $(e.target).is(':checked');
alert('clicked on the checkbox in the row with id=' + id +
'\nNow the checkbox is ' +
(isChecked? 'checked': 'not checked'));
});
}
and thanks for the answer :-) (#Oleg) helped me a lot..in time of course.. ;)
To change values of other column based on click of checkbox
var weightedAvgPriceIndex = getColumnIndexByName($(this), 'WeightedAveragePrice'),
rows = this.rows,
i,
c = rows.length;
for (i = 1; i < c; i += 1) {
$(('input[type="checkbox"]'),rows[i].cells[iCol]).click(function (e) {
var id = $(e.target).closest('tr')[0].id;
isChecked = $(e.target).is(':checked');
var x = $('#' + id + ' td:eq(' + weightedAvgPriceIndex + ')').text();
$('#' + id + ' td:eq(' + weightedAvgPriceIndex + ')').text(Math.abs(x) + 10);
});
}
Related
I created a jq-grid with one column is a drop down. When I click on the cell it gets enabled with first data of the drop down data. I need to click again to show the full array of the drop down and select the correct data. Is there anyway I can open the dropdown in the first click itself.
I am using jqgrid 5.2 paid version.
colModel: [
{ name: 'UserSelection', index: 'UserSelection', width: 180, align: "left", editable: true, edittype: "select" }
}
loadComplete: function () {
jQuery("#jqgItemDetailsIssue").setColProp('UserSelection', {
editoptions: {
dataUrl: 'CopyofItemInquirySubmitIssue.aspx/fillUserSelection', cacheUrlData: true,
buildSelect: function (Result) {
var response = $.parseJSON(Result.d);
var s = '<select>';
if (response && response.Table1.length) {
for (var i = 0, l = response.Table1.length; i < l; i++) {
var ri = response.Table1[i];
s += '<option value="' + ri.Issue_ID + '" >' + ri.Issue_Type + '</option>';
}
I am using the open source version of handsontable (version 0.29.2). I created a custom renderer that creates a hidden SPAN element/icon on every row. When input fails validation, I use jQuery to programmatically unhide/show the SPAN tag/icon so that it appears in the right-hand side of the cell. It works great, but unfortunately when I enter an invalid value into another cell, the icon from the first cell disappears. The preferred behavior is to have all of the icons visible in cells where a validation issue exists.
Question: Is there a way to keep all of the icons visible?
If this is not possible, is there a different way in handsontable to display an image after validation? As you can see from the code below (and my jsfiddle example), I am not using the built-in handsontable validation hooks. With the built-in validation, I can't add an icon like I want - I can only override the default style of an invalid cell by using invalidCellClassName.
I have created a simple example with instructions demonstrating my issue:
http://jsfiddle.net/4g3a5kqc/15/
var data = [
["1", "abc"],
["2", "def"],
["3", "ghi"],
["4", "jkl"]
],
container = document.getElementById("example"),
hot1;
// This function is a custom renderer that creates a hidden SPAN element/
// icon. In this example, when a user changes the value, the SPAN element
// icon will appear.
function customRenderer(instance, td, row, col, prop, value, cellProperties) {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer; display: none;"></span>';
}
var hot1 = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
cells:
function (row, col, prop) {
var cellProperties = {};
if (col == 0) {
cellProperties.renderer = customRenderer;
}
return cellProperties;
}
});
hot1.addHook('afterChange', afterChange);
// Show the SPAN tag with the icon
// in the right-hand side of the cell.
function afterChange(changes, source) {
console.log(changes, source);
if (source == 'edit' || source == 'autofill') {
$.each(changes,
function (index, element) {
var change = element;
var rowIndex = change[0];
var columnIndex = change[1];
var oldValue = change[2];
var newValue = change[3];
console.log(oldValue, newValue, rowIndex, columnIndex, change);
if (columnIndex != 0) {
return;
}
if (newValue >= 0) {
return;
}
var cellProperties = hot1.getCellMeta(rowIndex, hot1.propToCol(columnIndex));
var td = hot1.getCell(rowIndex, columnIndex, true);
var span = td.getElementsByTagName("span");
$("#" + span[0].id).show();
});
}
}
Due to customRenderer() being called after every change we have to store somewhere cells with spans visible and check for it at the rendering. On the other hand if the span should not be visible (input is valid) we need to remove it from the array of cells wit visible spans. Working fiddle:
http://jsfiddle.net/8vdwznLs/
var data = [
["1", "abc"],
["2", "def"],
["3", "ghi"],
["4", "jkl"]
],
container = document.getElementById("example"),
hot1,
visibleSpans = [];
// This function is a custom renderer that creates a hidden SPAN element/
// icon. In this example, when a user changes the value, the SPAN element
// icon will appear.
function customRenderer(instance, td, row, col, prop, value, cellProperties) {
if (visibleSpans.indexOf(td) > -1) {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer;"></span>';
} else {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer; display: none;"></span>';
}
}
var hot1 = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
cells:
function (row, col, prop) {
var cellProperties = {};
if (col == 0) {
cellProperties.renderer = customRenderer;
}
return cellProperties;
}
});
hot1.addHook('afterChange', afterChange);
// Show the SPAN tag with the icon
// in the right-hand side of the cell.
function afterChange(changes, source) {
console.log(changes, source);
if (source == 'edit' || source == 'autofill') {
$.each(changes,
function (index, element) {
var change = element;
var rowIndex = change[0];
var columnIndex = change[1];
var oldValue = change[2];
var newValue = change[3];
var td = hot1.getCell(rowIndex, columnIndex, true);
console.log(oldValue, newValue, rowIndex, columnIndex, change);
if (columnIndex != 0) {
return;
}
if (newValue >= 0) {
var indexOfSpan = visibleSpans.indexOf(td);
if (indexOfSpan > -1) {
visibleSpans.splice(indexOfSpan, 1);
hot1.render();
return;
}
return;
}
var cellProperties = hot1.getCellMeta(rowIndex, hot1.propToCol(columnIndex));
visibleSpans.push(td);
var span = td.getElementsByTagName("span");
span[0].setAttribute('style', '');
});
}
}
I populate the table with an ajax call. In the first column I have checkboxes for selecting and deselecting rows and submit data to a php script. I have also two columns with select fields.
The render function for the one (of the two) column with select:
{
targets: 6,
render: function(data, type, full, meta) {
if(data.length == 4) {
return '<select class="form-control" id="selectotpionmonths' + data[0].cataloguenumber + '"><option value="'+ data[3].months
+ '">' + data[3].months + '<option value="'+ data[2].months
+ '">' + data[2].months + '<option value="'+ data[1].months
+ '">' + data[1].months + '<option value="'+ data[0].months
+ '">' + data[0].months + '</select>';
} else {
return data[0].months;
}
}
},
And the handler for click event and on change event:
$('#results tbody').on('click', 'input[type="checkbox"]', function(e){
var $row = $(this).closest('tr');
// Get row data
var data = table.row($row).data();
$('#selectotpionmonths' + data['enc_unit']).change(function(){
e.preventDefault();
var selectedoptionformonths = $('#selectotpionmonths' + data['enc_unit']).find("option:selected").text();
if(selectedoptionformonths == 3) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][3].price + '"]').prop('selected', true);
} else if(selectedoptionformonths == 6) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][2].price + '"]').prop('selected', true);
} else if(selectedoptionformonths == 9) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][1].price + '"]').prop('selected', true);
} else if(selectedoptionformonths == 12) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][0].price + '"]').prop('selected', true);
}
});
if(data['price_numberofmonths'].length == 4) {
var monthsoption = $('#selectotpionmonths' + data['enc_unit']).find("option:selected").text();
var priceoption = $('#selectoptionprice' + data['enc_unit']).find("option:selected").text();
} else {
var monthsoption = data['price_numberofmonths'][0].months;
var priceoption = data['price_rrp'][0].price;
}
// Get row ID
var dataforserver = {name: data['enc_unit'], duration: monthsoption, price: priceoption};
var rowId = dataforserver.name;
// Determine whether row ID is in the list of selected row IDs
var index = $.inArray(rowId, rows_selected);
// If checkbox is checked and row ID is not in list of selected row IDs
if(this.checked && index === -1){
rows_selected.push(rowId);
units_selected.push(dataforserver);
// Otherwise, if checkbox is not checked and row ID is in list of selected row IDs
} else if (!this.checked && index !== -1){
rows_selected.splice(index, 1);
units_selected.splice(index, 1);
}
if(this.checked){
$row.addClass('selected');
} else {
$row.removeClass('selected');
}
order_total = 0;
for(i=0; i < units_selected.length; i++) {
order_total += parseFloat(units_selected[i].price);
}
//console.log(order_total.toFixed(2));
$( "#ukhoanswer" ).html(
"Number of units selected: " + units_selected.length + "<br/>" +
"Total cost of order: " + order_total.toFixed(2)
);
// Update state of "Select all" control
updateDataTableSelectAllCtrl(table);
// Prevent click event from propagating to parent
e.stopPropagation();
});
// Handle click on table cells with checkboxes
$('#results').on('click', 'tbody td, thead th:first-child', function(e){
$(this).parent().find('input[type="checkbox"]').trigger('click');
});
// Handle click on "Select all" control
$('thead input[name="select_all"]', table.table().container()).on('click', function(e){
if(this.checked){
$('#results tbody input[type="checkbox"]:not(:checked)').trigger('click');
} else {
$('#results tbody input[type="checkbox"]:checked').trigger('click');
}
// Prevent click event from propagating to parent
e.stopPropagation();
});
You may view the initial code for the checkboxes here
When I click on the cell with the select field I want to prevent the click event on the row. I have tried adding e.preventDefault but with no success. For the columns with the select option I want only the change event to be triggered.
Any ideas?
I did the following:
var selectField = $('.form-control');
selectField.on('click', function(event) {
event.stopPropagation();
});
The selector are for the cells with the select options. Now the first time that I click on the select field the row is selected. But next time I select an option the click event is prevented and the row is not selected/deselected.
I am looking on how to prevent the row being selected on the first click on a select field.
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 have a jqGrid where i have a column with delete hyperlinks for each row, i just cant manke hyperlink to make an action like onclick=\"jQuery('#list').deleteRow('" + cl + "'); when i used simple button
{ name: 'act', index: 'act', width: 100, align: 'center', sortable: false}],
gridComplete: function () {
var gr = jQuery('#list'); gr.setGridHeight("auto", true);
var ids = jQuery("#list").jqGrid('getDataIDs');
for (var i = 0; i < ids.length; i++) {
var cl = ids[i];
be = "<a href style='height:25px;width:120px;' type='button' title='Slet' onclick=\"jQuery('#list').jqGrid('delGridRow','" + cl + "',{reloadAfterSubmit:false, url:'#Url.Action("deleteRow")'});\" >Slet</>";
jQuery("#list").jqGrid('setRowData', ids[i], { act: be });
}
}
It I understand you correct you should
add some value to href attribute. For example href='#'.
You should insert return false; at the end of the code of onclick function. It will prevent default <a> behavior.