Navigate/select ag-grid table row with arrow keys - reactjs

I'm trying to navigate the rows of an ag-grid table on a react app. This means when I press up or down, the current selected row changes to the previous/next row.
I've tried the example on the ag-grid docs. But I don't know how to access the gridOptions.
How would I make this work?

I think I found a way, although I'm using useRef and I'd prefer to avoid it.
This is the main function:
const arrowKeysNavigation = (tableRef) => (params) => {
var previousCell = params.previousCellPosition;
var suggestedNextCell = params.nextCellPosition;
const api = tableRef.current.api;
var KEY_UP = 38;
var KEY_DOWN = 40;
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
switch (params.key) {
case KEY_DOWN:
previousCell = params.previousCellPosition;
// set selected cell on current cell + 1
api.forEachNode(function (node) {
if (previousCell.rowIndex + 1 === node.rowIndex) {
node.setSelected(true);
}
});
return suggestedNextCell;
case KEY_UP:
previousCell = params.previousCellPosition;
// set selected cell on current cell - 1
api.forEachNode(function (node) {
if (previousCell.rowIndex - 1 === node.rowIndex) {
node.setSelected(true);
}
});
return suggestedNextCell;
case KEY_LEFT:
case KEY_RIGHT:
return suggestedNextCell;
default:
throw new Error(
"this will never happen, navigation is always one of the 4 keys above"
);
}
};
The main steps:
Create ref const tableRef = React.useRef();
Associate it to ag-grid together with the function above:
<AgGridReact ... ref={tableRef} navigateToNextCell={arrowKeysNavigation(tableRef)}/>

Related

How do you use multiple scripts in the same spreadsheet?

