I'm having a problem with my jqGrid.
It is using local data
It is setup to allow inline (cell editing)
When I delete a row (locally only) using the delRowData method, the row is deleted as expected. However when I delete a couple of rows, the inline cell editing seems to stop working.
When this happens I don't see any errors in the chrome debug window. I've setup a fiddle here
Here is the grid definition
$("#grid").jqGrid({
datatype: "local",
height: 250,
colNames: ['Inv No', 'Thingy', 'Blank', 'Number', 'Status'],
colModel: [{
name: 'id',
index: 'id',
width: 60,
sorttype: "int",
editable : false
}, {
name: 'thingy',
index: 'thingy',
width: 90,
sorttype: "date",
editable : true,
edittype : 'text'
}, {
name: 'blank',
index: 'blank',
width: 30,
editable : true,
edittype : 'text'
}, {
name: 'number',
index: 'number',
width: 80,
sorttype: "float",
editable : true,
edittype : 'text'
}, {
name: 'status',
index: 'status',
width: 80,
sorttype: "float",
editable : true,
edittype : 'text'
}],
caption: "Stack Overflow Example",
cellEdit : true,
cellsubmit : 'clientArray'
});
Here is my delete method. I've made it as simple as I can. It just always deletes the first row.
function deleteRow() {
var ids = $("#grid").jqGrid('getDataIDs');
$("#grid").jqGrid('delRowData', ids[0]);
}
The problem is the following: cell editing of jqGrid are written so that it works mostly with row indexes (see here) instead of rowids. Some internal structures of jqGrid (savedRows and iRow options) and the id of editable cell will be assigned with the value which constructed based on the index of editable row. So after deleting of a row in the grid the information need be updated.
I modified your jsfiddle demo to the following: http://jsfiddle.net/OlegKi/wdwdxLuk/14/. It uses the following code of deleteRow called if one clicks on the button "Delete the first Row of the grid":
function deleteRow() {
var $grid = $("#grid"), editingTr, rows, iRow, editingColumnName,
p = $grid.jqGrid("getGridParam"), // get reference to object with jqGrid options
savedRows = p.savedRow, //{id:iRow, ic:iCol, name:nm, v:cellData};
colModel = p.colModel;
if ($grid.length > 0 && $grid[0].rows.length > 1) {
rows = $grid[0].rows;
editingTr = savedRows.length > 0 ? rows[savedRows[0].id] : undefined;
// delete the row
$("#grid").jqGrid('delRowData', rows[1].id); // delete the first row (rows[0] don't contains any data)
if (editingTr !== undefined) {
// update the index of the editing row
iRow = editingTr.rowIndex;
if (iRow < 0) {
// editing row way deleted from the grid
p.savedRow = [];
delete p.iRow;
delete p.iCol;
} else {
// update the row index in savedRows
editingColumnName = colModel[savedRows[0].ic].name;
$(editingTr).find("#" + savedRows[0].id + "_" + $.jgrid.jqID(editingColumnName))
.attr("id", iRow + "_" + editingColumnName);
savedRows[0].id = iRow;
// update row index of selected row
p.iRow = iRow;
}
}
}
}
Related
Trying to find an answer to remove a row for dojo EnhancedGrid based on the row index.
Please find the EnhancedGrid.
var dataStore = new ObjectStore({objectStore: objectStoreMemory});
// grid
grid = new EnhancedGrid({
selectable: true,
store: dataStore,
structure : [ {
name : "Country",
field : "Country",
width : "150px",
reorderable: false,
editable : true
}, {
name : "Abbreviation",
field : "Abbreviation",
width : "120px",
reorderable: false,
editable : true
}, {
name : "Capital",
field : "Capital",
width : "100%",
reorderable: false,
editable : true
}, {
label: "",
field: "Delete",
formatter: deleteButton
}],
rowSelector: '20px',
plugins: {
pagination: {
pageSizes: ["10", "25", "50", "100"],
description: true,
sizeSwitch: true,
pageStepper: true,
gotoButton: true,
maxPageStep: 5,
position: "bottom"
}
}
}, "grid");
grid.startup();
And the Delete Button Script is here:
function deleteButton(id) {
var dBtn1 = "<div data-dojo-type='dijit/form/Button'>";
var dBtn2 = "<img src='delete.png' onclick='javascript:removeItem()' alt='" + id + "'";
dBtn = dBtn1 + dBtn2 + " width='18' height='18'></div>";
return dBtn;
}
Here is my Question: Each row will have a delete button at the end, On click of this button the same row should be deleted.
Can anybody tell me how to delete a row based on row index?
If you want to add (remove) data programmatically, you just have to
add (remove) it from the underlying data store. Since DataGrid is
“DataStoreAware”, changes made to the store will be reflected
automatically in the DataGrid.
https://dojotoolkit.org/reference-guide/1.10/dojox/grid/example_Adding_and_deleting_data.html
dojox/grid has a property selection and method getSelected() to get selected items. In example from documentation it's implemented in following way:
var items = grid5.selection.getSelected();
if(items.length){
// Iterate through the list of selected items.
// The current item is available in the variable
// "selectedItem" within the following function:
dojo.forEach(items, function(selectedItem){
if(selectedItem !== null){
// Delete the item from the data store:
store3.deleteItem(selectedItem);
} // end if
}); // end forEach
} // end if
Hope it will help.
Here is the solution. The sequence of methods that will run onClick of a button are removeItem() and onRowClick event
1> Set the "deleteButtonFlag" on click of a button.
function removeItem() {
deleteButtonGFlag = true;
}
2> Remove item
dojo.connect(grid, "onRowClick", function(e) {
if (deleteButtonGFlag) {
dataStore.fetch({
query: {},
onComplete: function(items) {
var item = items[e.rowIndex];
dataStore.deleteItem(item);
dataStore.save();
deleteButtonGFlag = false;
}
});
}
});
My JQGrid cloumns like,
colNames: ['Job ID', 'MailId','Save'],
colModel: [
{ name: 'JobId', index: 'JobId', width: 120, align: 'left', editable: true },
{ name: 'MailId', index: 'MailId', width: 150, align: 'left', editable: true },
{
name: 'Save', index: 'Save', width: 100, sortable: false,
formatter: function (cellvalue, options, rowObject) {
return "Save";
}
}
I create the Save link button at the end of JQGrid cell.
I need to pass clicked row's JobId and MailID to jquery function when click the link button in a row.How to do this?
In the above example you have given, the rowObject parameter in the formatter function will hold all the values in that row. So can use rowObject.JobId for your JobId and rowObject.MailId for your MailId.
I would recommend you to use beforeSelectRow (or onCellSelect) to detect click on <a> in the "Save" column. The answer explains what you can do. Another answers: this one and this one could be also interesting for you.
In your case beforeSelectRow could looks like below
beforeSelectRow: function (rowid, e) {
var $self = $(this),
iCol = $.jgrid.getCellIndex($(e.target).closest("td")[0]),
cm = $self.jqGrid("getGridParam", "colModel");
if (cm[iCol].name !== "Save") {
return true;
}
alert ($self.jqGrid("getCell", rowid, "JobId"));
return false;
}
Additionally you should consider which value you use as id in the input data. The value build so name rowid - the value of id attributes of <tr> elements (the rows of the grid). If for example either JobId or MailId (one from the two columns) contains unique values for every row then you can use the value from the column as the rowid. To do this you need just add key: true to the corresponding column.
I have a function that grabs the cell text values from a flexigrid where a checkbox has been checked. But I am having a problem. When I click on the master checkbox(doesnt contain any text values as it is displayed with the column titles) it craps out because of the master checkbox.
This is the error I get: Uncaught Error: Syntax error, unrecognized expression: #
Here is my function that grabs the Event Date from the Flexigrid:
function getSelectedCopyDates() {
var arr = new Array();
//for every row that has a checked checkbox
$("tr").has(".noteCheckBox:checked").each(function (i) {
//push the value of column(FName, LName) into the array
arr.push($("#" + this.id + "> td[abbr='EventDate'] > div").text());
}
});
return arr;
}
And here is a snippet of my flexigrid:
$('#viewNotesGrid').flexigrid({
url: url,
dataType: 'json',
method: 'get',
colModel: [
{ display: '<input type="checkbox" class="noteCheckBox" id="checkAllNotes" />', name: 'checkBox', width: 20, sortable: false, align: 'center', process: showDescription },
{ display: 'File ID', name: 'FileID', width: 70, sortable: true, align: 'center', process: showDescription, hide: true },
here is what it looks like:
use $("tr:has(:not('th'))") selector to select tr without master check box row
$("tr:has(:not('th'))").has(".noteCheckBox:checked").each(function (i) {
if ($("tr").has(".checkAllNotes:checked")){
arr.push($("#" + this.id + "> td[abbr='EventDate'] > div").text());
}
});
I have my grid with multiselect = true, something likes this, you can click each checkbox and then delete, when I delete my first row I know the method selarrrow creates and arrays It just delete, but when I want to delete the second row It just never do the delRowData method, and when I select multiple checkbox It just delete the first. I think my method is looping over and over againg each time and never delete at least visually the other row, how can I fix it?? any advise thanks
this is my method:
onSelectRow:function(id) {
$("#mySelect").change(function (){
if(($("#mySelect option:selected").text()) == 'Deleted') {
var id = $("#list2").getGridParam('selarrrow');
for(var i =0; i<id.length;i++) {
$("#list2").jqGrid('delRowData',id[i]);
}
});
}
html
</head>
<body>
<div>
Move to:
<select id="mySelect">
<option value="1">Select and option</option>
<option value="2">Trash</option>
<option value="3">Deleted</option>
</select>
</div>
<table id="list2"></table>
<div id="pager2"></div>
</body>
</html>
js
$("#Inbox").click(function () {
$.post('../../view/inbox.html', function (data) {
$('#panelCenter_1_1').html(data);
$("#list2").jqGrid({
url: '../..controller/controllerShowInbox.php',
datatype: 'json',
colNames: ['From', 'Date', 'Title', 'Message'],
colModel: [
{ display: 'From', name: 'name', width: 50, sortable: true, align: 'left' },
{ display: 'Date', name: 'date', width: 150, sortable: true, align: 'left' },
{ display: 'Title', name: 'title', width: 150, sortable: true, align: 'left' },
{ display: 'Message', name: 'message', width: 150, sortable: true, align: 'left' },
],
searchitems: [
{ display: 'From', name: 'name' },
{ display: 'Date', name: 'date' },
{ display: 'Title', name: 'title' },
{ display: 'Message', name: 'message' },
],
rowNum: 10,
rowList: [10, 20, 30],
pager: '#pager2',
sortname: 'id_usuario',
viewrecords: true,
sortorder: "desc",
caption: "Inbox",
multiselect: true,
multiboxonly: true,
onSelectRow: function (id) {
$("#mySelect").change(function () {
if (($("#mySelect option:selected").text()) == 'Trash') {
var id = $("#list2").getGridParam('selarrrow');
if (id != '') {
var grid = $("#list2");
grid.trigger("reloadGrid");
$.post('../../controller/controllerChangeStatus.php', { id: id }, function (data) {
$('#panelCenter_2_1').html(data);
grid.trigger("reloadGrid");
});
}
} else if (($("#mySelect option:selected").text()) == 'Deleted') {
id = $("#list2").getGridParam('selarrrow');
if (id != '') {
var grid = $("#list2");
grid.trigger("reloadGrid");
$.post('../../controller/controllerChangeStatus.php', { id: id }, function (data) {
$('#panelCenter_2_1').html(data);
grid.trigger("reloadGrid");
});
}
} else {
}
});
}
});
});
});
You code looks very strange for me. I can't explain the effects which you describe without having the demo code, but I could point you to some places in the code which should be rewrote.
First problem: you use id parameter in the line onSelectRow:function(id) and then use the same variable name id to declare var id = $("#list2").getGridParam('selarrrow');. I don't understand why you do this. If you don't need parameter of onSelectRow you can just use onSelectRow:function() which will make the code more clear.
Second problems: you use binding to change event in $("#mySelect").change, but you use the statement inside of another event onSelectRow. So on every row selection you will have one more event handler to the change event. For example you would replace the body of $("#mySelect").change(function (){ to alert("changed!"). Then you would select two different rows and change the option in the "#mySelect". You will see two alerts. Then you select another row and change the option in the "#mySelect". You will see three alerts. And so on.
So you should rewrote your code in any way. If you will still have the same problem you should include full demo code (including HTML code with <select id="mySelect">...) which can be used to reproduce your problem.
I use a different approach. I build a vector of selected row ids and then process 'em with a single batch statemente server side then reload the grid.
More or less the code is.
var righe = $(nomeGrigliaFiglia).getGridParam("selarrrow");
if ((righe == null) || (righe.length == 0)) {
return false;
}
var chiavi = [];
for (var i = 0; i < righe.length; i++) {
var Id = righe[i];
var data = $(nomeGrigliaFiglia).jqGrid('getRowData', Id);
// Process your data in here
chiavi[i] = new Array(2)
chiavi[i][0] = data.FieldKey;
chiavi[i][1] = data.FieldChildId;
}
Note that I'm using this to actually send a int [][] to a C# Action
multiselect: true,
in your data process php $SQL .= "DELETE FROM ". $table. " WHERE no in ($_POST[id]);" ;
Is there a way I can use custom formatter to format the grouptext value in jqgrid.
Current Output for var grouping=new Array("Environment", "System", "IIR","Userlimit","Kernel Parameters");
Suppose I have these groups.
var grouping=new Array("3Environment", "0System", "4IIR","2Userlimit","1Kernel Parameters");
If I sort it in ascending order it should display System, Kernel, Userlimit, Environment, IIR i.e., using some kind of custom formatter remove 01234 from 1st character or similar to sort my groups in some already decided order.
jqGrid Code
$('#compareContent').empty();
$('<div id="compareParentDiv" width="100%">'+
'<table id="list2" cellspacing="0" cellpadding="0"></table>'+
'<div id="gridpager3"></div></div>')
.appendTo('#compareContent');
$("#compareParentDiv").hide();
var gridDiff = $("#list2");
gridDiff.jqGrid({
datastr: compareData,
datatype: "jsonstring",
colNames: ['KeyName', 'SubCategory', starheader, header1,'isEqual'],
colModel: [
{ name: 'elementName', index: 'elementName', key: true, width: 120 },
{ name: 'subCategory', index: 'subCategory', width: 1 },
{ name: 'firstValue', index: 'firstValue', width: 310, jsonmap:'attribute.0.firstValue' },
{ name: 'secondValue', index: 'secondValue', width: 310,jsonmap:'attribute.0.secondValue' },
{ name: 'isEqual', index: 'isEqual', width: 1,hidden:true}
],
pager: '#gridpager3',
rowNum:60,
scrollOffset:1,
//viewrecords: true,
jsonReader: {
repeatitems: false,
page: function(){return 1;},
root: "response"
},
//rownumbers: true,
height: '320',
autowidth:true,
grouping: true,
groupingView: {
groupField: ['subCategory'],
groupOrder: ['desc'],
groupDataSorted : false,
groupColumnShow: [false],
//groupCollapse: true,
groupText: ['<b>{0}</b>']
},
loadComplete: function() {
if (this.p.datatype !== 'local') {
setTimeout(function () {
gridDiff.trigger('reloadGrid');
}, 0);
} else {
$("#compareParentDiv").show();
}
var i, names=this.p.groupingView.sortnames[0], l = names.length;
data = this.p.data, rows = this.rows, item;
for (i=0;i<l;i++) {
if ($.inArray(names[i],grouping) >= 0) {
$(this).jqGrid('groupingToggle',this.id+"ghead_"+i);
$(rows.namedItem(this.id+"ghead_"+i)).find("span.ui-icon").click(function(){
var len = data.length, iRow;
for (iRow=0;iRow<len;iRow++) {
item = data[iRow];
if (item.isEqual) {
$(rows.namedItem(item._id_)).hide();
}
}
});
} else {
// hide the grouping row
$('#'+this.id+"ghead_"+i).hide();
}
//console.info($('#'+this.id+"ghead_"+i));
}
var i, names=this.p.groupingView.sortnames[0], l = names.length,
data = this.p.data, rows = this.rows, item;
l = data.length;
for (i=0;i<l;i++) {
item = data[i];
if (!item.isEqual) {
$(rows.namedItem(item._id_))
.css({
"background-color": "#FFE3EA",
"background-image": "none"
});
} else {
$(rows.namedItem(item._id_)).hide();
}
}
}
});
gridDiff.jqGrid('navGrid', '#gridpager3', { add: false, edit: false, del: false, search: false, refresh: false });
gridDiff.jqGrid('navButtonAdd',"#gridpager3",{caption:"Toggle",title:"Toggle Search Toolbar", buttonicon :'ui-icon-pin-s',
onClickButton:function(){
gridDiff[0].toggleToolbar();
}
});
gridDiff.jqGrid('navButtonAdd',"#gridpager3",{caption:"Clear",title:"Clear Search",buttonicon :'ui-icon-refresh',
onClickButton:function(){
gridDiff[0].clearToolbar();
}
});
gridDiff.jqGrid('filterToolbar',
{stringResult: true, searchOnEnter: false, defaultSearch: 'cn'});
Update
Or is there a way to use positioning to place each grouped item, if sorting is not an option
Updated after accepting answer by Oleg
Page1
Page3
It seems to me that you have not the problem with the custom formatter of the grouptext
You use groupingView having groupDataSorted: false so the sorting of the group (in your case groupField: ['subCategory'] with groupOrder: ['asc']) do jqGrid for you. So the standard sorting behavior will be used.
jqGrid supports sorttype property of the colModel which define how the column should be sorted. If you need custom sorting order you should define sorttype property as a function which returns integer or string used instead of the cell value from the column. the prototype of the sorttype function could be function(cellValue,rowData) so it is possible to define the order which not only the cell value of the sorted column will be used but the whole contain of the row inclusive _id_ property. In you case the usage of the first cellValue parameter would be enough.
So to solve you problem you can for example define an array with the order of 'subCategory' values which you need:
var orderOfSubCategory = [
"System", "system", "Kernel", "Kernel Parameters", "Userlimit",
"Environment", "IIR", "Product"
];
and then define 'subCategory' column as following:
{
name: 'subCategory',
index: 'subCategory',
width: 1,
sorttype: function (value) {
return $.inArray(value, orderOfSubCategory);
}
}
You should don't forget, that jQuery.inArray return 0-based index of the item or -1 if the item will be not found in the array. So the values of 'subCategory' which could be not found in the orderOfSubCategory array will be placed the first. See here the corresponding demo.
Some other small remarks about your code. You use new Array(...) which is bad practice in JavaScript instead of that you should use always [...] construct which do the same is shorter and work quickly. Example: var grouping = ["Environment", "System", "IIR","Userlimit","Kernel Parameters"];
Another place which is difficult for to read for me is:
$('#compareContent').empty();
$('<div id="compareParentDiv" width="100%">'+
'<table id="list2" cellspacing="0" cellpadding="0"></table>'+
'<div id="gridpager3"></div></div>')
.appendTo('#compareContent');
$("#compareParentDiv").hide();
Here you first use cellspacing="0" cellpadding="0" attributes of the table which are unneeded and seconds use empty(), append() combination instead of one html() call. The following code do the same, but it seems me better:
$('#compareContent').html(
'<div id="compareParentDiv" style="display: none" width="100%">' +
'<table id="list2"></table><div id="gridpager3"></div></div>');