Google Sheets Horizontal Radio checkboxes - google-apps-script

I am trying to create radio checkboxes, i managed to make it work when the checkboxes are in vertical as shown in the exemple sheet bellow with the tab name 'Radio 1' but i have another tab 'Radio 2' where the checkboxes are aligned horizontally and are not aligned one after the other but after every 2 cells, the first Radio works with the following code
function onEdit(e) {
if (e.range.columnStart != 2 || e.range.rowStart == 1 || e.range.rowStart > 8 || e.value != "TRUE") return;
let r = SpreadsheetApp.getActive().getActiveSheet().getRange(2,2,7);
let checks = r.getValues();
for (let i in checks){
if(checks[i][0] == true && +i != e.range.rowStart - 2)
checks[i][0] = false;
}
r.setValues(checks);
}
but i cant make it to work when adapting to the second radio tab, any ideas?
sheet link

Try
function onEdit(e) {
var sh = e.source.getActiveSheet()
if (sh.getName() == 'Radio 1') {
if (e.range.columnStart != 2 || e.range.rowStart == 1 || e.range.rowStart > 8 || e.value != "TRUE") return;
let r = SpreadsheetApp.getActive().getActiveSheet().getRange(2, 2, 7);
let checks = r.getValues();
for (let i in checks) {
if (checks[i][0] == true && +i != e.range.rowStart - 2)
checks[i][0] = false;
}
r.setValues(checks);
}
else if (sh.getName() == 'Radio 2') {
var cel = e.source.getActiveRange()
if (cel.getRow() == 11 && cel.getValue() == true) {
var r = sh.getRange('H' + cel.getRow() + ':S' + cel.getRow())
var checks = r.getValues()
for (var i=0;i<checks[0].length;i+=2) {
if (checks[0][i] == true && i != cel.getColumn()-8)
if (checks[0][i]==true) {checks[0][i] = false};
}
r.setValues(checks);
}
}
}
If you want to apply to multi-rows, change this cel.getRow() == 11

In your situation, how about the following modification?
Modified script:
In this modification, the cell ranges of checkboxes are used.
function onEdit(e) {
// This is from your sample Spreadsheet.
// The cell ranges of checkboxes are set as A1Notation.
const obj = {
'Radio 1': ["B2", "B3", "B4", "B5", "B6", "B7", "B8"],
'Radio 2': ["H11", "J11", "L11", "N11", "P11", "R11"]
};
const sheet = e.source.getActiveSheet();
const sheetName = sheet.getSheetName();
const a1Notation = e.range.getA1Notation();
if (!obj[sheetName] || !obj[sheetName].includes(a1Notation) || e.range.getValue() === false) return;
sheet.getRangeList(obj[sheetName].filter(e => e != a1Notation)).uncheck();
}
When this script is run, when a checkbox is checked on "Radio 1" or "Radio 2", other checked checkboxes are unchecked.
If you want to add "Radio 3" and others, please add them to obj.
Note:
When you changed the checkboxes and the sheet names, please modify obj. Please be careful about this.
References:
filter()
uncheck() of Class RangeList

Related

Problem with script not unchecking boxes when checking another one in google sheet

