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>');
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;
}
});
}
});
Updated with jsfiddle: https://jsfiddle.net/pnnorhtg/
I have a data table and I am having a difficult time initializing the 'numbers with html' data tables plug-in https://datatables.net/plug-ins/sorting/num-html.
It's initially sorted on 'Count' DESC. However once I execute my function that modifies and appends html to each of the cell in that column it is no longer sortable.
Based on my research this plug-in should be able to fix this but I am having no luck.
This is my data:
var preHtmlData = [{
Brand: "Toyota",
Count: 33423,
GBV: 242445
}, {
Brand: "Ford",
Count: 23558,
GBV: 334343
}, {
Brand: "Honda",
Count: 9466,
GBV: 933455
}];
This is my function that goes through and adds html text to the value based on the key:
//adding text next to Count
function updateItemCount(preHtmlData) {
for(var key in preHtmlData) {
var value = preHtmlData[key];
console.log(value)
if (value.Brand == 'Toyota') {
value.Count = value.Count + ' <div style="font-size: 10px;margin-top: -5px">Toyota Purchases</div>';
} else if (value.Brand == 'Ford') {
value.Count = value.Count + ' <div style="font-size: 10px;margin-top: -5px">Ford Purchases</div>';
} else if (value.LOB == 'Honda') {
value.Count = value.Count + ' <div style="font-size: 10px;margin-top: -5px">Honda Purchases</div>';
}
}
}
This is what where I am initializing table:
summary_data_table = $('#resultsTable').DataTable({
"bSort": true,
"destory": true,
"data": data,
"searching": false,
"paging": false,
"order": [
[aryJSONColTable.length - 1, "desc"]
],
"dom": '<"top">t<"bottom"><"clear">',
"columnDefs": aryJSONColTable,
[
{ type: 'natural-nohtml', targets: 5 }
]
"initComplete": function(settings, json) {
$("#resultsTable").show();
}
});
I've added the plug-in and constructed my code as per the documentation, I have a feeling its some how I've defined my columnDefs, but I need it to execute aryJSONColTable and the natural sorting.
UPDATE
As seen from your fiddle, you can overcome this problem by placing an order type("type":"natural") inside your custom properties that you pass on to columnDefs
customParams = {
"targets": keys.length - 1,
"sTitle": "Item Count",
"type":"natural"
}
Please see the updated fiddle for the solution https://jsfiddle.net/pnnorhtg/1/
I use multi-row grouping and put the totals in the grouping headers.
I'm not using the totals in the totals rows. I see the the rows are grouped and where the totals would be there are empty rows. In my case there is an empty row after each of the child grouping and at the end there is an empty row for the parent totals.
How do I remove these totals rows?
Thank you!
.cshtml:
<div id="gridList" class="grid" style="width: 100%; height: 500px"></div>
.js
$(function() {
var columns = [
{
id: "isExcluded",
name: "Exclude",
field: "isExcluded" /*, width: 120*/,
formatter: Slick.Formatters.Checkmark,
editor: Slick.Editors.Checkbox, sortable: true
},
{
id: "symbol",
name: "Symbol",
field: "symbol",
sortable: true /*, width: 120*/
},
{
id: "price",
name: "Price",
field: "price",
sortable: true
//, groupTotalsFormatter: sumTotalsFormatter
},
{
id: "parent_name",
name: "Parent Name",
field: "parent_name",
sortable: true /*, width: 120*/
},
{
id: "description",
name: "Description",
field: "description",
sortable: true,
width: 120,
editor: Slick.Editors.Text,
},
{ id: "cancel_ind",
name: "Canceled",
field: "cancel_ind",
sortable: true, width: 80 }
];
function requiredFieldValidator(value) {
if (value == null || value == undefined || !value.length) {
return { valid: false, msg: "This is a required field" };
} else {
return { valid: true, msg: null };
}
};
var options = {
editable: true,
enableAddRow: true,
enableCellNavigation: true,
asyncEditorLoading: false,
autoEdit: true,
enableExpandCollapse: true,
rowHeight: 25
};
var sortcol = "parent_name";
var sortdir = 1;
var grid;
var data = [];
var groupItemMetadataProviderTrades = new Slick.Data.GroupItemMetadataProvider();
var dataView = new Slick.Data.DataView({ groupItemMetadataProvider: groupItemMetadataProviderTrades });
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
function groupByParentAndSymbol() {
dataViewTrades.setGrouping([
{
getter: "parent_name",
formatter: function(g) {
return "Parent: " + g.value + " <span style='color:green'>(" + g.count + " items) Total: " + g.totals.sum.price + "</span>";
},
aggregators: [
new Slick.Data.Aggregators.Sum("price")
],
aggregateCollapsed: true
,lazyTotalsCalculation: true
},
{
getter: "symbol",
formatter: function(g) {
return "Symbol: " + g.value + " <span style='color:green'>(" + g.count + " items) Total: " + g.totals.sum.price + "</span>";
},
aggregators: [
new Slick.Data.Aggregators.Sum("price")
],
collapsed: true
,lazyTotalsCalculation: true
}]);
};
grid = new Slick.Grid("#gridList", dataView, columns, options);
grid.registerPlugin(groupItemMetadataProviderTrades);
grid.setSelectionModel(new Slick.RowSelectionModel());
..... /*sorting support etc*/
// use instead of the default formatter <--- removed not used.
function sumTotalsFormatter(totals, columnDef) {
var val = totals.sum && totals.sum[columnDef.field];
//if (val != null) {
// return "total: " + ((Math.round(parseFloat(val) * 100) / 100));
//}
return "";
}
// will be called on a button click (I didn't include the code as irrelevant)
var getDataList = function () {
$.getJSON('/Home/GetData/', function (json) {
data = json;
dataView.beginUpdate();
dataView.setItems(data);
groupByParentAndSymbol();
dataView.endUpdate();
dataView.syncGridSelection(grid, true);
});
};
getDataList();
});
Adding displayTOtalsRow: false to the dataview solved my problem - the total rows are not shown now.
var dataView = new Slick.Data.DataView({ groupItemMetadataProvider: groupItemMetadataProviderTrades, displayTotalsRow: false });
To answer simply to your question... Just remove the aggregators: [...], when I say remove you have 2 options, you can remove whatever is the array [...] or you could simply erase completely that object line (so removing completely the aggregators[...]).
Now if you want more explanation of how it works...Let's give you some definition so you'll understand better. An aggregate is a collection of items that are gathered together to form a total quantity. The total in question could be a sum of all the fields, an average or other type of aggregator you might define. So basically it's the action of regrouping by the column you chose and give the calculation result of the group. Alright now how does it work in the case of a SlickGrid? You need to define what kind of Aggregator you want to use (Avg, Sum, etc...) that goes inside your function groupByParentAndSymbol(), defining them will do the calculation BUT unless you attach it to the field, nothing will be displayed, so in the example you found it is very important to attach/bind this groupTotalsFormatter: sumTotalsFormatter to your columns definition, as for example:
...var columns = [{id: "cost", ...width: 90, groupTotalsFormatter: sumTotalsFormatter}, ...];
so let's recap... Once the Aggregator is define new Slick.Data.Aggregators.Sum("cost") it will do the calculation but unless it's bind to the field nothing will be displayed. As an extra option, the aggregateCollapsed (true/false) is to display the sub-total (avg, sum or whatever) inside or outside the group when you collapse.
I have am currently using Dojo EnhancedGrid with Pagination, filtering and cell edition.
The problem is that in one page, I need to update another value when a cell is edited. When I update this value, I loose the cell selected so I need to click on the next cell to select it and modify it.
It is so not possible to do Enter / edit / enter / down / enter / edit (Excel like edition).
Here is a part of my code :
var store = new dojo.data.ItemFileWriteStore({'data':data});
var grid = new dojox.grid.EnhancedGrid({
id: 'grid',
store: store,
structure: structure,
columnReordering: true,
autoHeight: true,
autoWidth: true,
initialWidth: '100%',
escapeHTMLInData: false,
plugins: {
pagination: {
pageSizes: ["10", "25", "50", "All"],
description: true,
sizeSwitch: true,
pageStepper: true,
gotoButton: true,
maxPageStep: 4,
position: "bottom"
},
filter : {}
},
onStartEdit: function(inCell, inRowIndex)
{
item = grid.selection.getSelected()[0];
currentVal = item[inCell['field']][0];
},
doApplyCellEdit: function(inValue, inRowIndex, inAttrName) {
if(inValue != currentVal){
[...]
$.ajax(url, data, {
success:function(data, textStatus) {
val = parseInt(data["info"]);
if(!isNaN(val)) {
grid.store.setValue(item, 'info', val);
grid.update();
} else {
grid.store.setValue(item, 'info', 0);
grid.update();
}
}
});
}
}
});
dojo.byId("gridDiv").appendChild(grid.domNode);
grid.startup();
Do you see any solution to handle this ?
I too use an enhanced dojo grid, where I had a similar problem. I used this to reload the data right:
require(["dijit/registry"],function(registry) {
var grid = registry.byId('grid');
grid._lastScrollTop=grid.scrollTop;
grid._refresh();
});
With this you always should get the last row you manipulated, and eventually also the last selected one... .
After many research, I have found the following solution :
$.ajax(url, data, {
success:function(data, textStatus) {
val = parseInt(data["info"]);
if(!isNaN(val)) {
grid.store.setValue(item, 'info', val);
grid.update();
window.setTimeout(function() {
grid.focus.next();
}, 10);
} else {
grid.store.setValue(item, 'info', 0);
grid.update();
window.setTimeout(function() {
grid.focus.next();
}, 10);
}
}
});
The timer is needed because there is a short delay before grid update the thus loosing the focus.
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]);" ;