This function works fine. When the current sheet is not a Google form response sheet. I am using (Everyminute) Trigger
Image of: Sand data (mainData) sheet to (shareData1) sheet
I am looking for a, When the user submits the Google form whose status is ( Paid ), the data should go on the second sheet which is (shareData1)
The problem here is that this function will not work anymore when I am using the Google Forms response sheet. And it shows an error.
Error Image
in the error image for demotion, I am run this function manually, the same error show in Executions AppScript panel.
function doneCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("mainData");
var values = sheet.getRange(1, 3, sheet.getLastRow(), 1).getValues();
var moveRows = values.reduce(function(ar, e, i) {
if (e[0] == "Paid" ) ar.push(i + 1)
return ar;
}, []);
var targetSheet = ss.getSheetByName("shareData1");
moveRows.forEach(function(e) {
sheet.getRange(e, 1, 1, sheet.getLastColumn()).moveTo(targetSheet.getRange(targetSheet.getLastRow() + 1, 1));
});
moveRows.reverse().forEach(function(e) {sheet.deleteRow(e)});
}
function doneCopy() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getSheetByName("mainData");
const tsh = ss.getSheetByName("shareData1");
const vs = sh.getRange(1, 3, sh.getLastRow(), 1).getValues().flat();
const n = sh.getLastColumn();
let d = 0;
vs.forEach((e, i) => {
if (e == 'Paid') {
sh.getRange(i + 1, 1, 1, n).copyTo(tsh.getRange(tsh.getLastRow() + 1, 1));
sh.deleteRow(i + 1 - d++);
}
});
}
I'm not sure what your additional needs are but I'll take my best guess.
function doneCopy() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getSheetByName("mainData");
const tsh = ss.getSheetByName("shareData1");
const vs = sh.getRange(1, 3, sh.getLastRow(), 1).getValues().flat();
const n = sh.getLastColumn();
const a = ['Paid','Process'];
let d = 0;
vs.forEach((e, i) => {
if (~a.indexOf(e)) {
sh.getRange(i + 1, 1, 1, n).copyTo(tsh.getRange(tsh.getLastRow() + 1, 1));
sh.deleteRow(i + 1 - d++);
}
});
}
Related
I'm trying to add a script to my sheet that would help to keep in cleaner by moving all completed rows from 'Main' sheet/tab to 'Completed' if the row is in the 'Complete' status. Filtering unfortunately isn't enough.
I was hoping it's something I can figure out on my own but have been running into errors when running the script I modified. Not sure if it's the right one. Could anyone point me towards a correct script?
Any guidance would be much appreciated.
Here is the example sheet:
https://docs.google.com/spreadsheets/d/1dGm-XddcndmvwcP-K61OViLpNTcMmKpI2rEQOYpVuJQ/edit?usp=sharing
Here is the script I found and tried to modify to my own sheet but still got errors when renamed sheets and edited ranges:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('doneCopy', 'doneCopy')
.addToUi();
}
function doneCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Current");
var values = sheet.getRange(1, 8, sheet.getLastRow(), 1).getValues();
var moveRows = values.reduce(function(ar, e, i) {
if (e[0] == "DONE") ar.push(i + 1);
return ar;
}, []);
var targetSheet = ss.getSheetByName("OLD");
moveRows.forEach(function(e) {
sheet.getRange(e, 1, 1, sheet.getLastColumn()).moveTo(targetSheet.getRange(targetSheet.getLastRow() + 1, 1));
});
moveRows.reverse().forEach(function(e) {sheet.deleteRow(e)});
}
There are three syntax errors in your code:
the name of the source sheet
var source = ss.getSheetByName("Main")
the name of the target sheet
var target = ss.getSheetByName("Completed")
the value to match
e[0] == "Complete"
function doneCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Main");
var values = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
var moveRows = values.reduce(function(ar, e, i) {
if (e[0] == "Complete") ar.push(i + 1);
return ar;
}, []);
var targetSheet = ss.getSheetByName("Completed");
moveRows.forEach(function(e) {
sheet.getRange(e, 1, 1, sheet.getLastColumn()).moveTo(targetSheet.getRange(targetSheet.getLastRow() + 1, 1));
});
moveRows.reverse().forEach(function(e) {sheet.deleteRow(e)});
}
I have a sheet with 6 columns that is being updated with a webhook using the doPost function below that works just fine.
I have filtered only the rows where column 5 = 'true' (index [4]), but I would like to move all columns that match this condition of true in column 5 into another sheet and then clear the first sheet leaving only the header rows in the first sheet.
I'm nearly there, but I would appreciate it if anyone has any suggestions to achieve this final step. Thanks for reading...
function doPost(e) {
var jsonString = e.postData.getDataAsString();
var event = JSON.parse(jsonString)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Import");
var timeStamp = new Date();
var time = Utilities.formatDate(timeStamp, "GMT+1", "dd/MM/yyyy, h:mm a");
var nextRow = sheet.getLastRow()+1;
//Insert the data into the sheet
sheet.getRange(nextRow, 1).setValue(time);
sheet.getRange(nextRow, 3).setValue(jsonString);
sheet.getRange(nextRow, 4).setValue(event.data.amount);
sheet.getRange(nextRow, 5).setValue(event.data.metadata.is_supplementary);
sheet.getRange(nextRow, 6).setValue(event.data.reference);
}
function getData() {
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var filteredRows = rows.filter(function(row){
var is_supplementary = row[4];
if (is_supplementary == true){
return row;
}
})
Logger.log(filteredRows);
}
Try this:
function doPost(e) {
const jsonString = e.postData.getDataAsString();
const event = JSON.parse(jsonString)
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getSheetByName("Import");
const ts = new Date();
const time = Utilities.formatDate(ts, "GMT+1", "dd/MM/yyyy, h:mm a");
const nextRow = sh.getLastRow() + 1;
sh.getRange(nextRow, 1).setValue(time);
sh.getRange(nextRow, 3, 1, 4).setValues([[jsonString, event.data.amount, event.data.is_supplementary, event.data.reference]]);//doing last 3 all at once
}
function getData() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();//getting active sheet
const vs = sh.getRange(2,1,sh.getLastRow() - 1,sh.getLastColumn()).getValues().filter(r => r[4]);//test truthiness
const osh = ss.getSheetByName("output");
osh.getRange(osh.getLastRow() + 1, 1, vs.length,vs[0].length).setValues(vs);
sh.getRange(2,1,sh.getLastRow() - 1, sh.getLastColumn()).clearContent();
}
I would like a custom script that can move a random value from one column to another
Example:
Before
After
Can this somehow achieved?
Try
function myFunction() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName(`MY_SHEET_NAME`)
const colAValues = sheet.getRange(`A2:A`)
.getDisplayValues()
.filter(String)
const colBValues = sheet.getRange(`B2:B`)
.getDisplayValues()
.filter(String)
const randomIndex = Math.floor(Math.random() * colAValues.length)
const randomValue = colAValues.splice(colAValues.indexOf(randomIndex), 1)
colBValues.push(randomValue)
sheet.getRange(`A:B`).clearContent()
sheet.getRange(2, 1, colAValues.length, 1).setValues(colAValues)
sheet.getRange(2, 2, colBValues.length, 1).setValues(colBValues)
}
Random Move
function randomMove() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
let col1 = sh.getRange(2, 1, sh.getLastRow() - 1).getValues().flat().filter(e => e);
let col2 = sh.getRange(2, 2, sh.getLastRow() - 1).getValues().flat().filter(e => e);
let idx = Math.floor(Math.random() * col1.length);
let v = col1[idx];
if (col1[idx]) {
col2.push(col1[idx]);
col1.splice(idx, 1);
}
if (col1.length || col2.length) {
sh.getRange(2, 1, sh.getLastRow() - 1, 2).clearContent();
}
if (col1.length) {
sh.getRange(2, 1, col1.length, 1).setValues(col1.sort((a, b) => a - b).map(e => [e]));
}
if (col2.length) {
sh.getRange(2, 2, col2.length, 1).setValues(col2.sort((a, b) => a - b).map(e => [e]));
}
}
Demo:
I have the below working script but would like to have it working in multiple tabs, instead of having to create several triggers and overload the sheet.
This is the script:
function clearSomeCellsReading () {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Reading');
const sr = 1;
const vs = sh.getRange(sr,21,sh.getLastRow() - sr + 1).getValues().flat();
vs.forEach((e,i) => {
if(e > 29) sh.getRange(i + sr,16,1,3).clearContent();
})
}
Apart from "('Reading')", I have other 20 locations that I would like to incorporate, ie. Bristol, Watford...
All the other tabs are exactly the same to this one, all copies of each other with just different data.
I tried duplicating the script and just changing the tab name but I keep getting errors...
Any help would be greatly appreciated.
Thank you!
I think this might be what you're looking for. If you have some distinct text to identify the Sheets you want to run the procedure on, that would make it dynamic. Otherwise you can specify the exact names of the sheets you want to run it on as shown below.
function allSheetsMacro(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const theSheetsToInclude = ["Reading","Bristol","Watford"];
const allSheets = ss.getSheets();
for(var i=0;i<allSheets.length;i++){
var aSheet = allSheets[i];
if(theSheetsToInclude.includes(aSheet.getName())){
//or whatever rule to find your sheets.
clearSomeCellsReading_(aSheet);
}
}
}
function clearSomeCellsReading_(sh) {
//original function but being called each time from first function.
const sr = 1;
const vs = sh.getRange(sr,21,sh.getLastRow() - sr + 1).getValues().flat();
vs.forEach((e,i) => {
if(e > 29) sh.getRange(i + sr,16,1,3).clearContent();
})
}
function clearSomeCellsReading () {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const sr = 1;
const vs = sh.getRange(sr,21,sh.getLastRow() - sr + 1).getValues().flat();
vs.forEach((e,i) => {
if(e > 29) sh.getRange(i + sr,16,1,3).clearContent();
})
}
or maybe this:
function clearSomeCellsReading() {
const shts = ['Reading', 'others'];
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
if (~shts.indexOf(sh.getName())) {
const sr = 1;
const vs = sh.getRange(sr, 21, sh.getLastRow() - sr + 1).getValues().flat();
vs.forEach((e, i) => {
if (e > 29) sh.getRange(i + sr, 16, 1, 3).clearContent();
})
}
}
I have this onEdit function that goes over the sheet, looks at the cell value under NAME column, finds its position in another cell under LIST column and outputs this position in the POSITION column.
I am trying to find a way to limit this in a specific range, more specifically to exclude the 1st row (row 1) from this indexing, since if i add a row above the LIST, NAME and POSITION the function fails with TypeError: Cannot read property 'toString' of undefined.
Heres my function -
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('sheet1');
const [hA, ...vs] = sh.getDataRange().getValues();
function onEdit() {
var r = ss.getActiveCell();
if( r.getColumn() > 7 ) {
let idx = {};
hA.forEach((h, i) => { idx[h] = i; });
let vO1 = vs.map((r, i) => {
var tes = [r[idx['LIST']].toString().split(',').indexOf( r[idx['NAME']] ) +1]
return (tes == 0) ? [''] : tes;
});
sh.getRange(2, idx['POSITION'] + 1, vO1.length, vO1[0].length).setValues(vO1);
}
}
Only 1 row before labels:
const [header, hA, ...vs] = sh.getDataRange().getValues();
Alternative:
const values = sh.getDataRange().getValues();
values.shift();
const [hA, ...vs] = values;
Mutiple rows (specify labelRow):
const labelRow = 2;
const values = sh.getDataRange().getValues();
const [hA, ...vs] = values.slice(labelRow - 1);
Alternative:
const labelRow = 2;
const rows = sh.getLastRow() - labelRow + 1;
const [hA, ...vs] = sh.getRange(label, 1, rows, sh.getLastColumn()).getValues();
There are bugs on your code.
return (tes == 0) ? [''] : tes; should be:
return (tes == [0]) ? [''] : tes;
sh.getRange(2, idx['POSITION'] + 1, vO1.length, vO1[0].length).setValues(vO1); should be (make sure to define labelRow):
sh.getRange(labelRow + 1, idx['POSITION'] + 1, vO1.length, vO1[0].length).setValues(vO1);