Trying to set up an onedit script for google sheet that unchecks all tickboxes in one column when a new one in the same column is ticked in.
function onEdit(e){
if(e.range.columnStart != 1 || e.value == "FALSE") return;
for(var i=1;i<100;i++){
if(i == e.range.rowStart) continue;
// Here I am trying to check if the cell has the value TRUE and if so change it to FALSE.
if(e.source.getActiveSheet().getRange(i,1).value == "TRUE"){
e.source.getActiveSheet().getRange(i,1).setValue("FALSE");
}
}
}
I'm going through the cells with an FOR statement and try to check if they have the value TRUE and if so change it to FALSE. It seems to not detect any TRUE though. If I remove the IF statement it does keep the newly checked box checked but fills the whole column with the FALSE value.
What is it that I am missing or have misunderstood trying to use the IF statement to detect TRUE and change it to FALSE?
Managed to solve it. Instead of checking for the value TRUE I tried to use the isChecked() function and it works.
function onEdit(e){
if(e.range.columnStart != 1 || e.value == "FALSE") return;
for(var i=1;i<100;i++){
if(i == e.range.rowStart) continue;
if(e.source.getActiveSheet().getRange(i,1).isChecked() == true){
e.source.getActiveSheet().getRange(i,1).setValue("FALSE");
}
}
}
It should be a bit faster this way:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() != "Your Sheetname" || e.range.columnStart != 1 || e.value == "FALSE") return;
let vs = sh.getRange(1, 1, sh.getLastRow(), 1).getValues()
vs.forEach((r, i) => {if (i + 1 != e.range.rowStart) { vs[i][0] = "FALSE" }});
sh.getRange(1, 1, vs.length, vs[0].length).setValues(vs);
}
If you your using its in a bunch of sheets, you could use:
if(!~['Sheet1','Sheet2].indexOf(sh.getName()) || e.range.columnStart != 1 || e.value == "FALSE") return;

Combining two onEdit() in single Google Sheets App Script

I am trying to combine two onEdit functions in a single App Script. I have read through other posts on this subject and feel like I have integrated their suggestions but it is still not working.
Function A (timeStamp) places a time stamp in column B when columnn A is edited
Function B (arhviveRow) copies the edited row to sheet "Inactive" when a check box is marked True on sheet "Active" and then deletes the row from sheet "Active".
Both functions work correctly when run separately, but only the second function works when combined.
function onEdit(e) {
timeStamp();
archiveRow();
//Automatically stamp date and time on line
function timeStamp() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Active" ) { //checks that we're on Sheet1 or not
var r = s.getActiveCell();
if( r.getColumn() == 1 ) { //checks that the cell being edited is in column A
var nextCell = r.offset(0, 1);
if( nextCell.getValue() === "" ) //checks if the adjacent cell is empty or not?
nextCell.setValue(new Date() + new (Time));
}
}
}
//Archive and delete line
function archiveRow(){
//ColumnNumberToWatch defines which column on sheet to monitor for an edit
var ss = e.source,
sheet = ss.getActiveSheet(),
range = e.range,
targetSheet,
columnNumberToWatch = 9; // column A = 1, B = 2, etc
// "sheet.getName() ===" defines which sheet to watch for the edit
// "targetSheet =" defines sheet to copy data to
if (sheet.getName() === "Active" && e.value === "TRUE" && e.range.columnStart === columnNumberToWatch) {
targetSheet = "Inactive"
} else if (sheet.getName() === "Inactive" && e.value === "FALSE" && e.range.columnStart === columnNumberToWatch) {
targetSheet = "Active"
}
//Copies data to last row in targetSheet and then deletes from source sheet
ss.getSheetByName(targetSheet)
.appendRow(sheet.getRange(e.range.rowStart, 1, 1, sheet.getLastColumn())
.getValues()[0])
sheet.deleteRow(e.range.rowStart);
}
}
Any insights into where I went wrong would be greatly appreciated.
Thanks!
The new Date() object should already contain the time, and there is no Javascript Object for new Date(Time).
It should look like this:
function timeStamp() {
var s = SpreadsheetApp.getActiveSheet();
Logger.log(s);
if( s.getName() == "Active" ) { //checks that we're on Sheet1 or not
var r = s.getActiveCell();
if( r.getColumn() == 1 ) { //checks that the cell being edited is in column A
var nextCell = r.offset(0, 1);
if( nextCell.getValue() === "" ) {//checks if the adjacent cell is empty or not?
nextCell.setValue(new Date().toLocaleString());
}
}
}
}
Sample output for the date:
Active Sheet
Once the checkbox was clicked setting the value to TRUE, appends the row to the "Inactive" sheet.
Inactive Sheet
function onEdit(e) {
const sh = e.range.getSheet();
const name = sh.getName():
if (name == "Active" && e.range.columnStart == 1) {
e.range.offset(0, 1).setValue(Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy HH:mm:ss"));
}
if (name == 'Active' && e.range.columnStart == 9 && e.value == "TRUE") {
let tsh = e.source.getSheetByName('Inactive');
tsh.appendRow(sh.getRange(e.range.rowStart, 1, 1, sh.getLastColumn()).getValues()[0]);
sh.deleteRow(e.range.rowStart())
} else if (name = 'Inactive' && e.range.columnStart == 9 && e.value == "FALSE") {
let tsh = e.source.getSheetByName('Active');
tsh.appendRow(sh.getRange(e.range.rowStart, 1, 1, sh.getLastColumn()).getValues()[0]);
sh.deleteRow(e.range.rowStart());
}
}

Get on edit macro working on google form responses tab

I have the following code that works perfect on the rest of my google sheet
but as people have started missing data when filling in the sheet i have made a google form for them to use when adding in the information
The only issue is that my "onedit" macro works on every tab except the "responses tab" from the google form
Is there any way to get this to work?
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
var value = e.range.getValue();
var sheet = e.source.getActiveSheet().getName();
var destination = e.source.getActiveSheet().getRange(row,21);
var destination2 = e.source.getActiveSheet().getRange(row,22);
if(col === 1 && row > 1 && value === "NO" && destination.getValue() ===""){
e.source.getActiveSheet().getRange(row,21).setValue(new Date(new Date().setHours(0,0,0,0))).setNumberFormat('dd-MMM-yy');
}
if(col === 1 && row > 1 && value === "YES" && destination2.getValue() ===""){
e.source.getActiveSheet().getRange(row,22).setValue(new Date(new Date().setHours(0,0,0,0))).setNumberFormat('dd-MMM-yy');
}
}
function onEdit(e) {
const sh = e.range.getSheet();
const nd = new Date();
const dt = new Date(dt.getFullYear(), nd.getMonth(), nd.getDate());
if (e.range.columnStart == 1 && e.range.rowStart > 1 && e.value == "NO" && sh.getRange(e.range.rowStart, 21).getValue() == "") {
sh.getRange(e.range.rowStart, 21).setValue(nd).setNumberFormat('dd-MMM-yy');
}
if (e.range.columnStart == 1 && e.range.rowStrart > 1 && e.value === "YES" && sh.getRange(e.range.rowStart, 22).getValue() == "") {
sh.getRange(e.range.rowStart, 22).setValue(nd).setNumberFormat('dd-MMM-yy');
}
}

