Dynamic multicolumn sorting using fnPreDrawCallback - sorting

I have a table with 3 columns and when I sort column 1 or 2 then I would like to sort column 3 by descending.
I'm using fnPreDrawCallback (I tried to use fnDrawCallback too).
Here is my code:
"fnPreDrawCallback": function (oSettings) {
var column = oSettings.aaSorting[0][0];
if (column !== 3) {
oSettings.aaSorting.push([3, "desc"]);
}
}
This code looks fine, but, for example, when I sort column 1, the column 3 isn't sorted and, more awkward, when I try to sort at a 2nd time on column 1, the sort result is always ascending.
How can I achieve this?

The data has already been "sorted" by the time the preDrawCallback is fired, so changing aaSorting in here won't change the outcome of the table.
You can verify by checking oSettings. There is aiDisplay and aiDisplayMaster properties. aiDisplay is an ordered array of the elements that changes as they are sorted from clicks on a th. aiDisplayMaster is the original order that the data came back from the server or was existing on the page.
I would recommend manually calling fnSort from the click event of your th elements. To do this you will have to unbind the click event that datatables installs.
Create a function like this and call it from fnInitComplete so it only runs after datatables has been setup.
function unbindDTSorting() {
//unbind sort event, prevent sorting when header is clicked
$j('[id$=table] th').unbind('click.DT');
//create your own click handler for the header
$j('[id$=table] th').click(function(e) {
var oTable = $j('[id$=table]').dataTable();
//here is where you can do all of your if/else logic to create the desired multidimensional sorting
if(this.cellIndex == 3){
oTable.fnSort( [ [2, 'asc'],[3,'desc' ]] );
}
});
}

Related

Google Apps Script: Activate and sort rows when cells in given column are not blank

