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)});
}
Related
I'm looking to edit this script so that before the rows are deleted, they are appended to the tab "Done". I tried creating a target sheet, but can't seem to get it working:
function remove(){
var SS = SpreadsheetApp.getActive();
var SHEET = SS.getSheetByName("Todo");
var TARGETSHEET = SS.getSheetByName("Done");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = "Remove";
var COL_TO_SEARCH = 0;
var rangeVals = RANGE.getValues();
for(var i = rangeVals.length-1; i >= 0; i--){
if(rangeVals[i][COL_TO_SEARCH] === DELETE_VAL){
// TARGETSHEET.appendRow(i+1);
// TARGETSHEET.moveRows(rangeVals);
SHEET.deleteRow(i+1);
};
};
};
I essentially am trying to get it to operate like the script below, but for ANY value that has the word "Remove" in a specific column; not one by one. I want to run it from a button:
function onEdit(e){
var sourceSheet = e.range.getSheet();
if(sourceSheet.getSheetName() === 'Todo'){
var row = e.range.getRow();
var rowRange = sourceSheet.getRange(row, 1, 1, sourceSheet.getLastColumn());
var rowValues = rowRange.getValues()[0];
if(rowValues[0] === "Remove"){
var targetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Done");
targetSheet.appendRow(rowValues);
sourceSheet.deleteRow(row);
}
}
}
Any thoughts are greatly appreciated
I believe your goal is as follows.
You want to check column "A" of "Todo" sheet, and when the value of column "A" is "Remove", you want to move the row to the destination sheet "Done".
You want to run the script by a button on the Spreadsheet.
In this case, how about the following sample script?
Sample script:
function myFunction() {
const srcSheetName = "Todo";
const dstSheetName = "Done";
const ss = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = ss.getSheetByName(srcSheetName);
const dstSheet = ss.getSheetByName(dstSheetName);
const range = srcSheet.getDataRange();
let srcValues = range.getValues();
const dstValues = srcValues.filter(([a]) => a == "Remove");
srcValues = srcValues.filter(([a]) => a != "Remove");
dstSheet.getRange(dstSheet.getLastRow() + 1, 1, dstValues.length, dstValues[0].length).setValues(dstValues);
range.clearContent().offset(0, 0, srcValues.length, srcValues[0].length).setValues(srcValues);
}
When this script is run, the above goal is obtained. In this sample, the sheet of "Todo" is updated by new values filtered by "Remove".
When you want to run this script by a button, please assign myFunction to the button.
Reference:
filter()
I'm attempting to write a few functions that
copy google form submission to from "form submission" sheet to "All Leads" sheet
move whole row from "All Leads" sheet to "Open Leads" sheet based on a cell value = "open"
move whole row data either back to "All Leads" or "closed","lost" sheets based on cell value ="closed/lost/blank"
var sheetNameToWatch = "Form Responses";
var columnNumberToWatch = 3;
var sheetNameToMoveTheRowTo = "All Leads";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && isBlank(range) == FALSE) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
//sheet.deleteRow(range.getRow());
}
}
But I'm not getting this to trigger onEdit or onFormSubmission. Any help is appreciated, and as you can tell i'm new to scripting.
Here is the shared google spreadsheet
https://docs.google.com/spreadsheets/d/13090GHrXY17lRzA9ppQHZZGyT9yUNk6hMMXDQIKmddI/edit?usp=sharing
Since you already have entries stored in your Spreadsheet, you should just run this snippet once to copy the already stored values in their place. This works by gathering all the data wanted from the Form Responses sheet by using the getRange(row, col, numrows, numcols) method and then pasting the values by using the setValues() method.
function copyStuff() {
var spreadsheet = SpreadsheetApp.openById("ID_OF_YOUR_SPREADSHEET");
var allLeads = spreadsheet.getSheetByName("All Leads");
var formSub = spreadsheet.getSheetByName("Form Responses");
var valsFromForm = formSub.getRange(3, 1, 53, 13).getValues();
allLeads.getRange(2, 1, 53, 13).setValues(valsFromForm);
}
Afterwards, you should replace the above snippet with this one:
function onFormSubmit() {
var spreadsheet = SpreadsheetApp.openById("ID_OF_YOUR_SPREADSHEET");
var allLeads = spreadsheet.getSheetByName("All Leads");
var formSub = spreadsheet.getSheetByName("Form Responses");
var openSheet = spreadsheet.getSheetByName("Open Leads");
var closedSheet = spreadsheet.getSheetByName("Closed");
var lostSheet = spreadsheet.getSheetByName("Lost");
var lastVals = formSub.getRange(formSub.getLastRow(), 1, 1, 13).getValues();
allLeads.getRange(allLeads.getLastRow(), 1, 1, 13).setValues(lastVals);
var cellValue = spreadsheet.getSheetByName("THE_NAME_OF_YOUR_SHEET_WHERE_CELL_VALUE_IS").getValue();
if (cellValue == "OPEN")
openSheet.getRange(openSheet.getLastRow(), 1, 1, 13).setValues(lastVals);
else if (cellValue == "CLOSED")
closedSheet.getRange(closedSheet.getLastRow(), 1, 1, 13).setValues(lastVals);
else if (cellValue == "LOST")
lostSheet.getRange(lostSheet.getLastRow(), 1, 1, 13).setValues(lastVals);
var lastVals = formSub.getRange(formSub.getLastRow(), 1, 1, 13).getValues();
allLeads.getRange(allLeads.getLastRow(), 1, 1, 13).setValues(lastVals);
}
The above snippet works by getting the last row from the Spreadsheet and then pasting it in the right place based on the cellValue. To get the last row of the sheet, the getLastRow() method has been used.
Since you want this to run on every form submission, you should use an onFormSubmit() installable trigger, and configure it like this:
Note: You will have to have the script linked to the form.
Reference
Sheet Class Apps Script - getRange();
Sheet Class Apps Script - getLastRow();
Installable Triggers Apps Script.
My issue is, I have data being moved from one Sheet to another via script when marked "Complete". In the "Completed" sheet is where I want to sort the data. I already have an Autosort script that works only when debugging, not even on edit (tried editing everywhere), Let alone when data is moved to the sheet.
I want to be able to Auto sort whenever data is moved to the new sheet (I don't think its an onEdit function?)
I am not a programmer and I'm fairly new to Google Apps Script. I just dabble into code once in a while because I find it interesting, so I don't even know where to start to get the results I'm looking for.
This is the Auto Sort,
function AutoSortOnEdit() {
var sheetNames = ["Complete"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
sheetNames.forEach(function(name) {
var sheet = ss.getSheetByName(name);
var range = sheet.getRange(4, 1, sheet.getLastRow() - 1,
sheet.getLastColumn());
range.sort({column: 2, ascending: true});
});
}
EDIT: I realized I was using a script for multiple sheets. I changed it for one sheet, same issues though.
function AutoSortOnEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Completed Returns");
var range = sheet.getRange(4, 1, sheet.getLastRow() - 1,
sheet.getLastColumn());
range.sort({column: 2, ascending: true});
}
Any help would be greatly appreciated!
I managed to get it working by throwing the 2 scripts together under 1 function like so. I could not figure out how to get the event function to run while calling multiple functions, so I just combined them. Above the 2 "}" brackets is the move Script and below them is the Auto sort.
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
var r = e.range;
var actionCol = 24;
var nameCol = 24;
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
var colNumber = s.getLastColumn();
if (e.value == "TRUE" && colIndex == actionCol) {
var targetSheet = ss.getSheetByName("Completed Returns");
if (ss.getSheetByName("Completed Returns")) {
var targetSheet = ss.getSheetByName("Completed Returns");
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
s.deleteRow(rowIndex);
}
}
var sheet = ss.getSheetByName("Completed Returns");
var range = sheet.getRange(4, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
range.sort({column: 2, ascending: true});
}
Thanks Everyone for the response!
You can add your function to one another
function AutoSortOnEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Completed Returns');
var range = sheet.getRange(
4,
1,
sheet.getLastRow() - 1,
sheet.getLastColumn()
);
range.sort({ column: 2, ascending: true });
}
function copyData() {}
function userActionRun() {
copyData();
AutoSortOnEdit();
}
At now you can bind it ti EDIT event
function onEdit(){
userActionRun();
}
You can use the Sort function to sort a data-set.
If you have a function that moves data form one sheet to another when the row is marked as complete, then you can add a line at the end of that to sort it.
You could also create a FilterView that sorts the whole sheet based on your parameters. Unlike Filters, FilterViews are saved between sessions.
I would like to retrieve the data from many sheets into one single sheet.
I have 13 columns titles in my sheets, so I only take the data from the second row of all sheets.
For example, I have 3 sheets whose name are "FR", "UK", "DE", and "Master".
My columns are Country, Name, Month Usage, Model, Machine.
from Row 2, I have plenty of data for "FR","UK","DE".
"Master" has only the columns names.
What I want to merge all the data in a sheet called "Master".
So I took a code from Youtube "Combine one sheet into one" and the guy who has done the video made the code to retrieve data for 3 columns.
It actually does retrieve data from my 3 columns.
function combineData() {
var masterSheet = "Master";
var ss =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(masterSheet);
var lc = ss.getLastColumn();
var lr = ss.getLastRow();
// ss.getRange(2,1,lr-1,lc).clearContent();
var labels = ss.getRange(1, 1, 1, lc).getValues()[0];
labels.forEach(function(label, i) {
var colValues = getCombinedColumnValues(label, masterSheet);
ss.getRange(2, i + 1, colValues.length, 1).setValues(colValues);
})
function getCombinedColumnValues(label, masterSheetName) {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var colValues = [];
for ([i, sheet] in sheets) {
var sheetName = sheet.getSheetName();
if (sheetName !== masterSheetName && sheetName !== "UID") {
var tempValues = getColumnValues(label, sheetName);
colValues = colValues.concat(tempValues);
}
}
return colValues;
}
function getColumnValues(label, sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
var colIndex = getColumnIndex(label, sheetName);
var numRows = ss.getLastRow() - 1;
var colValues = ss.getRange(2, colIndex, numRows, 1).getValues(); // for name, index =2 but replacing by colIndex says "startong column too small)
return colValues;
}
function getColumnIndex(label, sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
var lc = ss.getLastColumn();
var lookupRangeValues = ss.getRange(1, 1, 1, lc).getValues()[0];
var index = lookupRangeValues.indexOf(label) + 1;
return index;
}
};
I thought the code was dynamic to the number of columns present in my Master sheet, but it isn't. My error while compiling is "The starting column of the range is too small"
Does anyone has an idea to fix the bug?
Thanks.
Get Data from all Sheets
function getDataFromAllSheets() {
var excl=['Master'];//Sheets to exclude
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Master');//data destination
sh.getRange(2,1,sh.getLastRow(),sh.getLastColumn()).clearContent();//clears old data but leaves headers
var shts=ss.getSheets();
for(var i=0;i<shts.length;i++) {
if(excl.indexOf(shts[i].getName())>-1) {//does not collected data from excluded sheets
var vA=shts[i].getDataRange().getValues();//get sht[i] data
for(var j=1;j<vA.length;j++) {//skips first line
sh.appendRow(vA[j]);//appends all rows after first line
}
}
}
}
I need a script to automatically add a blank line at the beginning whenever I finish filling the field in column 8 of a line?
Note: It is for this new line preserve the formula of the previous line.
This is the script that I am using.
It works by writing any part of the line (any column)
but I wanted him to be activated only when i write something in column 8.
function onEdit(e) {
if (e) {
var ss = e.source.getActiveSheet();
var r = e.source.getActiveRange();
// If you want to be specific
// do not work in first row
// do not work in other sheets except "Outubro"
if (r.getRow() != 1 && ss.getName() == "Outubro") {
// E.g. status column is
status = ss.getRange(r.getRow(), 8).getValue();
// Status
if (status == 'yes', 'null') {
var planilha = SpreadsheetApp.getActiveSpreadsheet();
var folha = planilha.getActiveSheet();
if (folha.getName() === "Outubro")
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
sheet.insertRowBefore(4);
var rangeToCopy = sheet.getRange(3, 1, 1, sheet.getMaxColumns());
rangeToCopy.copyTo(sheet.getRange(4, 1));
}
}
}
}
Thank you for the help from the community.
The code is now working.
I'll leave the code here for anyone who need.
Once again thank you all for the help.
function onEdit(e) {
if (e) {
var ss, activeRange, activeColumn;
var planilha = SpreadsheetApp.getActiveSpreadsheet();
var folha = planilha.getActiveSheet();
if (folha.getName() === "Outubro")
ss = SpreadsheetApp.getActiveSpreadsheet();
activeRange = ss.getActiveRange();
activeColumn = activeRange.getColumn();
//Logger.log('activeColumn: ' + activeColumn); //VIEW LOGS
if (activeColumn !== 8) {return;};//Quit if not column 8 {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
sheet.insertRowBefore(4);
var rangeToCopy = sheet.getRange(3, 1, 1, sheet.getMaxColumns());
rangeToCopy.copyTo(sheet.getRange(4, 1));
}
}