Hide/unhide rows based on checkbox on Google sheet

I have a Google spreadsheet which has checkboxes in column P, as and when a checkbox is ticked the corresponding row automatically hides.
I am looking to add an additional check box in G1 that will show all hidden rows if checked and if possible a checkbox in E1 to then hide again all the rows that have the checkbox ticked in column P.
Basically I want to automatically hide rows when I tick the checkbox in column P
Then later I may need to review the hidden rows by clicking the checkbox in G1.
When I am finished reviewing the hidden rows above click a checkbox in E1 and all rows which are checked in column P will hide again.
function onEdit(e){
if (e.range.columnStart != 16 || e.value != "TRUE") return;
SpreadsheetApp.getActiveSheet().hideRows(e.range.rowStart);
}
Solution:
Check if edited cell is G1 via getA1Notation(). In that case, check if value is TRUE, and if that's the case, show all rows. An easy option to show all rows is using unhideRow(row), setting A:A as your range (since this includes all rows in the sheet).
Check if edited cell is E1. If the value is TRUE, retrieve all values from P column via getValues(), iterate through them, and hide the corresponding rows if the value is true, using hideRows(rowIndex).
Check if the edited cell is in column P, and use hideRows on the edited row if that's the case, as you're already doing.
Code snippet:
function onEdit(e){
const sheet = SpreadsheetApp.getActiveSheet();
const range = e.range;
const editedValue = e.value;
if (range.getA1Notation() === "G1" && editedValue === "TRUE") {
sheet.unhideRow(sheet.getRange("A:A"));
} else if (range.getA1Notation() === "E1" && editedValue === "TRUE") {
const firstRow = 2;
const lastRow = sheet.getLastRow();
const pValues = sheet.getRange("P" + firstRow + ":P" + lastRow).getValues().flat();
pValues.forEach((pValue,i) => {
if (pValue === true) {
sheet.hideRows(i + firstRow);
}
});
} else if (e.range.columnStart === 16 && editedValue === "TRUE") {
sheet.hideRows(range.rowStart);
}
}
I know it is a bit of an old thread, but still very helpfull to al lot of people i guess. Both the code from the TS and the answer were very helpfull.
I used this for a similar project and found it a bit strange to have two checkboxes to show/hide rows though, so i made this work with one checkbox in cell "G1" to toggle the view hide/unhide.
Code Snippet
function onEdit(e){
const sheet = SpreadsheetApp.getActiveSheet();
const range = e.range;
const editedValue = e.value;
if (range.getA1Notation() === "G1" && editedValue === "TRUE") {
sheet.unhideRow(sheet.getRange("A:A"));
} else if (range.getA1Notation() === "G1" && editedValue === "FALSE") {
const firstRow = 2;
const lastRow = sheet.getLastRow();
const pValues = sheet.getRange("P" + firstRow + ":P" + lastRow).getValues().flat();
pValues.forEach((pValue,i) => {
if (pValue === true) {
sheet.hideRows(i + firstRow);
}
});
} else if (e.range.columnStart === 16 && editedValue === "TRUE") {
sheet.hideRows(range.rowStart);
}
}

Google Sheets, Moving from one Tab to another via input

I am trying to get this script working where it will work when I put a "yes" or "no" for a choice it will move based on the "yes" to the targeted sheet "Completed Dispatch"
The original sheet is called "Tracker" and the column that I need it to check the "Yes or No" is called "Dispatched"
It doesn't work and I am not that great in GAS
The actual problem I am having is when I make the decision from no to Yes it does not move the row and does not do anything at all.
function onEdit(e) {
var ss = e.source,
sheet = ss.getActiveSheet(),
range = e.range,
targetSheet,
columnNumberToWatch = 9; // column A = 1, B = 2, etc
if (sheet.getName() === "Tracker" && e.value === "Dispatched" && e.range.columnStart === columnNumberToWatch) {
targetSheet = "Completed Dispatch"
} else if (sheet.getName() === "Completed Dispatch" && e.value === "Incomplete" && e.range.columnStart === columnNumberToWatch) {
targetSheet = "Tracker"
}
ss.getSheetByName(targetSheet)
.appendRow(sheet.getRange(e.range.rowStart, 1, 1, sheet.getLastColumn())
.getValues()[0])
sheet.deleteRow(e.range.rowStart);
}