In essence I'm trying to have a checkbox trigger addition. I have a number in Column A. When that number is entered checkboxes will appear in Column G. When that checkbox is checked I want it to trigger the addition function and add 1 to the same row in column A and not affect the other rows and then uncheck the checkbox.
So far, this is only working with Row 1 and not the other rows and I am not exactly sure why.
function onEdit (e) {
checkboxes(e);
addition(e)
}
function checkboxes(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ui = SpreadsheetApp.getUi();
var names = ss.getRange("A1:A");
var namesValues = names.getValues();
var checkboxes = ss.getRange("G1:G");
var cbRows = checkboxes.getHeight();
var cbValues = checkboxes.getValues();
var newCBValues = new Array(cbRows);
for (var row = 0; row < cbRows; row++) {
newCBValues[row] = new Array(0);
if (namesValues[row] == "" || namesValues[row] == " ") {
newCBValues[row][0] = " ";
}else{
if (cbValues[row][0] === true) {
newCBValues[row][0] = true;
}else{
newCBValues[row][0] = false;
}
}
}
checkboxes.setValues(newCBValues);
}
function addition(e) {
var ss = SpreadsheetApp.getActiveSheet();
var boxey = ss.getRange("G1:G")
var isAdd = boxey.getValue();
if (isAdd) {
Add();
boxey.setValue(false);
}
function Add() {
var ss = SpreadsheetApp.getActiveSheet();
var numbers = ss.getRange("A1:A");
numbers.setValue(numbers.getValue()+1);
}
Add one to column A of current row when checkbox in column G is checked
function onEdit(e) {
if (e.range.columnStart == 7 && e.value == "TRUE") {
const sh = e.range.getSheet();
sh.getRange(e.range.rowStart, 1).setValue(sh.getRange(e.range.rowStart, 1).getValue() + 1);
sh.getRange(e.range.rowStart, 7).setValue("FALSE")
}
checkboxes(e);//your current code
addition(e);//your current code
}
Related
I have 1 spreadsheet with multiple sheets.
The 1st and the 2nd sheets sometimes have similar data in the rows (duplicates). Also, each sheet has a column (8) with a checkbox.
Task: I need to move one of the duplicates to the 3rd sheet when the checkboxes in both sheets (1st and 2nd) are checked.
Here is the code that moves the row when it's checked in a single sheet.
Can someone help me modify it to complete my task?
function onEdit(e) {
let range = e.range;
let col = range.getColumn();
let row = range.getRow();
let val = range.getValue();
let source = e.source.getActiveSheet();
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sourceSheet = ss.getSheetByName(source.getName());
if (sourceSheet.getName() == 'SHEET1' && col == 8 && val == true){
let data = sourceSheet.getRange(row,1,1,7).getValues();
let targetSheet = ss.getSheetByName('SHEET2');
targetSheet.appendRow(data[0]);
sourceSheet.deleteRow(row);
}
if (sourceSheet.getName() == 'SHEET2' && col == 8 && val == true){
let data = sourceSheet.getRange(row,1,1,7).getValues();
let targetSheet = ss.getSheetByName('SHEET3');
targetSheet.appendRow(data[0]);
sourceSheet.deleteRow(row);
}
}
Sample Spreadsheet
Apply filter()
You can add the filter() method (combined with the JSON.stringify() method) to your script to determine if a row is a duplicate of another from the other sheet. The modified script should somehow look like this:
function onEdit(e) {
var range = e.range;
var col = range.getColumn();
var row = range.getRow();
var val = range.getValue();
var source = e.source.getActiveSheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName(source.getName());
var targetSheet = ss.getSheetByName('Sheet3');
//If Sheet1 checkbox is triggered
if (sourceSheet.getName() == 'Sheet1' && col == 8 && val == true) {
var rowArr = ss.getSheetByName('Sheet1').getRange(row, 1, 1, 8).getValues();
var lastRow2 = ss.getSheetByName('Sheet2').getLastRow();
var sheet2Values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2').getRange(1, 1, lastRow2, 8).getValues();
var count = sheet2Values.filter(x => {
return (JSON.stringify(x) === JSON.stringify(rowArr[0]))
});
var otherRow = sheet2Values.map((x, i) => {
if (JSON.stringify(x) === JSON.stringify(rowArr[0])) {
return i;
}
});
if (count.length > 0) {
var otherRow = sheet2Values.map((x, i) => {
if (JSON.stringify(x) === JSON.stringify(rowArr[0])) {
return i;
}
}).filter(y => y);
rowArr[0].pop();
targetSheet.appendRow(rowArr[0]);
sourceSheet.deleteRow(row);
var otherSheet = ss.getSheetByName('Sheet2');
otherSheet.deleteRow(otherRow[0] + 1)
}
}
//If Sheet2 checkbox is triggered
if (sourceSheet.getName() == 'Sheet2' && col == 8 && val == true) {
var rowArr = ss.getSheetByName('Sheet2').getRange(row, 1, 1, 8).getValues();
var lastRow = ss.getSheetByName('Sheet1').getLastRow();
var sheet1Values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1').getRange(1, 1, lastRow, 8).getValues();
var count = sheet1Values.filter(x => {
return (JSON.stringify(x) === JSON.stringify(rowArr[0]))
});
if (count.length > 0) {
var otherRow = sheet1Values.map((x, i) => {
if (JSON.stringify(x) === JSON.stringify(rowArr[0])) {
return i;
}
}).filter(y => y);
rowArr[0].pop();
targetSheet.appendRow(rowArr[0]);
sourceSheet.deleteRow(row);
var otherSheet = ss.getSheetByName('Sheet1');
otherSheet.deleteRow(otherRow[0] + 1)
}
}
}
Output
Based on your sample spreadsheet, the modified script should work as shown below:
Please take note that the appendRow() method appends any row to the last non-empty row in the sheet. A row with a checkbox is not considered to be an empty row thus explains the behavior of the output.
Reference
filter()
JSON.stringify()
Would that do what you want ?
function copyDuplicateRows() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet1 = spreadsheet.getSheetByName("Sheet1");
var sheet2 = spreadsheet.getSheetByName("Sheet2");
var sheet3 = spreadsheet.getSheetByName("Sheet3"); // destination sheet
var data1 = sheet1.getDataRange().getValues();
var data2 = sheet2.getDataRange().getValues();
// Use a JavaScript object to keep track of duplicate rows
var seen = {};
// Iterate through data1 and copy unique rows to sheet3
for (var i = 0; i < data1.length; i++) {
var row = data1[i];
var key = row.join(); // create a unique key for each row
if (!seen[key]) {
seen[key] = true;
sheet3.appendRow(row);
}
}
// Iterate through data2 and copy unique rows to sheet3
for (var i = 0; i < data2.length; i++) {
var row = data2[i];
var key = row.join();
if (!seen[key]) {
seen[key] = true;
sheet3.appendRow(row);
}
}
}
In sheet 'Template', I have a data validation column B and I would like to change the value in this column, if value in column AB equals X or Y. Otherwise, I want the value in column B to be the same.
I found the following script which doesn't make much sense to me
function Test1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Template");
var numRows = SpreadsheetApp.getActiveSheet().getLastRow();
var range;
/* Loop through Column AB and find cells equal to order payment
and set Column B value based on it */
for (var i = 1; i <= numRows; i++) {
range = s.getRange('AB' + i );
if (range.getValue() == "X") {
range.offset(0, 6).setValue("X");
}
else {
range.offset(0,6).setValue("NO");
}
}
}
please check if this code works for you:
function Test1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Template");
// 27 = number of columns
var sheetContent = s.getRange(1,2,s.getLastRow(),27).getValues();
for (var i = 0; i < sheetContent.length; i++) {
if(sheetContent[i][26] == "X" || sheetContent[i][26] == "Y"){
//You can replace the updated value by anything you want it to be.
sheetContent[i][0] = "Updated Value";
}
}
s.getRange(1,2,sheetContent.length,sheetContent[0].length).setValues(sheetContent);
}
Try this:
function Test1() {
const ss = SpreadsheetApp.getActive();
const sh= ss.getSheetByName("Template");
const vs = sh.getRange(1,2,sh.getLastRow(),sh.getLastColumn()).getValues()
let a = vs.map((r,i) => {
if(r[27] == "X" || r[27] == "Y") {
return ["Yes"];
} else {
return [r[1]];
}
});
sh.getRange(1,2,a.length, a[0].length).setValues(a);
}
I'm trying to have TIMEVALUE set off a script. I have column P which is a Timer column that is subtracting a time from NOW to get a time value and then I am converting that to a TIMEVALUE in column O. When that value is either below or above certain values I want column N to then have a value so it would trigger my checkboxes script. But for some reason I can't get the TIMEVALUE to trigger. I tried to put it in another column and have the values CopyAndPasted Values Only into a column with that run on a time trigger of every minute, but apparently that doesn't count as an Edit or it's not reading the DisplayValue.
function onEdit(e) {
timeValue(e);
checkboxes(e);
rangerTime(e);
}
function rangerTime(e){
var editRow = e.range.getRow();
var editColumn = e.range.getColumn();
if (editColumn === 13 && e.value == "TRUE") {
const sh = e.range.getSheet();
sh.getRange(editRow, 25).setValue(sh.getRange(editRow, 25).getValue()+1);
sh.getRange(editRow, 13).setValue(" ")
}
}
function timeValue(e) {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
var editRow = e.range.getRow();
var editColumn = e.range.getColumn();
if(editRow > 3) {
var rowRange = sheet.getRange("O" + editRow);
var kCell = sheet.getRange("K" + editRow);
var kValue = kCell.getValue();
var nCell = sheet.getRange("N" + editRow);
var kHasValue = kValue != "";
if(editColumn > 10) {
if(rowRange.getDisplayValue()<0.02 && !kHasValue){
nCell.setValue(1);
}
if (rowRange.getDisplayValue()>0.5 && !kHasValue){
nCell.setValue(1);
}
if(kHasValue) {
nCell.setValue(" ");
}
}
}
}
function checkboxes(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ui = SpreadsheetApp.getUi();
var names = ss.getRange("N4:N");
var namesValues = names.getValues();
var checkboxes = ss.getRange("M4:M");
var cbRows = checkboxes.getHeight();
var cbValues = checkboxes.getValues();
var newCBValues = new Array(cbRows);
for (var row = 0; row < cbRows; row++) {
newCBValues[row] = new Array(0);
if (namesValues[row] == "" || namesValues[row] == " ") {
newCBValues[row][0] = " ";
}else{
if (cbValues[row][0] === true) {
newCBValues[row][0] = true;
}else{
newCBValues[row][0] = false;
}
}
}
checkboxes.setValues(newCBValues);
}
This part is run on the every minute Time Trigger:
function CopyandPaste() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('AA4').activate();
var currentCell = spreadsheet.getCurrentCell();
spreadsheet.getSelection().getNextDataRange(SpreadsheetApp.Direction.DOWN).activate();
currentCell.activateAsCurrentCell();
spreadsheet.getRange('O4').activate();
currentCell = spreadsheet.getCurrentCell();
spreadsheet.getSelection().getNextDataRange(SpreadsheetApp.Direction.DOWN).activate();
currentCell.activateAsCurrentCell();
spreadsheet.getRange('AA4:AA202').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};
Column AA = TIMEVALUE(Column P)
From the question
I tried to put it in another column and have the values CopyAndPasted Values Only into a column with that run on a time trigger of every minute, but apparently that doesn't count as an Edit or it's not reading the DisplayValue.
You are right, only actions done by a user directly through the Google Sheets user interface will cause the edit trigger to be triggered.
One option is to make that your time-driven trigger besides changing the checkboxes also call the timeValue function but you have to refactor it or to mock the edit event object to pass it as the timeValue parameter.
Reference
https://developers.google.com/apps-script/guides/triggers
As mentioned in the title, I have to stop this script
From turning all the formulas to value and deleting only the duplicate line of column A: A
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var newData = new Array();
if (actualSheetName == "Feuille 1" ) {
if (e.range.getColumn() == 1){
for(i in data){
var row = data[i];
var duplicate = false;
for(j in newData){
if(row[0] == newData[j][0]){
duplicate = true;
}
}
if(!duplicate){
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}}}
It looked to me like you were trying to make this a onEdit() function so here it is:
In order to get this function to work you must edit a cell in column1. (i.e. you must actually change one of the cells in column one)
function onEdit(e) {
var sheet=e.range.getSheet();
//e.source.toast('flag1');
var data=sheet.getDataRange().getValues();
var newData = [];
var d=0;
if (sheet.getName()=="Sheet1") {
//e.source.toast('flag2');
if (e.range.columnStart ==1) {
for(var i=0;i<data.length;i++) {
if(newData.indexOf(data[i][0])==-1) {
newData.push(data[i][0]);
}else{
sheet.deleteRow(i+1-d++);
}
}
}
}
}
Note: you can't test this script in the normal way by running it from the script editor. You must supply with an event object. I normally just debug it by editing the appropriate page to generate the onEdit() trigger.
This won't delete blank rows:
function onEdit(e) {
var sheet=e.range.getSheet();
//e.source.toast('flag1');
var data=sheet.getDataRange().getValues();
var newData = [];
var d=0;
if (sheet.getName()=="Sheet1") {
//e.source.toast('flag2');
if (e.range.columnStart ==1) {
for(var i=0;i<data.length;i++) {
if(data[i][0]=='')continue;
if(newData.indexOf(data[i][0])==-1) {
newData.push(data[i][0]);
}else{
sheet.deleteRow(i+1-d++);
}
}
}
}
}
the working code is here ^_^
the formula of B4 is =max(A:A)+1
if you delete a row or insert a new row it will give here the value of B4 wich is the bigest number of A:A columns + 1 and delete the duplicated empty rows in A:A
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var ss = SpreadsheetApp.getActive()
var actualSheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
if (actualSheetName == "sheet 1" || actualSheetName == "sheet 2") {
if (e.range.getColumn() == 1) {
if (e.value == '' || e.value == null) {
var B1Value = SpreadsheetApp.getActiveSheet().getRange("B4").getValue();
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
var row = r.getRow();
var time = new Date();
SpreadsheetApp.getActiveSheet().getRange('A' + row.toString()).setValue(B1Value);
}}}{
var sheet=e.range.getSheet();
var data=sheet.getDataRange().getValues();
var newData = [];
var d=0;
if (sheet.getName()=="PI-Analy attentes") {
if (e.range.columnStart ==1) {
for(var i=0;i<data.length;i++) {
if(newData.indexOf(data[i][0])==-1) {
newData.push(data[i][0]);
}else{
sheet.deleteRow(i+1-d++);
}}}}}}
I want to input a variable in a cell only if the cell is empty. The if statement, however, does not work. Any advice?
var ss=SpreadsheetApp.getActiveSpreadsheet();
var r=ss.getRange("'odpovědi'!A2:J");
var rws=r.getNumRows();
ax=r.getCell(rws-1, 10).getValue();
if (ax == "") {
ax = "foo";
r.getCell(rws-1, 9).setValue(ax);
}
No need to extact the value to determine if the cell is empty. Google Spreadsheet API already has a method for this: Range - isBlank method
var cell = r.getCell(rws-1, 10);
if (cell.isBlank()) {
cell.setValue("foo");
}
Try:
function myFunction() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var s=ss.getSheetByName('odpovědi')
var lr=s.getLastRow()
var ax=s.getRange(lr, 10).getValue();
if(ax == ""){
ax = "foo";
s.getRange(lr, 10).setValue(ax);
}
}
If you already have cell value then use === or !== operators if you want avoid type conversion (where 0 == "" ).
Code snippet for decreasing not empty cell values
var sheet = ss.getSheets()[0];
var range = sheet.getRange("E2:H5");
var currentValues = range.getValues();
var newValues = [];
for (var row in currentValues) {
var newRow = [];
for (var col in currentValues[row]) {
if (currentValues[row][col] !== "") { // if not empty cell
newRow[col] = currentValues[row][col] - 1;
}
else {
newRow[col] = currentValues[row][col];
}
}
newValues[row] = newRow;
}
range.setValues(newValues);