I have a grid with 3 columns that looks like:
col1 col2 col_sortorder
AAAA 1000 1
AAAA 1002 2
AAAA 1003 3
I made it possible that the user can change the sortoder in the grid by using the mouse. For example move the second row on the top, so the grid looks like:
col1 col2 col_sortorder
AAAA 1002 2
AAAA 1000 1
AAAA 1003 3
I achieved this with:
jQuery("#list").jqGrid('sortableRows');
jQuery("#list").bind('sortstop', function() { fun_sort(event) });
Now I want to update my database with a new value for the col_sortorder.
The function fun_sort() is triggered by the sortstop-event correctly.
My intention was just to read all the data from the grid and use the forloop-index as the new value for the col_sortorder, but when I read through my grid using:
var allRowsInGrid = $('#list').jqGrid('getGridParam','data');
for (i = 0 ; i <= allRowsInGrid.length -1; i++){
var col1 = allRowsInGrid[i].col1;
var col2 = allRowsInGrid[i].col1;
var col_sortorder = i+1; //new value for sortorder
// call ajax to update the database
}
The function getGridParam always returns the initial grid order and not the order after I have moved a row inside the grid.
Can somebody tell me how I can to this?
I find your question interesting and thus I created the demo https://jsfiddle.net/OlegKi/xw0gcjez/, which demonstrates how you can solve the problem. I used update callback of sortableRows, which is the same as "sortupdate" event (see the documentation).
$("#list").jqGrid("sortableRows", {
update: function () {
updateColSortorder();
// the data of the column col_sortorder will contain
// now sequensial values 1,2,3...
// even the display values are still old
// reload grid to display updated data
var p = $grid.jqGrid("getGridParam");
// we reset sortname to "col_sortorder" only to reload
// with minimal visual changes for the user
p.sortname = "col_sortorder";
p.sortorder = "asc";
setTimeout(function () {
$grid.trigger("reloadGrid");
}, 0);
}
});
where updateColSortorder is
function updateColSortorder () {
var rows = $grid[0].rows, localRow, i;
for (i = 0; i < rows.length; i++) {
if ($(rows[i]).hasClass("jqgrow")) {
// row is a row with data. row.id is the rowid
localRow = $grid.jqGrid("getLocalRow", rows[i].id);
localRow.col_sortorder = i;
}
}
}
The grid uses HTML table internally. Thus $grid[0] is the DOM of table, which has rows properties. Every row has id property and so on. The order of elements in the rows collection corresponds the order in which the rows are displayed.
Related
I am trying to loop through rows within a spreadsheet and identify if a particular row has the key word "hello" and move that entire row into a new spreadsheet.
I have attempted the following code. The code works for the first row but doesn't loop through and stops after the first row. Expanding the range selection to "C1:E32" does not help.
function Edit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activatedSheetName = ss.getActiveSheet().getName();
var ActiveSheet = ss.getSheetByName("ActiveSheet"); // source sheet
var MoveDatatoThisSheet = ss.getSheetByName("MoveDatatoThisSheet"); // target sheet
var re = new RegExp(/(Hello)/i);
var startRow = 1;
var endRow = ss.getLastRow();
var getRange = ss.getDataRange();
var getRow = getRange.getRow();
for (var ree = startRow; ree <= endRow; ree++) {
// if the value in column D is "Approved", move the row to target sheet
cellValue = ss.getRange("C1:E1");
if (cellValue.getValue().match(re)) {
// insert a new row at the second row of the target sheet
MoveDatatoThisSheet.insertRows(2, 1);
// move the entire source row to the second row of target sheet
var rangeToMove = ActiveSheet.getRange(/*startRow*/ getRow, /*startColumn*/ 1, /*numRows*/ 1, /*numColumns*/ ActiveSheet.getMaxColumns());
rangeToMove.moveTo(MoveDatatoThisSheet.getRange("A2"));
// add date and time of when approved to target row in column E
MoveDatatoThisSheet.getRange("E2").setValue(Date());
// delete row from source sheet
ActiveSheet.deleteRow(cellValue, 1);
}
}
}
Your loop never uses the variable ree, it only operates with cellValue = ss.getRange("C1:E1").
Another problem is that deletion shifts the rows under the deleted one, possibly causing subsequent operations to act on a wrong row. When you go through an array of rows, deleting some of them, do it bottom up, not top down.
for (var ree = endRow; ree >= startRow; ree--) {
var rangeToCheck = ss.getRange(ree, 3, 1, 3); // 3 columns starting with column 3, so C-E range
if (rangeToCheck.getValues()[0].join().match(re)) { // joining values before checking the expression
MoveDatatoThisSheet.insertRows(2,1);
var rangeToMove = ActiveSheet.getRange(/*startRow*/ getRow, /*startColumn*/ 1, /*numRows*/ 1, /*numColumns*/ ActiveSheet.getMaxColumns());
rangeToMove.moveTo(MoveDatatoThisSheet.getRange("A2"));
// add date and time of when approved to target row in column E
MoveDatatoThisSheet.getRange("E2").setValue(Date());
// delete row from source sheet
ActiveSheet.deleteRow(ree);
}
}
If the goal is to check only column D (say), the code simplifies slightly
var rangeToCheck = ss.getRange(ree, 4); // column D in row ree
if (rangeToCheck.getValue().match(re)) { // joining values before checking the expression
Performance
As Google recommends, one should avoid multiple calls to getValues / setValues and such, instead grabbing all necessary data at once, processing it, and making batch changes at once. E.g., instead of placing it a row in another sheet, add it to an array; when the loop ends, place the entire array in that sheet.
I'm trying to create a drop down menu with contents based on a another cell in the same row. For example if A1 = 'yes' then the drop down in B2 gives you the options of 'yes' or 'no'. I can do this I have the list data set up and to code works. The problem is I need to do this 155 times in 4 different sheets. Is there a faster way to do this than right clicking and editing the data validation rules for each cell. Here's a link to the test sheet I'm working on :
https://docs.google.com/spreadsheets/d/1rd_Ig_wpof9R_L0IiA1aZ9syO7BWxb6jvBhPqG8Jmm4/edit?usp=sharing
You can set data validation rules with a script, as documented here. Here's a reference for starting with Apps scripts.
I wrote a function that does approximately what you described. It works with the range B3:B157 of the sheet '9th grade' in the current spreadsheet. For each of them, it sets the validation rule to be: a value in the same row, columns B and C of sheet 'List Data'. The line with
....... = listData.getRange(i+3, 2, 1, 2);
will need to be modified if the source range of validation is to be different. Here, the parameters are: starting row, starting column, number of rows, number of columns. So, 2 columns starting with the second, in row numbered i+3.
function setRules() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var grade = ss.getSheetByName('9th Grade');
var listData = ss.getSheetByName('List Data');
var range = grade.getRange('B3:B157');
var rules = range.getDataValidations();
for (var i = 0; i < rules.length; i++) {
var sourceRange = listData.getRange(i+3, 2, 1, 2);
rules[i][0] = SpreadsheetApp.newDataValidation().requireValueInRange(sourceRange).build();
}
range.setDataValidations(rules);
}
I land in this issue for a diferent reason: "Just mass DataValidation copy (or update) in one column". Thanks, to user3717023 that bring me a light.
I hope that helps someone this simplification.
function setRules() {
//select spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var leads = ss.getSheetByName('Leads');
//Select correct Datavalidation
var rangeNewDataValidation = leads.getRange('M2:M2');
var rule = rangeNewDataValidation.getDataValidations();
//Copy (or Update) Datavalidation in a specific (13 or 'M') column
var newRule = rule[0][0].copy();
Logger.log(leads.getMaxRows())
for( var i=3; i <= leads.getMaxRows(); i++){
var range = leads.getRange(i, 13);
range.setDataValidations([[newRule.build()]]);
}
}
I have got a NSTableView where multiple selection is allowed. Now when the user selects multiple rows and click on a Button, I need to fetch all the selected row values. Please help!
For fetching a single row data I am using the code as below
var row = tableViewOutlet.selectedRow
var column = tableViewOutlet.tableColumnWithIdentifier("EmpName")
var cell: AnyObject? = column?.dataCellForRow(row)
println("Cell Value - \(cell!.stringValue)")
But I want it for multiple rows in a loop
I wrote the code as below
for (var i = 0; i < tableViewOutlet.numberOfSelectedRows; ++i) {
if(tableViewOutlet.isRowSelected(i))
{
var row = tableViewOutlet.selectedRow
var column = tableViewOutlet.tableColumnWithIdentifier("EmpName")
var cell: AnyObject? = column?.dataCellForRow(row)
println("Selected Emp Name - \(cell!.stringValue)")
}
}
But it is giving me only last selected row value. Tell me where I am going wrong.
There is an API misunderstanding:
numberOfSelectedRows returns how many rows are selected.
Use selectedRowIndexes which returns an NSIndexSet instance containing the indexes of the selected rows
You can enumerate the index set with
Swift 1.2
for (_, index) in enumerate(tableViewOutlet.selectedRowIndexes)
{
}
Swift 2
for (_, index) in tableViewOutlet.selectedRowIndexes.enumerate() {}
Swift 3+
for (_, index) in tableViewOutlet.selectedRowIndexes.enumerated() {}
But I'd retrieve the data from the table view data source rather than from the table cell
I have a slickGrid which is using dataView to render student grades. I would like to default sort the grid prior to it being rendered by column with id = 0 and field = 'Student'. How can I trigger sort event on this column before the grid renders?
The reason why I want to do this is because I have a really strange bug that can be seen in this video:
http://screencast.com/t/Oz0vlcsQPp
The sorter works fine on the 1st asc/des sort but then it goes all out of whack. Noting is sorted the way it should be. However if I 1st sort by student name then the sorter on any other column works just fine without any issues no matter how many times I sort. If I refresh the page the problem happens again.
Since I cannot even begin to understand why is this happening my only hope is to initially fire a sort on the student column and bypass the problem all together.
NOTE: I am using the naturalSort.js from here: https://github.com/overset/javascript-natural-sort/blob/master/naturalSort.js. I don't think the sort is the issue since it works fine when I initially sort by student name... This one is breaking my brain...
EDIT: As you can see in the video my grid cell data looks something like "A (78.65%)". My data structure looks like this:
"Column_3":{"displayValue":"A (100%)","sortValue":100.0},
"Column_4":{"displayValue":"B (87.53%)","sortValue":87.53},
"Column_5":{"displayValue":"?","sortValue":-1.0}
I am sending over an object for sorting reasons in order to use percentage as a sorting criteria. In order to make this work I have defined dataItemColumnValueExtractor in grid options as such:
self.options["dataItemColumnValueExtractor"] = getItemColumnValue;
function getItemColumnValue(item, column) {
var values = item[column.field];
return values.displayValue !== undefined ? values.displayValue : values;
}
This allows me to use the sortValue data to sort the grid. Here is my sort event:
grid.onSort.subscribe(function(e, args){
var comparer = function(a, b) {
var result;
if (a[args.sortCol.field].sortValue !== undefined && a[args.sortCol.field].sortValue !== null && b[args.sortCol.field].sortValue !== undefined && b[args.sortCol.field].sortValue !== null) {
result = naturalSort(a[args.sortCol.field].sortValue,b[args.sortCol.field].sortValue);
}
else {
result = naturalSort(a[args.sortCol.field],b[args.sortCol.field]);
}
return result;
};
dataView.sort(comparer, args.sortAsc);
});
Bottom line is everything works fine except the above mentioned issue with sorting... Any help would be appreciated...
First of all...your issue for first time sorting is something else which can be fixed...
But if you want to sort a col on grid load you can trigger the click event....
$(function () {
for (var i = 0; i < 50000; i++) {
var d = (data[i] = {});
d["num"] = i;
.
.
d["effortDriven"] = (i % 5 == 0);
}
dataView = new Slick.Data.DataView();
grid = new Slick.Grid("#myGrid", dataView, columns, options);
$('.slick-header-columns').children().eq(2).trigger('click'); // eq(2) for the 3rd col
}
I am trying to filter a Google line chart columns and using the code shared here in Google Charts-Code for Category Filter
It all works well however I have a number of columns and would like to have the chart start with just one column displayed and allow the user to add in any of the additional columns as needed.
What I've found is that if I play with the initState variable to set it to the one column I want to display initially, it will have that column shown in the selector section but still displays all the columns initially until I select an additional column when it hides the rest and just displays the two I have selected.
So then I tried turning off this part of the code:
// put the columns into this data table (skip column 0)<br>
for (var i = 1; i < data.getNumberOfColumns(); i++) {
columnsTable.addRow([i, data.getColumnLabel(i)]);
initState.selectedValues.push(data.getColumnLabel(i));
}
and replacing it with
columnsTable.addRow([1, data.getColumnLabel(16)]);
initState.selectedValues.push(data.getColumnLabel(16));
which sets the column i'm after (column 16) as the selected column in the selection list but removes the other columns from the list of available columns and still displays all 16 columns.
How can I set this up so it displays the single selected column's data initially yet still gives the ability to pick other columns from the selector?
You want to keep the columnstable.addRow call inside the for loop, as it populates the DataTable used to provide the list of columns. You can set the selectedValue variable as you have it:
// put the columns into this data table (skip column 0)<br>
for (var i = 1; i < data.getNumberOfColumns(); i++) {
columnsTable.addRow([i, data.getColumnLabel(i)]);
}
initState.selectedValues.push(data.getColumnLabel(16));
In order to make the chart draw properly with the initial selection, we need to make a small adjustment to the structure, putting all of the updating code into its own function, and then calling that as necessary:
function setChartView () {
var state = columnFilter.getState();
var row;
var view = {
columns: [0]
};
for (var i = 0; i < state.selectedValues.length; i++) {
row = columnsTable.getFilteredRows([{column: 1, value: state.selectedValues[i]}])[0];
view.columns.push(columnsTable.getValue(row, 0));
}
// sort the indices into their original order
view.columns.sort(function (a, b) {
return (a - b);
});
chart.setView(view);
chart.draw();
}
google.visualization.events.addListener(columnFilter, 'statechange', setChartView);
setChartView();
Here's a working example: http://jsfiddle.net/asgallant/WaUu2/157/.