How to compute a column value while editing in jqgrid - asp.net

I have a supposedly common problem to solve (done easily with other grid controls I'm familiar with).
In jqgrid, i'm quite stumped.
I have a jqgrid with inline editing enabled. I would like to add some scripting so that when editing a row (or adding a new row), the value of ColumnC is automatically computed as ColumnA * ColumnB as default. The user can change the values in any column at any time. I want this value to be computed as soon as the user enters it and not wait till the data is saved.
My approach so far has been to attach a dataEvent of type "change" to ColumnA and ColumnB -
dataEvents: [
{ type: 'change', fn: function(e) {
var rowid = $("#myGrid").jqGrid('getGridParam','selrow');
var rowData = $("#myGrid").getRowData(rowid);
var cell1 = rowData['ColumnA'];
var cell2 = rowData['ColumnB'];
var newValue = cell1 * cell2;
$("#myGrid").jqGrid('setCell', rowid, 'ColumnC', newValue);
}
},
]
Obviously, cell1 & cell2 don't actually return the value but the whole cell content as already discovered by other users here How to get a jqGrid cell value. The only way to get a cell value seems to be to use a custom regex user function that strips out that value.
Apart from that, is there a better/alternate way to achieve what I need? Something as simple as jqGrid - How to calculated column to jqgrid? though obviously that won't cut it for me since it will only displaying data and user cannot update it.
Any help would be appreciated.
UPDATE: After guidance from Oleg, I was able to extend getTextFromCell to support what I need.
function getTextFromCell(cellNode) {
var cellValue;
//check for all INPUT types
if (cellNode.childNodes[0].nodeName == "INPUT") {
//special case for handling checkbox
if (cellNode.childNodes[0].type == "checkbox") {
cellValue = cellNode.childNodes[0].checked.toString();
}
else {
//catch-all for all other inputs - text/integer/amount etc
cellValue = cellNode.childNodes[0].value;
}
}
//check for dropdown list
else if (cellNode.childNodes[0].nodeName == "SELECT") {
var newCell = $("select option:selected", cellNode);
cellValue = newCell[0].value;
}
return cellValue;
}
function getCellNodeFromRow(grid,rowId,cellName) {
var i = getColumnIndexByName(grid, cellName);
var cellValue;
//find the row first
$("tbody > tr.jqgrow", grid[0]).each(function() {
//The "Id" column in my grid is at index 2...
var idcell = $("td:nth-child(2)", this);
var currRowId = getTextFromCell(idcell[0])
if (currRowId == rowId) {
cellValue = getTextFromCell($("td:nth-child(" + (i + 1) + ")", this)[0]);
return false;
}
});
return cellValue;
}
The code in getCellNodeFromRow is not the most efficient. There is a .each() loop for find the matching row node. I can see this being slow when the grid has thousands of rows. Is there a better/more efficient way to find the row node? I have the row Id already.

Look at the demo from the answer. It uses cell editing, but the same technique work for inline editing too. Just click on any cell in the "Amount" column and modify the numerical value. You will see that the value in the "Total" row (footer) will be changed dynamically during the cell is still in the editing mode. I think it is what you need.

you can achieve this using onCellSelect event of jqgrid as below
//global section
var columnA;
var ColumnB;
var ColumnC;
var currentRow;
//
onCellSelect: function (rowid, iCol, aData) {
currentRow = rowid;
var ColumnA = $('#grid').getCell(rowid, 'MyCol');
var ColumnB = $('#grid').getCell(rowid, 'MyCol');
$("#grid").jqGrid('editRow', rowid, true );
$("#myMenu").hide();
if (rowid && rowid !== lastsel) {
if (lastsel) jQuery('#grid').jqGrid('restoreRow', lastsel);
$("#grid").jqGrid('editRow', rowid, true );
lastsel = rowid;
}
else if (rowid && rowid === lastsel)
{ $("#grid").jqGrid('editRow', rowid, true ); }
//if it is in editable mode
// when you view the html using firebug it will be like the cell id change to
//format like "rowid_ColumnName"
$('#' + currentRow + '_ColumnC').val(ColumnA*ColumnB);
// or you can use achieve this using following jqgrid method at
//appropriate place
$("#myGrid").jqGrid('setCell', rowid, 'ColumnC', ColumnA*ColumnB);
}

Related

Very simple if else check in Google App Maker

This is likely embarrassingly easy but I'm new and I've been beating my head against the wall on this for a while now. What I am attempting to do is basically a modified version of the "Hello App Maker!" If else test.
The necessary info I have the following widgets attached to the appropriate data sources:
Dropdown widget called source_name (string - list)
Label widget I've called name (string)
Text Box widget called qty_duration (number)
Label widget I've called hours (number)
I have a dropdown widget called source_name with 5 options. On selection I have the value appear in a label widget I've called name. If the option selected from the drop down widget is ever LABOUR I am trying to then have the value of a Text Box widget called qty_duration appear in a label widget I've called hours
On the source_name dropdown event - onValueChange I have the following code:
// Define variables for the input and output widgets
var nameWidget = app.pages.Apex_job_details.descendants.name;
var outputWidget = app.pages.Apex_job_details.descendants.hours;
var techhours = app.pages.Apex_job_details.descendants.qty_duration;
var nothing = 0;
// If a name is LABOUR, add the qty to the output widget Else output 0.
if (nameWidget == 'LABOUR') {
outputWidget.text = techhours;
} else {
outputWidget = nothing;
}
It's not giving me any errors, but it's also not outputting to the hours label. If I edit the code as follows just to muck with it:
// Define variables for the input and output widgets
var nameWidget = app.pages.Apex_job_details.descendants.name;
var outputWidget = app.pages.Apex_job_details.descendants.hours;
var techhours = app.pages.Apex_job_details.descendants.qty_duration;
var nothing = 0;
// If a name is LABOUR, add the qty to the output widget Else output 0.
if (nameWidget == 'LABOUR') {
outputWidget.text = techhours;
} else {
outputWidget.text = nothing;
}
I'm not sure what I'm doing wrong.
Assuming all labels and input widgets are inside a table row you will want to adjust your code as follows:
var tablerow = widget.parent;
var nameWidget = tablerow.descendants.name.text;
var outputWidget = tablerow.descendants.hours;
var techhours = tablerow.descendants.qty_duration.value;
if(nameWidget === 'LABOUR') {
outputWidget.text = techhours;
} else {
outputWidget.text = null;
}
By using widget.parent in the onValueChange event of the dropdown you will automatically reference the table row and then by using descendants you are referencing only the descendants of that table row. This will bridge the error by using an absolute reference when using table rows. If it still doesn't work let me know.

Performance server scripting

I have table with multiple customerKey values assigned to a numeric value; I wrote a script where foreach row of data I scan whole table to find all values assigned to the current customerKey and return a highest one;
I have a problem with performance - script processes around 10 records per second - any ideas how to improve this or maybe propose an alternative solution plesae?
function getLastest() {
var date = app.models.magicMain.newQuery();
var date_all = date.run();
date_all.forEach(function(e) { // for every row of date_all
var temp = date_all.filter(function(x) {
return x.SubscriberKey === e.SubscriberKey; // find matching records for the current x.SubscriberKey
});
var dates = [];
temp.forEach(function(z) { // get all matching "dates"
dates.push(z.Date);
});
var finalValue = dates.reduce(function(a, b) { // get highest dates value (integer)
return Math.max(a, b);
});
var record = app.models.TempOperatoins.newRecord(); // save results to DB
record.email = e.SubscriberKey.toString() + " " + finalValue.toString();
app.saveRecords([record]);
});
}
The only suggestion I have would be to add:
var recordstosave = [];
At the top of your function.
Then replace app.saveRecords([record]) with recordstosave.push(record).
Finally outside of your foreach function do app.saveRecords(recordstosave).
I saw major processing time improvements doing this rather than saving each record individually inside a loop.

update edited cells within treetable after expand/collapse items

I have a treeTable with editable cells within the expanded rows. The editable cells get a dirty flag after editing (in the example the background color is set to red).
The problem i'm running into is that i found no certain way to update the dirty flag on expand/collapse (edited cells get the css class 'edited-cell').
At the moment the code looks like that:
// each editable textfield gets a Listener
textField.attachLiveChange(
var source = oEvent.oSource;
...
jQuery('#' + source.getId()).addClass(EDITED_CELL_CLASS, false)
// list with cell ids, e.g. "__field1-col1-row1"
DIRTY_MODELS.push(model.getId()) //*** add also binding context of row
)
// the table rows are updated on toggleOpenState
new sap.ui.table.TreeTable({
toggleOpenState: function(oEvent) {
...
this.updateRows() // see function below
}
})
// update Rows function is also delegated
oTable.addDelegate({ onAfterRendering : jQuery.proxy(this.updateRows, oTable)});
//http://stackoverflow.com/questions/23683627/access-row-for-styling-in-sap-ui5-template-handler-using-jquery
// this method is called on each expand/collapse: here i can make sure that the whole row has it's correct styling...
// but how to make sure that special cells are dirty?
function updateRows(oEvent) {
if (oEvent.type !== 'AfterRendering'){
this.onvscroll(oEvent);
}
var rows = this.getVisibleRowCount();
var rowStart = this.getFirstVisibleRow();
var actualRow;
for (var i = 0; i < rows; i++){
actualRow = this.getContextByIndex(rowStart + i); //content
var row = this.getRows()[i]
var obj = actualRow.getObject()
var rowId = row.getId()
updateStyleOfRows(obj, rowId, actualRow)
updateDirtyCells(rowId) //*** how to get the binding context in this function???
}
};
// update Dirty Cells in function updateRows():
function updateDirtyCells(rowId){
for (var i = 0; i < DIRTY_MODELS.length; i++){
var dirtyCellId = DIRTY_MODELS[i]
//*** make sure that only the correct expanded/collapsed rows will be updated -> depends on the bindingContext of the row
jQuery('#' + rowId).find('#' + dirtyCellId + '.editable-cell').addClass(EDITED_CELL_CLASS, false)
}
}
This doesn't work correctly, because the ids of the cells change on each layout render (e.g. collapse/expand rows). Please see attached image.
Let me know if i should provide more information.

Kendo Grid Grouping column sorting is not working

In Kendo UI Grid, After grouping grouped column sorting is not working, remaining column sorting is working fine.
Can anyone give me idea on how to sort grouped column from client side.
Thank you!!
When you group your data in kendo grid it automatically sort groups asc.
You can read about this behavior in docs
But what you need is change group sorting on column header click.
on dataBound event try to look at grid dataSource.sort() collection and if need change group sorting direction.
Something like this:
//Get the grid object
var grid = $("#grid").data("kendoGrid");
// Get the datasource bound to the grid
var ds = grid.dataSource;
// Get current sorting
var sort = ds.sort();
// Display sorting fields and direction
if (sort) {
for (var i = 0; i < sort.length; i++) {
if(sort[i].field == " myField"){
grid.dataSource.group({field:"myField", dir: sort[i].dir });
}
}
}
Kendo UI Grid Grouping gives you ListSortDirection.Ascending sorting by default. If you want to do something else you have to set it. If you are using the WebApi interface and generating a kendoRequest for the Kendo.mvc.dll method .ToDataSourceResult(kendoRequest); then you may try something like this:
var sort = kendoRequest.Sorts.FirstOrDefault();
var group = kendoRequest.Groups.FirstOrDefault();
if(sort != null && group != null) {
if(sort.Member == group.Member && sort.SortDirection == ListSortDirection.Descending) {
kendoRequest.Groups[0].SortDirection = sort.SortDirection;
}
}
var result = data.ToDataSourceResult(kendoRequest);

How to delete rows from a wijmo grid in a loop and refresh?

Is there a way we can delete rows from a wijmo grid running within a loop and refresh the grid with new data. I tried with the following approach, I can see the rows getting deleted while debugging but after the loop ends the grid is refreshed with old set of data.
self.delete = function (obj, event) {
var pagesize = $("#pageDisplay :selected").val();// 5
var pageSizeDiff = defaultPageSize - pagesize;//5
var $grid = $("#Grid");
var newData = $grid.wijgrid("data");// array of 10 objects
var i = 0;
while (i < pagesize) {
newData.splice(pageSizeDiff, 1);// delete from 5th row
$grid.wijgrid("data", newData);
//refresh grid
$grid.wijgrid("ensureControl", true);
i++;
};
};
I am not sure why you are setting the new data in the loop. Ideally, you should delete the rows in the loop and then, set the new data.

Resources