I was trying to create a script for google sheet that counts certain colors and it seems to be working perfectly, but when I tried to make a trigger for it, this is when I start to get problems.
I created the trigger with the OnEdit() event, but everytime I edit the table i get this exception "interval not found". So, if I want it to work correcly, I have to cut and paste the formula on the table (Because the trigger isn't working).
This is my code:
function countColor(countRange) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var range = sheet.getRange(countRange);
var rangeWidth = range.getWidth();
var bg = range.getBackgrounds();
var score = 0;
for (var i = 0; i < rangeWidth; i++)
{
if (bg[0][i] == "#38761d")
{
score += 1;
}
else if (bg[0][i] == "#ffff00")
{
score = score + 0.5;
}
else if (bg[0][i] == "#274e13")
{
score += 1.5;
}
}
return score;
};
1 - So I want to know why the trigger isn't working correcly.
2 - I would like also to know, how to do this--> when I copy and paste the formula in another cell, these correspond to the row in which I have pasted it. (just like normal tables do). For example is the range was a1:b1 in the first cell, when I copy it on the second cell it would be a2:b2
In most cases time based triggers cannot be used with functions that accept parameters. In your case the parameter countrange will probably be populated with the triggers event object which will likely result in some very weird behavior.
Functions that you write to be used in cells are called custom functions in google apps script and you cannot run custom function from a trigger.
Custom Functions
Related
So I'm trying to figure out a way where if the two cells match in numbers, the dropdown list item changes to "stopp".
See the example here: Example
What I want it to do is when the column G has the same number as the column H, it changes the status to "Stopp".
Could someone help?
Unfortunately, this is not possible to do directly in Google Sheets, you would need to incorporate some Apps Script to extend Google Sheets.
With Apps Script, you could simply create a function to check and update the values, or you could do it automatically with triggers. Specifically, the most useful trigger in this situation would be the onEdit() trigger (you can read more about it here), since it would run automatically every time that the document is edited.
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var column1Index = 7; //LETTER G
var column2Index = 8; //LETTER H
var outputColumnIndex = 9; //LETTER I
var numberOfRowsToCheck = 10;
var column1Values = sheet.getRange(1,column1Index,numberOfRowsToCheck,1).getValues();
var column2Values = sheet.getRange(1,column2Index,numberOfRowsToCheck,1).getValues();
for (var i=0;i<column1Values.length;i++){
if(column1Values[i][0] == column2Values[i][0]){
sheet.getRange(i+1, outputColumnIndex).setValue("Stop");
}
}
}
I currently have a script that will remove a negative keywords from a shared negative keyword list when run.
I would like to have this script run when a specific value for example "run" is put in a cell A1 of a an external google sheet.
Below is the current code I have with out the trigger.
function main() {
removeAllNegativeKeywordsFromList();
}
function removeAllNegativeKeywordsFromList() {
var NEGATIVE_KEYWORD_LIST_NAME = 'test';
var negativeKeywordListIterator =
AdsApp.negativeKeywordLists()
.withCondition('Name = "' + NEGATIVE_KEYWORD_LIST_NAME + '"')
.get();
if (negativeKeywordListIterator.totalNumEntities() == 1) {
var negativeKeywordList = negativeKeywordListIterator.next();
var sharedNegativeKeywordIterator =
negativeKeywordList.negativeKeywords().get();
var sharedNegativeKeywords = [];
while (sharedNegativeKeywordIterator.hasNext()) {
sharedNegativeKeywords.push(sharedNegativeKeywordIterator.next());
}
for (var i = 0; i < sharedNegativeKeywords.length; i++) {
sharedNegativeKeywords[i].remove();
}
}
}
I have tried connecting the script to a google sheet and having it run when i put the trigger word in, however it does not seem to work
I did not enter the trigger i used as it think it is completely wrong. the code is without the trigger
Run above script when the word "run" is put in cell A1 of an external google sheet.enter code here
So, if I understood right you are only looking for the trigger for this code. To trigger your code when 'run' is inserted into A1 you would use onEdit(e)
function onEdit(e)
{
// Your testword
var theword = 'run';
// Get the value in cell
var value = e.value;
// Check the range. You could use the spreadsheet->cell->getvalue() but
// this should perform better as calling the SheetApp - API is costly
var isA1 = (e.range.columnStart == 1 && e.range.rowStart == 1);
// if the word and the range both match
if( isA1 && (value == theword))
{
// Run your code
removeAllNegativeKeywordsFromList();
}
}
The trigger itself is tested and working, but as for your code I could not confirm that as I do not know if your 'removeAllNegativeKeywordsFromList' works in the first place. In case you need any help with that please advise some more with this AdsApp, please.
Also please note that any user calling this function via onEdit has to authorise it first. This can be done by running it from script editor or creating a specific authorise-function.
Hope this helps at all.
I manage bookings for my business on Google Spreadsheet. I discovered a wonderful script to update my calendar according to the bookings on the spreadsheet: https://github.com/Davepar/gcalendarsync
So one row = one booking = one event in the calendar.
It works perfectly, but I need a new feature.
As of right now, the script will update one specific calendar, and I would like to update two separate calendars, depending on the value of a specific column.
Example:
Let's say I manage a limo business, and I have two limos, a blue one and a red one.
I put the bookings in a worksheet, specifying for each row if i'll assign the blue or red limo.
I would like to have 2 separate calendars to check the availability of each one separately.
I'm no programmer, but I looked around and apparently this can be done fairly easily, by adding a function:
"if value of column C is "blue", assign this calendar ID, if value of column C ir "red", assign this calendar ID."
I just don't know exactly how to do it.
So, here is the script: https://raw.githubusercontent.com/Davepar/gcalendarsync/master/gcalendarsync.js
According to me, what has to be modified is this:
var calendarId = '<your-calendar-id>#group.calendar.google.com';
// Synchronize from spreadsheet to calendar.
function syncToCalendar() {
// Get calendar and events
var calendar = CalendarApp.getCalendarById(calendarId);
if (!calendar) {
errorAlert('Cannot find calendar. Check instructions for set up.');
I replaced by:
var calendarId1 = 'calendaridofbluelimo#group.calendar.google.com';
var calendarId2 = 'calendaridofredlimo#group.calendar.google.com';
// Synchronize from spreadsheet to calendar.
function syncToCalendar() {
// Get calendar and events
var calendar = CalendarApp.getCalendarById(calendarId1);
if (!calendar) {
errorAlert('Cannot find calendar. Check instructions for set up.');
I haven't modified much at all, I still need to add the function that determines which calendar has to be modified.
I tried to do it according to this response: Create events in multiple Google Calendars from Spreadsheet
But I couldn't figure it out (it is for a different script)
Note: I removed all the "Calendar to Spreadsheet" syncing function - I don't want a modification on the calendar to affect the spreadsheet.
Any help would be very appreciated!
Thanks
You need a conditional statement to check the value of the Spreadsheet cell. Something like the following could work:
var calendarId1 = 'calendaridofbluelimo#group.calendar.google.com';
var calendarId2 = 'calendaridofredlimo#group.calendar.google.com';
function syncToCalendar() {
// Open the Spreadsheet and get the active page.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Then, you need to get the data range to use in the conditional.
// This gives you an array you can loop through and test each row.
// For the sake of illustration, we'll say it's in col B
var data = sheet.getRange("B:B").getValues();
// Test each row in the conditional
for(var i=0; i<data.length; i++) {
if(data[i] == "blue") {
var calendar = CalendarApp.getCalendarById(calendar1);
} else if(data[i] == "red") {
var calendar = CalendarApp.getCalendarById(calendar2);
} else if(!data[i]) {
errorAlert('Cannot find calendar. Check instructions for set up.');
}
// rest of your function...
}
Thanks a lot for your answer. I tested your code, and it doesn't seem to work. The script works, but it will only update the first calendar.
Here is the code I put (the Red/blue variable is in the column R:R)
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sheet.getRange("R:R").getValues();
// Test each row in the conditional
for(var i=0; i<data.length; i++) {
if(data[i] == "Blue") {
var calendar = CalendarApp.getCalendarById(calendarId1);
} else if(data[i] == "Red") {
var calendar = CalendarApp.getCalendarById(calendarId2);
} else if(!data[i]) {
errorAlert('Cannot find calendar. Check instructions for set up.');
}
}
I tested a few things to eliminate potential issues. Like i put B:B (where there is no Rosa/Negro variable) instead of R:R, and the script doesn't work. So that's good.
Also, more interesting, i tried to switch the ids of both calendars. For example, i had
var calendarId1 = 'calendaridofbluelimo#group.calendar.google.com';
var calendarId2 = 'calendaridofredlimo#group.calendar.google.com';
And i put:
var calendarId2 = 'calendaridofbluelimo#group.calendar.google.com';
var calendarId1 = 'calendaridofredlimo#group.calendar.google.com';
What happened is that it added all the events in the Red Limo calendar, and it didn't delete the events off the blue calendar (like it's supposed to do). So I tried many other combinations (after deleting each event in the calendar) and I couldn't find the logic, sometimes it adds all the events to the blue calendar, sometimes all the events to the red.
I have read all answers about this error, but none of them work for me. So maybe someone has another idea.
I'm trying to pass parameter to function getRange but when I'm trying to invoke this function it shows me error
Cannot find method getRange(number,(class),number)
Here is my code:
function conditionalCheck(color,rangeCondition, rangeSum, criteria){
var condition = SpreadsheetApp.getActiveSheet().getRange(2,rangeCondition,15).getValues();
var val = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(2,rangeSum,15).getValues();
var bg = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(2,rangeSum,15).getBackgrounds();
var sum = 0;
for(var i=0;i<val.length;i++){
if(condition[i][0] == criteria && bg[i][0] != color){
sum += val[i][0];
}
}
return sum;
}
And I pass a custom function like:
conditionalCheck("#ffff00",1,3,A3)
This is how the sheet looks like:
I understand that JS trying to guess the type of parameters, that is why it thinks that ex. "rangeCondition" is a class, but I don't know how to give him a Number type.
Funny thing is, that this function works when I open the spreadsheet, but when I'm trying to invoke this function while I'm working it shows me this error. So to update sheet I have to reopen the whole spreadsheet.
I was able to reproduce the error by executing the function directly from the editor.
This behavior makes sense, considering custom function needs to receive a valid parameter. At runtime, your 'rangeSum' parameter is set to 'undefined', which invalidates the getRange() method as it requires a number.
It's actually quite strange that you got your 'for' loop working. In most cases, using the the '+' operator on array values obtained from the sheet will concatenate them into a string, so you'll get '5413' instead of 13 (5 + 4 + 1 + 3)
function calculateSum(column) {
column = column||1; //set the default column value to 1
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(1, column, sheet.getLastRow());
var values = range.getValues();
var sum = 0;
for (var i=0; i < values.length; i++) {
sum += parseInt(values[i]);
}
return sum;
}
Finally, this approach is not very efficient in terms of performance. Once you get the instance of the object, you should use that instance instead of attacking the server with multiple calls like you do in the first 3 lines of your code. For example
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange(1, 1, sheet.getLastRow(), 1);
If you plan on using this custom function in multiple places within the sheet, consider replacing it with the script that processes the entire range - this way you will only perform a single read and write operation to update all values. Otherwise, you may end up filling up your service call quotas very quickly
UPDATE
Instead of creating custom function, create the function that takes the entire range and processes all data in one call. You can test the 'calculateSum()' function above with predefined column number, e.g.
var column = 1 // the column where you get the values from
Upon getting the 'sum' value, write it into the target range
var targetRange = sheet.getRange("B1"); // the cell that you write the sum to
targetRange.setValue(sum);
Finally, you can make that function execute after you open or edit the sheet by appending the following code
function onOpen() {
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Menu')
.addItem('Calculate sum', 'calculateSum')
.addToUi();
calculateSum();
}
function onEdit() {
calculateSum();
}
Calling it from the custom menu would be simple - you just need to create the handler and pass function name as parameter.
I found a solution for a problem with reloading custom function after changing data.
The solution is described here:
Refresh data retrieved by a custom function in google spreadsheet
It showed that we cannot refresh custom function if we don't change inputted parameters because it is cached. So if we change inputted data, a function will reload. We can force a function if we put there timestamp
I have a spreadsheet with a custom function calling a web API like this:
function myFunction(value) {
var value = value
...
}
and I call this function in different cells in B column in this way:
=myFunction(A2)
=myFunction(A3)
=myFunction(A4)
...
so that the values change regarding the content of A column.
Now, I would like to update all these functions with a trigger, which could be every minute, or every hour, or at midnight. I used the built in trigger on Google Apps Script interface, like I did in the past with external scripts, but it doesn't work (I think because the trigger call the function without the "value" variable).
I was thinking to add an external triggered script that update the value of another cell (let's suppose "C1"), and then use the onEdit function to update the custom functions. I searched a lot about onEdit, but I really didn't understand how to make it works in my case.
Should the onEdit function recall myFunction? In what way?
Any help is appreciated, thank you
You can use this function for refreshing formulas in your column:
function updateColumnBFormulas()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('test');
var range = sheet.getRange(1, 2, sheet.getLastRow(), 1);
// get all formulas
var formulas = range.getFormulas();
for (var i = 0; i < formulas.length; i++)
{
// if there's formula in a cell
if (formulas[i][0])
{
// refresh it
sheet.getRange(i+1, 2).setFormula(formulas[i][0]);
}
}
}
Then set up trigger to run it every minute (Edit - Current project's trigger):
Ok, I solved with an external script that updates a cell, and then a dummy argument in my custon function that refers to that cell (as suggested by #RobinGertenbach)
This is the external triggered script:
function update() {
var number = Math.floor(new Date().getTime()/1000);
ss.getSheetByName("Data").getRange("A1").setValue(number);
}
and my custom function now looks like:
function myFunction(value, now) {
var value = value
var now = now
...
}
and then it is called in column B in this way:
=myFunction(A2, $A$1)
=myFunction(A3, $A$1)
=myFunction(A4, $A$1)
...
The solution with a function for refreshing formulas posted above was not doing the job, I don't know why. Formulas were refreshing but the values didn't get updated.
Thank you very much for your help!