AG-Grid not reordering datasource rows - ag-grid

I have an ag-grid that updates based on a datasource. It works fine except when rows are reordered.
I have a getRowNodeId setup with a uniqueId for each row.
data source comes in as
datasource: 76370da8-eeb1-44f9-b107-f0060a7de6d9 - 1 : A2
datasource: ef682a41-212f-46fe-a2f3-f9086af24b9a - 2 : B3
datasource: 4627d5a5-7297-4147-b21f-ec3ee464743c - 3 : C3
datasource: 4c453ab1-eb2d-4a0c-b328-ed51047050be - 4 : E1
datasource: 10eff5aa-20cd-4967-95db-aaf5d7a8dd81 - 5 : E1
datasource: ebd4b39b-8003-4a9b-8983-7e3a6bd3fc58 - 6 : A2
the grid row data is:
griddata: 76370da8-eeb1-44f9-b107-f0060a7de6d9 - 1 : A2
griddata: ef682a41-212f-46fe-a2f3-f9086af24b9a - 2 : B3
griddata: 4627d5a5-7297-4147-b21f-ec3ee464743c - 3 : C3
griddata: 4c453ab1-eb2d-4a0c-b328-ed51047050be - 4 : E1
griddata: ebd4b39b-8003-4a9b-8983-7e3a6bd3fc58 - 6 : A2
griddata: 10eff5aa-20cd-4967-95db-aaf5d7a8dd81 - 5 : E1
griddata: a9c11821-e6a3-48d0-a6b3-d38617ed16d2 - 7 :
applytransaction of removing all grid rows and adding the datasource back will updated the grid but I dont want an operation so heavy. I just want a simple reordering of these rows. Refreshcells does not work, nor do I want redrawRows for the same reason as the applyTransaction.
Any help or ideas would be greatly appreciated.