I'm extremely new to Apps Script and trying to make my first thing. It's a shopping list.
I want to create a function that will activate and then sort (by Column 1, 'Aisle #') all rows where there are values in a given other column (Column 3, 'Qty'). The idea is to sort the items on the list for that week (i.e., with a value filled in for Qty) by aisle to give me the order I should be looking for things. I do not want to sort items which are in the spreadsheet but without
a value for Qty.
Here is what I've got so far:
var sheet = ss.getActiveSheet()
var range = sheet.getDataRange();
var rangeVals = range.getValues()
function orderList2(){
if(rangeVals[3] != ""){
sheet.activate().sort(1, ascending=true);
};
};
I'm trying to use "if" to define which rows to activate before doing the sort (as I don't want to sort the entire sheet—I only want to sort the items I will be buying that week, i.e., the items with a value in Column 3). The script runs but ends up sorting the entire sheet.
The closest thing I could find was an iteration, but when I did it, it ended up only activating the top-left cell.
Any help you can provide would be greatly appreciated!
Cheers,
Nick
Answer:
Use Range.sort() instead of Sheet.sort() if you don't want to sort the entire sheet.
Explanation:
You want to sort the data according to the value in column A (Aisle #), if the corresponding value in C (Qty) is not empty.
If my assumption is correct, the rows where Qty is empty should go below the rest of data, and they should not be sorted according to their Aisle #.
In this case, I'd suggest the following:
Sort the full range of data (headers excluded) according to Qty, so that the rows without a Qty are placed at the bottom, using Range.sort() (if you don't need to exclude the headers, you can use Sheet.sort() instead).
Use SpreadsheetApp.flush() to apply the sort to the spreadsheet.
Use getValues(), filter() and length to know how many rows in the initial range have their column C populated (variable QtyElements in the sample below).
Using QtyElements, retrieve the range of rows with a non-empty column C, and sort it according to column 1, using Range.sort().
Code sample:
function orderList2() {
var sheet = SpreadsheetApp.getActiveSheet();
var firstRow = 2; // Range starts at row 2, header row excluded
var fullRange = sheet.getRange(firstRow, 1, sheet.getLastRow() - firstRow + 1, sheet.getLastColumn());
fullRange.sort(3); // Sort full range according to Qty
SpreadsheetApp.flush(); // Refresh spreadsheet
var QtyElements = fullRange.getValues().filter(row => row[2] !== "").length;
sheet.getRange(firstRow, 1, QtyElements, sheet.getLastColumn())
.sort(1); // If not specified, default ascending: true
//.sort({column: 1, ascending: false}); // Uncomment if you want descending sort
}
Reference:
Range.sort(sortSpecObj)

jqgrid column chooser returns column order based on current order not original order

I want to persist the column order via localStorage which is working. However, the column chooser gives the order of the columns based on the current order not the original order.
Example:
3 column table where 0 is first, 1 == second, 2 is last column
0,1,2
choose column order to put last column in first, order becomes
2,0,1
choose column order again and put (original last column) back into last and order becomes:
1,2,0
because it resets the column numbers based on current order rather than ORIGINAL order. How to fix this?
onClickButton: function () {
$(this).jqGrid('columnChooser', {
done : function (perm) {
if (perm) {
localStorage["OD_Table_Col_Order"] = perm;
$(this).jqGrid("remapColumns", perm, true);
}
}
});
}
I think that you can find the solution if you would use remapColumns parameter of jqGrid as additional information.
One more way would be to save in localStorage the array of name properties of colModel items instead of the indexes perm.

DataTable.RowFilter using List results?

I need to keep the original DataTable and filter it based on list values. I've tried to hide rows that don't match up to the list but it doesn't work instantly. I don't want to copy the list to another dataTable and bind my dataGridView to is cause i have too much tied up to the original DataTable. Filtering only works for a few conditions but the list is holds only the values that are needed. Is there a LINQ solution to this? C# only please. This is how I got my list. There is another dataGridView that holds primary key for the datatable that I need to filter. It's key is held in a comboBox.
DataTable MainTable = MainDataSet.Tables["MyTable"];
DataTable lookupTable = lookupDataSet.Tables["MyLookupTable"];
var List = (from x in lookupTable.AsEnumerable()
where x.Field<string>("kAutoInc") == comboBox.SelectedValue.ToString()
select x.Field<int>("Pct")).ToList();
var a = MainTable.AsEnumerable().Where(r =>
List .Any(id => id == r.Field<int>("Pct")));
This gives me values of int 30, 40, 50, 60...
The DataGridView has a matching column "Pct" that I need to filter rows that only contain these values. I know it seems easy but I just can't seem to get it to work.
Please use DataView instead.
dataview dv=new dataview(datatable);
dv.filter=string.format("column1={0}","value1");
Like that.

Dojo DataGrid (EnhancedGrid) sorting issue

I have a DataGrid, created programmatically and loaded from ItemFileReadStore.
I want the first column of DataGrid always be sorted in descending order and disabled for user for sorting. Any other column should be available for sorting as a secondary sortable.
I don't want to give users such a powerful(complex and confusing) feature, as sorting by multiple columns, because there are too many columns in my grid.
So, it should be one sortable column for user and another one "already sorted unsortable" column in fact.
Does anyone know how can this be achieved?
Thanks.
To sort the first column add "sortInfo:-1" when you created your object.
To allow sorting the grid from any other columns but not the first you need to overwrite the function canSort.
To create you grid should now look like this .
dijit.grid.DataGrid({
canSort: function (sortInfo) {
if (Math.abs(sortInfo) == 1){
return false;
} else {
return this.inherited("canSort", arguments);
}
},
sortInfo: -1, .....
If you need to sort on more as one column you need dojox.grid.enhanced.plugins.NestedSorting.
http://dojotoolkit.org/reference-guide/1.7/dojox/grid/EnhancedGrid/plugins/NestedSorting.html

Add new datagridRow, sort the datagrid and give serial numbers, in FLEX

I have a datagrid. I add a row to the datagrid using an ADD button. Once I add, I sort the datagrid based on a column. I also provide the serial numbers i.e. row numbers as first column to the datagrid. But, the serial number function does not apply after sorting. Hence, a new row added for e.g. row 5, based on sorting should be row 1, the serial number displayed is still row 5. The UI looks bad as numbers are not in correct order. the code is :
// Sorting Function :
private function sortGrid():void
{
sortGridColl = new ArrayCollection(sortGridArray);
sortA = new Sort();
sortByLevel = new SortField("Type", true, false);
sortA.fields=[sortByLevel];
sortGridColl.sort=sortA;
sortGridColl.refresh();
sortGrid.dataProvider=sortGridColl;
sortGrid.rowCount=myDPColl.length +1;
}
// Serial Number function :
private function sortGridSerialNumbers(oItem:Object,iCol:int):String
{
myDPColl = new ArrayCollection(sortGridArray);
var iIndex:int = myDPColl.getItemIndex(oItem) + 1;
return String(iIndex);
}
// Adding new row to datagrid :
sortGrid.dataProvider.addItem
(
{
Type : typeName.text
}
);
Is sortGridSerialNumbers supposed to return the current serial numbers after sorting? Because it seems to only display the serial numbers for your original state. It won't give the correct value for any item that was added since you added the item to the dataProvider, not the original array.
I like arrays better than array collections, so my choice would be to maintain the list as a raw array. Then on each add, push the new element, do a sortOn (myArray.sortOn("Type")), then iterate over all items to adjust the serial number. Then apply the array to the datagrid as a new dataprovider.

Resources