I created this script to apply to only the worksheet with the name "jan" -- however it runs on all the worksheets no matter how I try. Who can help me check what I am doing wrong?
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("jan");
var r = sheet.getActiveCell();
if( r.getColumn() == 3 ) {
var nextCell = r.offset(0, 1);
if( nextCell.getValue() === '' )
var time = new Date();
time = Utilities.formatDate(time, "GMT", "dd/MM");
nextCell.setValue(time);
};
};
Try:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if (sheet.getName() == "jan") {
// DO SOMETHING TO "jan"
Logger.log("working on sheet jan...");
}
}
To put the above with what you are doing:
function onEdit(e) {
var activeSheet = e.source.getActiveSheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("jan");
var r = sheet.getActiveCell();
if( r.getColumn() == 3 && activeSheet.getName()=="jan") {
var nextCell = r.offset(0, 1);
if( nextCell.getValue() === '' )
var time = new Date();
time = Utilities.formatDate(time, "GMT", "dd/MM");
nextCell.setValue(time);
};
};
Related
I am trying to pull from one sheet to the next sheet.
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();`enter code here`
if(s.getName() == "Main" && r.getColumn() == 2 && r.getValue() == "Chair") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Chair");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
The code above comes from this Github Gist from scottsommer22.
Do not run the function in the script editor. It runs automatically when you hand edit the spreadsheet, and the event object will then be filled in the way the function needs. See simple triggers.
According to an answer from Google Apps onEdit Event - event.source is undefined for, these built-in simple event handlers need the context of the event to be passed in in order to work properly. If you run them from the Script Editor directly, then no event object is passed in, which is why you get the error.
If you want to run and test your code on the script editor and at the same time be able to use the onEdit trigger, you can edit your script to something like this:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var r = SpreadsheetApp.getActiveSpreadsheet().getActiveRange();
if(s.getName() == "Main" && r.getColumn() == 2 && r.getValue() == "Chair") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Chair");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
I found two scripts. Since they both were an onEdit() function they couldn't work side by side, I tried to merge them.
I am using this sheet for a very basic inventory of things I sell / keep track of what I have sold.
I want two things;
First: I would like the cell in column A to change to the current date whenever I do a change on that row.
Second: If I change the value in column B to "Sold" I want it to be moved to a different sheet (as well as getting a new date due the change).
Column B has the following choices:
-Ja (as in stock)
-Bokad (as in booked)
-Såld (as in sold)
The name of the Sheets are:
-Blocket (inventory)
-Sålda (sold)
function onEdit(event) {
// assumes source data in sheet named Blocket
// target sheet of move to named Sålda
// test column with "Såld" is col 2
var s = event.source.getActiveSheet(),
cols = [2],
colStamp = 1,
ind = cols.indexOf(event.range.columnStart)
if (s.getName() == 'Blocket' || ind == -1) return;
event.range.offset(0, parseInt(colStamp - cols[ind]))
.setValue(e.value ? new Date() : null);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Blocket" && r.getColumn() == 2 && r.getValue() == "Såld")
{
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Sålda");
if(targetSheet.getLastRow() == targetSheet.getMaxRows()) {
targetSheet.insertRowsAfter(targetSheet.getLastRow(), 20); //inserts 20 rows
after last used row
}
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
See if this works
function onEdit(e) {
var s, targetSheet;
s = e.source.getActiveSheet();
if (s.getName() !== 'Blocket' || e.range.columnStart == 1) return;
s.getRange(e.range.rowStart, 1)
.setValue(new Date());
if (e.range.columnStart == 2 && e.value == "Såld") {
targetSheet = e.source.getSheetByName("Sålda");
if (targetSheet.getLastRow() == targetSheet.getMaxRows()) {
targetSheet.insertRowsAfter(targetSheet.getLastRow(), 20); //inserts 20 rows
}
s.getRange(e.range.rowStart, 1, 1, s.getLastColumn()).moveTo(targetSheet.getRange(targetSheet.getLastRow() + 1, 1));
}
}
I have a code that helps me copy a row of data based on a condition in a given column. I have a sheet called "Master" which has around 1000 rows of data. I want to move a row of data to a sheet called "Master Responses" if column 1 of "Master" has the word "Positive" or "Negative" in it. I used the or function (||) in the IF STATEMENT to select the condition (that is if "Positive" is entered or "Negative") but the row is only copied when I type "Positive" in the first column. When I type "Negative" in the first column the row is not copied. Also, I wanted to know how the code should be modified if I had to call the "Master Responses" sheet by using ".openByID or .openByURL". I have attached the code, please feel free to edit it. I am new to scripting and have been stuck on this for over a month. Any help would be appreciated. Thanks in advance.
function onEdit()
{
var sheetNamesToWatch = ["Master"];
var columnNumberToWatch = 1;
var valuesToWatch = ["Positive"];
var valuesToWatch1 = ["Negative"];
var targetSheetsToMoveTheRowTo = ["Master Responses"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if(sheetNamesToWatch.indexOf(sheet.getName()) != -1 &&
valuesToWatch.indexOf(range.getValue()) != -1 ||
valuesToWatch1.indexOf(range.getValue()) != -1 && range.getColumn()
==columnNumberToWatch)
{
var targetSheet = ss.getSheetByName(targetSheetsToMoveTheRowTo[valuesToWatch.indexOf(range.getValue())]);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1,
sheet.getLastColumn()).copyTo(targetRange);
}
}
I'm not sure about .openByID or .openByURL, however this should fix the problem with "Negative".
I also added extra parenthesis on the first if statement so that it was clear to me what it was checking on.
function onEdit()
{
var sheetNamesToWatch = ["Master"];
var columnNumberToWatch = 1;
var valuesToWatch = ["Positive"];
var valuesToWatch1 = ["Negative"];
var targetSheetsToMoveTheRowTo = ["Master Responses"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if((sheetNamesToWatch.indexOf(sheet.getName()) != -1) && ((valuesToWatch.indexOf(range.getValue()) != -1) ||
(valuesToWatch1.indexOf(range.getValue()) != -1)) && (range.getColumn() ==columnNumberToWatch))
{
if (valuesToWatch.indexOf(range.getValue()) != -1)
{
var targetSheet = ss.getSheetByName(targetSheetsToMoveTheRowTo[valuesToWatch.indexOf(range.getValue())]);
}
else
{
var targetSheet = ss.getSheetByName(targetSheetsToMoveTheRowTo[valuesToWatch1.indexOf(range.getValue())]);
}
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1,
sheet.getLastColumn()).copyTo(targetRange);
}
}
I have too many columns in the sheet and so many columns to hide as well, but while executing the script it runs half way and stopped saying maximum time reached.
When I again tried to execute it stopped exactly where I stopped previously. So I would like to have some customization that if the column is already hidden can skip that column and work on the others.
Is there any way to do it.
Here is the code I used:
function hideColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('ANALYTIC');
var data = sh.getRange('6:6').getValues();
var numCols = sh.getMaxColumns();
var numRows = sh.getMaxRows();
for(var i = 0; i <= numCols; i++){
if(data[0][i] == ""){
sh.hideColumns(i+1);
} else {
sh.unhideColumn(sh.getRange(1, i+1, numRows, 1));
}
}
}
Please help me.
You can use the documentProperties to store the last column before the end of the execution. To prevent the run from stopping abruptly you stop the run a little prematurely at 5min (execution will terminate at 6min mark) mark and store the column number in the documentProperty. You also display an alert asking you rerun the script.
Then retrieve the column number on the next run and start from there. If the program gets through the complete loop you delete the said properties. So you start from zero if you rerun the script next time.
Below is the code for the same
function hideColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('ANALYTIC');
var data = sh.getRange('6:6').getValues();
var numCols = sh.getMaxColumns();
var numRows = sh.getMaxRows();
var docProp = PropertiesService.getDocumentProperties()
var startCol = Number(docProp.getProperty("startCol")) //if there is no propert called startCol will return Null, Number(Null) = 0
Logger.log(startCol)
var startTime = new Date().getTime()
var ms5min = 5*60*1000 //5min in millseconds
for(var i = startCol; i <= numCols; i++){
if(data[0][i] == ""){
sh.hideColumns(i+1);
} else {
sh.unhideColumn(sh.getRange(1, i+1, numRows, 1));
}
var curTime = new Date().getTime()
var elasped = curTime-startTime
if (elasped >= ms5min){
docProp.setProperty("startCol", i)
SpreadsheetApp.getUi().alert("Please restart Run, exceeded 5min mark")
return
}
}
Logger.log(elasped)
docProp.deleteAllProperties()
}
If your sheet has under 10,000 columns (PropertiesService limit) you can use this script:
function hideColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('ANALYTIC');
var data = sh.getRange('6:6').getValues();
var documentProperties = PropertiesService.getDocumentProperties()
var documentPropertiesVals = documentProperties.getProperties();
var numCols = sh.getMaxColumns();
for(var i = 0; i < numCols; i++){
if (!(cPlusInt(i) in documentPropertiesVals)) {
documentPropertiesVals[cPlusInt(i)] === 'empty';
}
if (documentPropertiesVals[cPlusInt(i)] === 'hidden' && data[0][i] == "") continue;
if (documentPropertiesVals[cPlusInt(i)] === 'unhidden' && data[0][i] != "") continue;
if(data[0][i] == ""){
sh.hideColumns(i+1);
documentProperties.setProperty(cPlusInt(i), 'hidden')
} else {
sh.unhideColumn(sh.getRange(1, i+1, 1, 1));
documentProperties.setProperty(cPlusInt(i), 'unhidden')
}
}
}
function cPlusInt(num) {
return 'c'+num.toString()
}
You at first you may need to run this few times (many write operation to PropertiesService may be sluggish) but later it's "blazingly" fast (0.1 s per new column).
Better answer using #Jack Brown's idea
It is possible to make single save to PropertiesService - you would need to incorporate time limit from #Jack Brown's answer, this way:
function hideColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('ANALYTIC');
var data = sh.getRange('6:6').getValues();
var documentProperties = PropertiesService.getDocumentProperties()
var documentPropertiesVals = documentProperties.getProperties();
var numCols = sh.getMaxColumns();
var startTime = new Date().getTime()
var ms5min = 5*60*1000 //5min in millseconds
for(var i = 0; i < numCols; i++){
if (!(cPlusInt(i) in documentPropertiesVals)) {
documentPropertiesVals[cPlusInt(i)] === 'empty';
}
if (documentPropertiesVals[cPlusInt(i)] === 'hidden' && data[0][i] == "") continue;
if (documentPropertiesVals[cPlusInt(i)] === 'unhidden' && data[0][i] != "") continue;
if(data[0][i] == ""){
sh.hideColumns(i+1);
documentPropertiesVals[cPlusInt(i)] = 'hidden'
} else {
sh.unhideColumn(sh.getRange(1, i+1, 1, 1));
documentPropertiesVals[cPlusInt(i)] = 'unhidden'
}
var curTime = new Date().getTime()
var elapsed = curTime-startTime
if (elapsed >= ms5min){
break;
}
}
documentProperties.setProperties(documentPropertiesVals)
if (elapsed >= ms5min){
SpreadsheetApp.getUi().alert("Please restart Run, exceeded 5min mark")
}
}
cPlusInt function explanation
cPlusInt is necessary because of weird problems with google's PropertiesService. Object gotten from PropertiesService returns undefined at integer keys. To see problem use this code:
function test() {
var obj = {};
for (var i=0; i<10; i++) {
obj[i.toString()] = 'aa' + i.toString();
}
var documentProperties = PropertiesService.getScriptProperties();
documentProperties.deleteAllProperties();
documentProperties.setProperties(obj);
obj = documentProperties.getProperties();
Logger.log(obj)
for (var i in obj) {
Logger.log('%s %s %s', i, obj[i], i === '1');
}
}
I have the following script that runs on the 'onEdit' trigger (that part is working just fine)
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var myRange = SpreadsheetApp.getActiveRange();
if(sheet.getName() == "Plan" && myRange.getColumn() == 2 && myRange.getRow() > 3){
var option = new Array();
option[0]="0";
option[1]="1";
option[2]="2";
var dv = sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).getValidation();
dv.setAllowInvalidData(false);
dv.setHelpText("Some help text here");
dv.setCriteria(SpreadsheetApp.DataValidationCriteria.ITEM_IN_LIST,true,option );
sheet.getRange(myRange.getRow(),myRange.getColumn() + 1) .setValidation(dv);
}
}
That most of the code came from the answer on this question. Problem is that the
dv.setCriteria(SpreadsheetApp.DataValidationCriteria.ITEM_IN_LIST,true,option );
line of code doesn't work, the compiler won't even let me save it. In my looking around as to why, it seems Google has changed how it is handled, and taken their docs about it offline. Can anyone help me get this working?
yep it seems something changed...
try that:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var myRange = SpreadsheetApp.getActiveRange();
if(sheet.getName() == "Plan" && myRange.getColumn() == 2 && myRange.getRow() > 3){
var option = new Array();
option[0]="0";
option[1]="1";
option[2]="2";
// var dv = sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).getValidation();
var dv = sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).getDataValidation();
var dv = SpreadsheetApp.newDataValidation();
// dv.setAllowInvalidData(false);
dv.setAllowInvalid(false);
dv.setHelpText("Some help text here");
dv.requireValueInList(option, true);
// dv.setCriteria(SpreadsheetApp.DataValidationCriteria.ITEM_IN_LIST,true,option );
// sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).setValidation(dv);
sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).setDataValidation(dv.build());
}
}