I just wanted to answer how I solved this. It may not be the best way, but it works for me. Hopefully it can help someone else.
After my data came back in the correct or and my grid didnt refresh that order, I called
gridApi.onSortChanged();
This fired a callback event on the grid postSort().
My Code looks like the following which did the sort I was looking for:
postSort: (rowNodes: RowNode[]) => {
function move(toIndex: number, fromIndex: number) {
rowNodes.splice(toIndex, 0, rowNodes.splice(fromIndex, 1)[0]);
}
const orderedUniqueIds = this.getCorrectOrderedIds()
var nextInsertPos = 0;
for (var i = 0; i < orderedUniqueIds.length; i++) {
let currentUniqueId = orderedUniqueIds[i];
let correctNodePosistion = findIndex(rowNodes, (n: RowNode) => {
return n.data.uniqueId === currentUniqueId;
})
if (correctNodePosistion > -1) {
move(correctNodePosistion, i)
nextInsertPos++;
}
}
console.log('post sort fired');
}`

Related

Matching a date on a calendar to another field

Ok, I have a calendar on my page and each day is a formatted version of that date, eg.
Jan 2021
1 2 3 4
5 6 7 8
etc..
so the 1 cell will contain 1/1/2021 (but formatted to just show '1' [d])
I also have a cell (K5) on that page for a user to enter a date eg:[1/1/2021]
What i'd like is a script that changes the border colour of the day in the calendar if it matches the user entry cell.
The code:
function onEdit(e) {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var date = sheet.getRange("K5").getValue();
if (e.range.getValue()== date) {
e.range.setBorder(true, true, true, true, true, true, "red", SpreadsheetApp.BorderStyle.solid); }
};
This doesn't work and I can't think of a way of having the code work for every cell of the calendar (there are 2 years worth so over 1000 cells).
It doesn't need to be onEdit, i was just testing to see if the actual setBorder function worked (which it does)
Also, I cant use conditional formatting as I've already used that to change to bg and font colours for something else (and there's no option to change boarder colour anyway)
I've made a mini version with just Jan if you'd like to have a look and see what you can do:
https://docs.google.com/spreadsheets/d/1oV4lE8cQB-e2bVc_HgiGM31ivk3uHxPcqsSdLdCxsmQ/edit?usp=sharing
One alternative to looking for all the dates would be to use a formula to show the dates and their addresses in a different sheet. This formula will output a series of dates and their addresses for your holidays. It can then be read with an onEdit() script to put borders on the correct addresses:
Formula:
=ARRAYFORMULA(IFERROR(QUERY(SPLIT(FLATTEN(N(Calendar!E9:AY)&"|"&ROW(Calendar!E9:AY)&"|"&COLUMN(Calendar!E9:AY)&"|"&LEN(TO_TEXT(Calendar!E9:AY))),"|",0,0),"select Col1,Col2,Col3 where Col4<3 and ("&TEXTJOIN(" or",TRUE," Col1="&FILTER(Calendar!BE28:BE100,Calendar!BE28:BE100<>""))&")")))
Script:
function onEdit(e){
holidayBorders(e);
}
function holidayBorders(e){
var sheet = e.range.getSheet();
if(e.value && sheet.getName()=='Calendar' && e.range.getColumn()==57 && e.range.getRow() >= 28){
SpreadsheetApp.flush();
Utilities.sleep(10000);
var datasheet = e.source.getSheetByName('DATA');
var rcs = datasheet.getRange('AQ3:AR').getValues().filter(e=> e[0]);
for (let i=0;i<rcs.length;i++){
sheet.getRange(rcs[i][0],rcs[i][1]).setBorder(true, true, true, true, true, true, "red", SpreadsheetApp.BorderStyle.solid);
}
}
}
You could do the following:
Get all values in your range, using getValues().
Iterate through all values in the resulting 2D array.
For each value, check if (1) the value is a Date (for example, using instanceof) and whether the two dates are from the same day (for example, doing this).
If both conditions are met, set the border.
Code snippet:
function setBorders() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var date = sheet.getRange("K5").getValue();
var firstRow = 7;
var firstCol = 5;
var data = sheet.getRange(firstRow, firstCol, sheet.getLastRow() - firstRow + 1, sheet.getLastColumn() - firstCol + 1).getValues();
data.forEach((row, i) => {
row.forEach((value, j) => {
if (value instanceof Date && sameDay(date, value)) {
sheet.getRange(i + firstRow, j + firstCol).setBorder(true, true, true, true, true, true, "red", SpreadsheetApp.BorderStyle.solid);
}
});
})
}
function sameDay(date1, date2) {
return date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate();
}

Function/Expression to write values back in aggrid

I'm probably missing something in the documentation but cannot seem to find it right now.
Let's assume I have a data object like this:
{
value1: number,
value2: number,
computed: number
}
Building an AgGrid that displays a set of these objects as rows with value1/2 being editable while computed is not editable is straightforward.
I can use expressions or functions to create a dynamic column which calculates e.g. value1 * value2. If I change value1 or value2 the dynamic column gets refreshed with the new values.
The question is, is there a way to bind the dynamic column to the computed field, or do I have to subscribe to row changes and do the updating of the computed field manually?
Cheers
Based on this example
function getRowData() {
var rowData = [];
for (var i = 1; i <= 20; i++) {
rowData.push({
group: i < 5 ? "A" : "B",
a: (i * 863) % 100,
b: (i * 811) % 100,
c: (i * 743) % 100,
d: (i * 677) % 100,
e: (i * 619) % 100,
f: (i * 571) % 100,
t:1000 <--- added
});
}
return rowData;
}
and in columnDefs
{
headerName: "Total",
valueGetter: "data.t = (data.a + data.b + data.c + data.d + data.e + data.f)",
editable: false,
aggFunc: "sum",
cellClass: "total-col"
},
{
field: "t", -- just for test
}
So everything handled here
valueGetter: "data.t = (data.a + data.b + data.c + data.d + data.e + data.f)",
DEMO

Ag-grid: Count the number of rows for each filter choice

In my ag-grid I want to display counts of rows next to each filter choice in a set filter, and maybe sort choices by that count (descending).
This is what it looks like by default:
I want the choices to be displayed as
Select All (88)
Katie Taylor (2)
Darren Sutherland (1)
John Joe Nevin (1)
Barack Obama (0)
...
What is the most efficient way to get those counts (and maybe sort the choices accordingly) from the row data, taking into account filters already set in the other fields (if any)?
Assuming your columns field is "name", you could try building up a map and refer to this in the filters cellRenderer:
var nameValueToCount = {};
function updateNameValueCounts() {
nameValueToCount = {};
gridOptions.api.forEachNodeAfterFilter((node) => {
if(!nameValueToCount.hasOwnProperty(node.data.name)) {
nameValueToCount[node.data.name] = 1;
} else {
nameValueToCount[node.data.name] = nameValueToCount[node.data.name] + 1;
}
});
}
And your column def would look like this:
{
headerName: "Name",
field: "name",
width: 120,
filter: 'set',
filterParams: {
cellRenderer: NameFilterCellRenderer
}
},
And finally, the NameFilterCellRenderer would look like this:
function NameFilterCellRenderer() {
}
NameFilterCellRenderer.prototype.init = function (params) {
this.value = params.value;
this.eGui = document.createElement('span');
this.eGui.appendChild(document.createTextNode(this.value + " (" + nameValueToCount[params.value] + ")"));
};
NameFilterCellRenderer.prototype.getGui = function () {
return this.eGui;
};
You would need to ensure that you called updateCountryCounts to update it when data changed (either with new/updated data, or when a filter was updated etc), but this should work for your usecase I think

How to simplify this code?

I have a simple code:
results = mongo.group(
key = [ 'test','id' ],
....
)
temp_hash = {}
for result in results:
if temp_hash.has_key(result['test']):
temp_hash[result['test']] = int(temp_hash[result['test']]) + 1
else:
temp_hash[result['test']] = 1
How to simplify this code using only mongodb logic ?
Take a look at gcount sample at
http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group. For example, you can do something like:
result = coll.group(['test'],
None,
{ count : 0 },
'function(obj, prev) {prev.count++;}')

Retrieve unique random items from a mongodb collection?

I run an IRC bot and I have a function which returns 1 random url using Math.random at the moment, from my Mongodb collection.
I would like to refactor it to return x number of unique items, and for each subsequent invocation of the url fetching command .getlinks I would like that it keeps everything unique, so that a user doesn't see the same link unless all the possible links have been already returned.
Is there some algorithm or native mongodb function I could use for this?
Here's a sample scenario:
I have a total of 9 records in the collection. They have a _id and url field.
user a: .getlinks()
bot returns: http://unique-link-1, http://unique-link-2, http://unique-link-3, http://unique-link-4
user a: .getlinks()
bot returns: http://unique-link-5, http://unique-link-6, http://unique-link-7, http://unique-link-8
user a: .getlinks()
bot returns: http://unique-link-9, http://unique-link-6, http://unique-link-1, http://unique-link-3
Background information:
There's a total of about 200 links. I estimate that will grow to around 5000 links by the end of next year.
Currently the only thing I can think of is keeping an array of all returned items, and grabbing all items from the collection at once and getting a random one 4 times and making sure it's unique and hasn't been shown already.
var shown = [], amountToReturn = 4;
function getLinks() {
var items = links.find(), returned = [];
for ( var i = 0; i<amountToReturn; i++ ) {
var rand = randItem( items );
if ( shown.indexOf( rand.url ) == -1 && shown.length < items.length ) ) {
returned.push( rand.url );
}
}
message.say( returned.join(',') );
}
You should find a number of possible options to get random item(s) from Collection here ...
http://jira.mongodb.org/browse/SERVER-533
Another intersting method is documented here ...
http://cookbook.mongodb.org/patterns/random-attribute/
The method mentioned above basically creates a new key/value on the document using Math.random()
> db.docs.drop()
> db.docs.save( { key : 1, ..., random : Math.random() } )
> db.docs.save( { key : 1, ..., random : Math.random() } )
> db.docs.save( { key : 2, ..., random : Math.random() } )
... many more insertions with 'key : 2' ...
> db.docs.save( { key : 2, ..., random : Math.random() } )
...
Get random records form mongodb via map/reduce
// map
function() {
emit(0, {k: this, v: Math.random()})
}
// reduce
function(k, v) {
var a = []
v.forEach(function(x) {
a = a.concat(x.a ? x.a : x)
})
return {a:a.sort(function(a, b) {
return a.v - b.v;
}).slice(0, 3 /*how many records you want*/)};
}
// finalize
function(k, v) {
return v.a.map(function(x) {
return x.k
})
}