Passing Dynamic Range:Google Script - javascript

I'm trying to write a custom function that will count and return the number of cells that contain information on a singular column. I'm using a range of A(x):Z(x) and I can't seem to dynamically pass these so I can get a user defined range everytime.
Edit: Current Error I'm receiving right now says: Missing ) after argument list. (line 10, file "Number Of Updates")
So far I have this....
function updateNum(row1,col1,row2,col2)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("report status");
var r = s.getActiveRange(row1+col1:row2+col2); <---Line with error
return (range.length-2)/2
}
any suggestions on how I could make this pass the range?
thanks,
Alexander

change the line for:
var r= s.getRange(row1, col1, row2-row1+1, col2-col1+1);
but that won't solve your problems has the line just behind is a non sense. "range" is not declared. I don't see where you want to go exactly. please write some pseudocode.
If what you want is to count the number of cells that got informations in it, just use the spreadsheet native function
counta()

Its not possible with custom functions because they are deterministic. That is, they will return the same result given the same input.
In your case even if you fix the bugs you are still not passing the actual input just its range limits. Thus if the data inside the range changes you still pass the same input limits thus will return the previous cached result.
There are ways arround that like passing an extra parameter that always changes like 'now()'but that has performance problems as it will recalculate constantly.

Related

Google script - newConditionalFormatRule; whenNumberGreaterThanOrEqualTo not accepting cells?

I'm building a google script but are having trouble with creating the conditional formatting. If I build them in the sheet, there is no issue with setting the range for the conditional format, then set it to "Greater than or equal to" and give it a cell, like =$B$5.
When I build the same thing using the script, it gives me an error that it only accepts numbers and not cells..?
Can anyone help me with this issue? Or is it simply not supported?
// What i want to work, but throws an error, since it doesn't get a number.
formatrules.push(Rule1);
var rule_builder = SpreadsheetApp.newConditionalFormatRule()
.whenNumberGreaterThanOrEqualTo("=$B$9")
.setBackground("#85e085")
.setRanges([currentsheet.getRange("H3:H8")])
.build();
// Something I tried, but it sets it to a static number and not the cell
formatrules.push(Rule1);
var rule_builder = SpreadsheetApp.newConditionalFormatRule()
.whenNumberGreaterThanOrEqualTo(sheet.getRange('B9').getValue())
.setBackground("#85e085")
.setRanges([currentsheet.getRange("H3:H8")])
.build();
Proposed modification
Since you want a dynamic value what about using the .whenFormulaSatisfied(String formula) function?
Here is an example in your application case:
var rule_builder = SpreadsheetApp.newConditionalFormatRule()
.whenFormulaSatisfied("=H3:H8>$B$9")
.setBackground("#85e085")
.setRanges([currentsheet.getRange("H3:H8")])
.build();
Reference
whenFormulaSatisfied(formula)
The parameter in the whenNumberGreaterThanOrEqualTo is of type Number, as specified in the API documentation seen here. You're passing in a string reference to a cell. Instead, you'd have to use SpreadsheetApp.getActiveSheet().getRange("B9").getValue(), as you do in your second attempt. The problem you're running into could be resolved by updating that rule every time the spreadsheet is edited (ie create an onEdit trigger for the function that creates this rule).
The current accepted answer should remain accepted. This is just a complementary post regarding OP's comment:
Seems kind of weird to enter the range again
You can define the range once and then use Template literals to incorporate it into the expression:
var rng = "H3:H8";
var rule_builder = SpreadsheetApp.newConditionalFormatRule()
.whenFormulaSatisfied(`=${rng}>$B$9`)
.setBackground("#85e085")
.setRanges([currentsheet.getRange(rng)])
.build();

Why do I get an Invalid Argument when using the removeLabel function in Google Script

I'd like to remove my user created label called "Add-to-Spendee-2", from a collection of emails. I've pretty much followed Google's removeLabel() Documentation to the dot on this, but I keep getting an "Invalid argument: label" error.
Here's the code:
function removeLabel()
{
var myLabel = GmailApp.getUserLabelByName('test-add-to-spendee-2');
var threads = GmailApp.search("label:test-add-to-spendee-2 AND from:swiggy AND subject:(Your receipt for Swiggy order)");
for (var x in threads)
{
var thread = threads[x]
thread.removeLabel(myLabel)
}
}
Note: If I substitute the removeLabel(myLabel) with any other function like markUnread(), the code works perfectly.
I think your code will work but I think all you need to do is:
var lbl=GmailApp.getUserLabelByName('Q0/Subject/Name');
var threads=GmailApp.search('label:Q0/Subject/Name');//exactly as you created it
lbl.removeFromThreads(threads);
Try using the debugger and make sure that threads is getting an array of GmailThread objects.
This is what the label look like in the Gmail search window:
They changed the slashes to dashes and used lower case and that's not really what the label looks like.
As I said above in my comment:
I just did that recently and I found that the description of the label in the gmail search window did not agree with how I actually created the label. It displayed a label like this q0-subject-name and I had it created as Q0/Subject/Name when I used q0-subject-name I couldn't find the label and when I used Q0/Subject/Name I found it.

Get URL from image via script on Google Sheets - does this code still work?