I have a spreadsheet that tracks legal cases from start to finish. In that spreadsheet I used a script to create dependent dropdown menus on multiple rows (I'll share the script at the end). The main dropdown menu tells me what Department the case is in. The Departments are Transcription; Doctor; Scheduling; Records; QA; and Billing.
I also have a script that is supposed to moves an entire row of data to a separate tab labeled Billing when the department dropdown menu is set to Billing. I had this script working before I made the dependent dropdown menus and was just using data validation to create my dropdown menu.
Both of these scripts work separately but when I try to use them together the dependent dropdown menus quit working and when the department is set to Billing that row disappears like its supposed to except it doesn't show up on the Billing tab like its supposed to. I have no idea where it goes.
Can someone please tell me how to get both scripts to work at the same time? And, why the row of data disappears when the department is set to Billing but doesn't go to the Billing tab?
Dependent Dropdown Menu Script
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database");
var wsOptions = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("options");
var options = wsOptions.getRange(2,1,wsOptions.getLastRow()-1,2).getValues();
function myFunction() {
var list = ["a","b","c","f"];
var cell = ws.getRange("J2");
applyValidationToCell(list,cell);
}
function onEdit(event){
var activeCell = event.range;
var value = activeCell.getValue();
var row = activeCell.getRow();
var column = activeCell.getColumn();
var wsName = activeCell.getSheet().getName();
if(wsName == "Database" && column === 5 && row > 1){
if(value === ""){
ws.getRange(row,10).clearContent();
ws.getRange(row,10).clearValidations();
} else{
ws.getRange(row,10).clearContent();
var filteredOptions = options.filter(function(options){ return options[0] === value });
var listToApply = filteredOptions.map(function(options){ return options[1] });
Logger.log(listToApply);
var cell = ws.getRange(row,10);
applyValidationToCell(listToApply,cell);
}
}
}
function applyValidationToCell(list,cell){
var rule = SpreadsheetApp
.newDataValidation()
.requireValueInList(list)
.setAllowInvalid(false)
.build();
cell.setDataValidation(rule);
}
Billing Script
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database");
var wsOptions = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("options");
var options = wsOptions.getRange(2, 1,wsOptions.getLastRow()-1,2).getValues();
function myFunction() {
var list = ["a","b","g"];
var cell = ws.getRange("K2");
applyValidationToCell(list,cell);
}
function onEdit(e){
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var wsName = activeCell.getSheet().getName();
if(wsName == "Database" && c === 5 && r > 1){
var filteredOptions = options.filter(function(o){return o[0] === val});
var listToApply = filteredOptions.map(function(o){ return o[1]});
console.log(listToApply);
var cell = ws.getRange(r, 10);
applyValidationToCell(listToApply,cell);
}
}
function applyValidationToCell(list,cell){
var rule = SpreadsheetApp
.newDataValidation()
.requireValueInList(list)
.setAllowInvalid(false)
.build();
cell.setDataValidation(rule);
}
function onEdit(e) {
const src = e.source.getActiveSheet();
const r = e.range;
if (r.columnStart != 5|| r.rowStart == 2 || e.value == src.getName()) return;
const dest = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(e.value);
src.getRange(r.rowStart,1,1,30).moveTo(dest.getRange(dest.getLastRow()+1,1,1,30));
src.deleteRow(r.rowStart);
}
All functions have to have a unique name and all functions have access to all sheets. onedit triggers are generated on every user edit and it's up to the onEdit function to route edits from the appropriate sheets using information gathered from the event object. Note: Sheet Name = e.range.getSheet().getName() where e is populated by the event object in the function declaration function onEdit(e) {}
The if statement below limits access to edits that occur on Sheet name "Database" and e.range.columnStart == 5 and rows greater than one
if(wsName == "Database" && column === 5 && row > 1){
if(value === ""){
ws.getRange(row,10).clearContent();
ws.getRange(row,10).clearValidations();
} else{
ws.getRange(row,10).clearContent();
var filteredOptions = options.filter(function(options){ return options[0] === value });
var listToApply = filteredOptions.map(function(options){ return options[1] });
Logger.log(listToApply);
var cell = ws.getRange(row,10);
applyValidationToCell(listToApply,cell);
}
}
if you require actions from other sheets then you must add more if statements or other conditional logic to route the appropriate edit traffic to the the correct processing statements.

Update Set after delete using a checkbox to delete Set Item

I am using a checkbox to select items.
When the checkbox is checked, item is added to a Set stored in state.
When checkbox is unchecked, item is deleted from the Set stored in state
Upon verifying if item was removed from Set, the function
set.has(setItem)
returns false.
However when checking the size of the Set, it is as if I did not remove anything.
I'm probably not updating the set to account for the deleted item.
Can anyone help?
my handleChange function below...
const handleChange = (e) => {
if (e.target.checked) {
var checkedItemId = parseInt(e.target.value)
setCheckedItems(new Set(checkedItems.add(checkedItemId)))
}else if(!e.target.checked){
checkedItems.delete(checkedItemId)
setCheckedItems(new Set(checkedItems))
}
}
const handleChange = (e) => {
const checkedItemId = parseInt(e.target.value);
if (e.target.checked) {
setCheckedItems(prevState => {
let newSetCheckedItems = new Set(...prevState.checkedItems);
return newSetCheckedItems.add(checkedItemId);
})
} else if (!e.target.checked) {
setCheckedItems(prevState => {
let newSetCheckedItems = new Set(...prevState.checkedItems);
return newSetCheckedItems.detele(checkedItemId);
});
}
}
The solution was to use a deep copy of the set.
Do the adding/removing operations on that deep copy.
Then update the set with the deep copy.
//i don't know about the react but i can give you solution in the jquery.
var new_arr=[];
$(document.body).on('click','.class_name',function(){
var is_checked = $(this).is(':checked');
var value_check_box = $(this).val();
if(is_checked==true){
// push the value of the check box in the array variable
new_arr.push(value_check_box);
}else{
var removeItem = value_check_box // it is the value when the user uncheck the uncheckbox;
new_arr = jQuery.grep(new_arr, function(value) {
return value != removeItem;
});
};
})

Radiogroup keyboard navigation

I have a radio group that is set in a table layout:
https://fiddle.sencha.com/#view/editor&fiddle/2ehg
If you navigate around that radio group with left, right, up and down keys, the behaviour is unintuitive. I have searched the code and tried to debug the focus event on the radios, but did not find how/where ExtJS code navigates through the components.
How can I improve the keyboard navigation such that it behaves natural?
With the keyMap config and listening on the navigation key events you can prevent the browser default, calculate the new position and set it.
See the working fiddle.
It reacts more than you would expect. When you are on the first item and you press the up-button the new focused item is the last one in the row.
You may have to tweak left and right accordingly to fit your needs.
// get the id for the component from the event
const getPureId = (event) => event.target.id.split('-').splice(0, 2).join('-');
const columnCount = 2;
const maxIndex = 5;
const minIndex = 0;
// config of the panel ...
keyMap : {
[Ext.event.Event.DOWN]: (event, panel) => {
var pureId = getPureId(event);
var comp = Ext.get(pureId).component;
var pos = panel.items.indexOf(comp);
var newPos = pos + columnCount;
// when the newPos is outside of our boundaries we calculate the new one
// based on the columnCount
if (newPos > maxIndex) {
newPos = newPos % (columnCount + 1);
}
event.preventDefault();
panel
.getComponent(newPos)
.focus()
.setValue(true);
}, [Ext.event.Event.UP]: (event, panel) => {
var pureId = getPureId(event);
var comp = Ext.get(pureId).component;
var pos = panel.items.indexOf(comp);
var newPos = pos - columnCount;
// when the newPos is outside of our boundaries we calculate the new one
// based on the maxIndex
if (newPos < minIndex) {
newPos = newPos + maxIndex + 1;
}
event.preventDefault();
panel
.getComponent(newPos)
.focus()
.setValue(true);
}
},
// more config of the panel ...

Trying to addEventListener to looped array

I'm pretty sure I've coded the event handler part wrong. When the array goes through and loops it does product a list on the page. I just need that list clickable with an event listener, then a series of re-direct based on if statements for comparison...ideas ?
window.onload = eventMonitor;
function eventMonitor(){
document.getElementById("names").addEventListener('click', reRoute, false);
document.getElementById("hiddenText").addEventListener('mouseover', treasureRoute, false);
function createName(){
var streetNames = ["Carmen", "Napoli", "Oscar", "Haven", "Tampa"];
//this top partscript creates a for loop that will take each array [item] and simply right it to the screen.
for (i=0; i<streetNames.length; i++){
var mName = "Martin";
var node = document.createElement("li");
var textNode = document.createTextNode(mName + " " + (streetNames[i]));
node.appendChild(textNode);
document.getElementById("names").appendChild(node);
}
}
function reRoute(){
if(names === 'Martin Carmen'){
routeWindow = window.open("https://en.wikipedia.org/wiki/MSC_Carmen");
}
else if(names === 'Martin Napoli'){
routeWindow = window.open("https://en.wikipedia.org/wiki/MSC_Napoli")
}
else if(names === 'Martin Oscar'){
routeWindow = window.open("https://en.wikipedia.org/wiki/MSC_Oscar")
}
else if(names === 'Martin Haven'){
routeWindow = window.open("https://en.wikipedia.org/wiki/MT_Haven")
}
else if(names === 'Martin Tampa'){
routeWindow = window.open("https://en.wikipedia.org/wiki/MV_Tampa")
}
}
function treasureRoute(){
shipWindow = window.open("file:///Users/User/something.html");
}
}
What you want to do does not require JavaScript. JavaScript, while useful in many circumstances, is error prone as you have noticed. The anchor tag is used to navigate between pages, which is why you inject <li>Text</li> elements into the DOM.
If you would nonetheless want to use JavaScript in a situation like yours, you would program your event handler to comply with the addEventListener API:
const names = document.getElementById('names');
names.addEventListnener('click', event => {
const { target } = event;
console.log(`${target.tagName} was clicked!`);
});

combo box formula item and value

I have the following formula in a Combo Box:
var keyObj = getComponent('ACConditionToggle');
var key = keyObj.getSubmittedValue();
if (!key || key==''){
key = keyObj.getValue();
}
switch(key)
{
case 'Approval':
return ['% Approval' , 'Approvers']
break;
case 'Denial':
return ['% Denial', 'Deniers']
default:
return new Array();
}
It works fine, however, I want to have labels different from the value. SO in this case with the label '% Approval' I want a value of 'Percent' and for for 'Approvers' the value of 'Number'
So how do I pass the label and the value from a formula. I can do that with static and get itemLabel and itemValue but how do I differential them in the formula?
after beating my head against the wall I found the answer to be so simple.
var keyObj = getComponent('ACConditionToggle');
var key = keyObj.getSubmittedValue();
var rtnArray = new Array();
if (!key || key==''){
key = keyObj.getValue();
}
switch(key)
{
case 'Approval':
rtnArray[0]="% Approval|Percent";
rtnArray[1]="Approver(s)|Number";
return rtnArray;
break;
case 'Denial':
rtnArray[0]="% Denial|Percent";
rtnArray[1]="Denials(s)|Number";
return rtnArray;
break
default:
return new Array();
}

Resources