I am using Google Sheets.
Cell A1:
=image("address.jpg")
This puts the image in a cell. To get the url from Stack Overflow produced this answer.
I created the script, and Google recognised it in autocomplete. The error I am getting is:
TypeError: Cannot call method "match" of null. (line 10).
I ran the regex through a checker, and it does get what I am looking for i.e the address, but the error seems to indicate that it's coming back with nothing.
Does this still work? Has Google changed something?
My work-around is to create two sheets and have §=image in one sheet, while in the second sheet, I remove § and use a standard Google function.
The linked solution is far better, and I'd like to implement that if I could. I cannot post a comment on the original solution's page as I don't have reputation points.
In your situation, "null" is given as an argument. Because the formula cannot be directly retrieved by =getImageUrl(A1). By this, the error of Cannot call method "match" of null. occurs. The formula can be retrieved by getFormula(). This is also mentioned at Eric Koleda's answer. So for example, the script can be modified as follows.
Modified script:
function getImageUrl(range) {
var formula = SpreadsheetApp.getActiveSheet().getRange(range).getFormula(); // Added
var regex = /=image\("(.*)"/i;
var matches = formula.match(regex);
return matches ? matches[1] : null;
}
Note:
If =image("URL") is put in "A1", when you use this like =getImageUrl("A1"). Please enclose A1 by the double quotes. By this, the string of "A1" is given to the function and is used as the range.
Reference:
getFormula()

Matching string

I have done a bare minimum of javascript coding via code academy. I also help build spreadsheets in a family business, and we are working on new spreadsheets for 2017 (late!!) with additional capabilities which make function calls within the sheet very unwieldy. Right now experimenting with very simple custom function intending to work up to a few I need to use. Ran into problems so cut out everything from first script except the problem area.
commission(platform, amount) takes a name and numerical amount respectively. Based on these values I will be setting up commission formulas. Discovered a problem matching the name. After deleting all but the problem area, all I have is:
function commission(platform, amount) {
return platform=="AB";
};
It is run from spreadsheet as:
(called from cell e4) =commission(c4,d4)
The value returned is FALSE.
c4 contains the text AB
d4 (irrelevant right now) contains 1000
The problem arose with if(platform == "AB") {.......
The function was not evaluating the condition as true. When I rewrote it to return the value of platform it did indeed return "AB" in cell e4 from which the function was called.
So the variable clearly does read (and return, when told to) the correct contents of c4, but does not recognize this value in the conditional statement.
I have seen condition statements in javascript use both == and ===. Not sure if there is any difference, tried both. Tried single and double quotation marks.
Posting on the good sheets forum, which requested I cross post.
May be intended/irrelevant but I noticed you have an extra ` in your code.
function commission(platform, amount) {
if(platform == "AB"){
return amount;
}
else
{
return 0; /// insert your own return
}
};
Google spreadsheet screenshot of solution

Parsing a string returned from ckeditor using javascript string methods

I am trying to get a certain area of data out from ckeditor. In order to do that I use the following code
function get_body_html(){
var email = CKEDITOR.instances['message'].getData();
var before_body = header_to + to + to_subject + subject + subject_body;
var s_index = email.indexOf(before_body)+before_body.length;
var e_index = email.indexOf(body_footer);
return email.substring(s_index,e_index);
}
For some reason that works when I do this on page load
CKEDITOR.instances.message.setData(header_to + to + to_subject+
subject + subject_body + body_text + body_footer);
get_body_html();
it works correctly and gives me the same string that is contained in body_text.
But when I do this
body_text = get_body_html();
CKEDITOR.instances.message.setData(header_to + to + to_subject + subject +
subject_body + body_text + body_footer);
in an onclick function it gets the wrong indexs somehow. Sometimes it can't find the string and returns -1 other times it just gets a weird index that doesn't make sense. These index variations only happen when my code is changed to tackle the problem a different way. So if it is the wrong indices like -5 and 2 then those would continue to be the wrong indices until I made a code change.
There are two facts that you should know about editor.setData.
In some cases it is asynchronous (it depends on the type of editor). That's why it also accepts a callback. Therefore any code that is meant to be executed after setData() should be executed in that callback.
It never is asynchronous before editor is ready. In this period (between editor initialization and instanceReady event) it works in a different mode - it just caches the set value and on getData() it returns exactly that value.
So, as I see on page load you call synchronously setData() and getData() - your function works because you get the value you're expecting to get.
But then, when you try to getData() when editor is already ready you get the HTML parsed, fixed, processed and perhaps differently formatted by CKEditor. I guess that your indexOf() checks are not enough to handle this. You have to rethink your function - e.g. regexp can help.
What also can help is removing htmlwriter plugin, which formats HTML in a way which may make it harder for you to work with it. E.g.:
config.removePlugins = 'htmlwriter';
I was able to get it to work. So the htmlwriter was one of the problems because it must add spaces in between by HTML tags. The other issue I found is that it strips some of the semicolons out in some of the style attributes. Overall CKEditor does a lot of formatting of the source which makes it very hard to index correctly but it's pretty much a trial and error thing. I ended up using the search JavaScript method for strings which can take a regular expression but I used it the same way indexOf would be used so I don't really know if that made a difference or not.

Categories