I'm a VBA newbie, but have successfully created a handful of useful Excel Functions. The one I'm working on right now, which seems like it should be simple, is eluding me. I think I'm misunderstanding the syntax, and need some guidance.
Consider the following screen capture; I am attempting to create the function in Column E, which is simply the VALUE from D$n.
So far, this is as far as I've gotten:
Function PASTVALUE(q As String)
q.PasteSpecial Paste:=xlPasteValues
End Function
which, if I understand properly, is reading the input value (in my case, the contents of cell D$n) as a String, then pasting it using PasteValues.
Do I need to somehow copy it before I paste it? I thought that the q As String parameter was what brought it into the function.
But then if I'm not copying, is it trying to paste from an empty clipboard...in which case I have no idea what I should be using to accomplish this.
Help!
You can just ''transfer'' the value(displayed) over like this
Function PASTEVALUE(rng As Range)
PASTEVALUE = rng.Text
End Function
or use the Evaluate() function to evaluate the formula in that range
Function PASTEVALUE(rng As Range)
PASTEVALUE = [rng]
End Function
There are some features of Excel's object model that you cannot access during a calculation; i.e. during the evaluation of a function. Broadly speaking they are the ones that manipulate the value in cells in some way. If the converse were true, then the calculation process in Excel would break.
Pasting clipboard data into the worksheet falls therefore into the forbidden category.
One solution would be to put your code in a macro; accessible by a button on the worksheet. That is outside the calculation cycle and therefore permissible.
Related
I'm writing a custom function that needs to do the equivalent of
=QUERY(IMPORTXML(url, xpath), query)
I found https://developers.google.com/chart/interactive/docs/querylanguage where section "Setting the Query from JavaScript" nicely explains to do this with:
var query = new google.visualization.Query(DATA_SOURCE_URL);
query.setQuery('select dept, sum(salary) group by dept');
query.send(handleQueryResponse);
But, I have a problem:
As shown there, query.send() passes the results asynchronously. But, I need to return them from my custom function. I want to show the results in the cell.
Short of writing some awful kludge with shared variables and timers waiting for results, I don't see how this can work. What am I missing?
To summarize: I want to write a custom function that returns the result of a query to its cell in Google Sheets.
UPDATE ADDED LATER:
Several commenters did not understand my question above, so I'm adding some more details here [#tanaike, #RemcoE33 - I hope this helps]:
The following line is valid in a Google Sheets cell.
=QUERY(IMPORTXML("https://www.wikidata.org/wiki/"&$A5, "//*"), "select Col2 where Col1 = 'name in native language' and Col2 is not null")
It works. But, I need to do embed this inside a more complex calculation, so I want to move it into a custom function.
I don't see how to do this cleanly because:
query.send completes asynchronously
Custom functions return the value to put in the cell
Custom functions do not have permission to write into other cells
Therefore, I don't see any clean way of doing this other than what I called above "writing some awful kludges with shared variables and timers waiting for results". The answer in the comment by #doubleunary is an example of this kind of solution. I will do this if I have to, but I'm really hoping for a cleaner, non-polling solution, especially because I may need to run this in many cells in parallel.
I need to do embed this inside a more complex calculation, so I want to move it into a custom function
query() and importxml() are deterministic, so there is nothing preventing you from just wrapping them in your custom function, like this:
=MyCustomFunction( query( importxml("https://www.wikidata.org/wiki/" & $A5, "//*"), "select Col2 where Col1 = 'name in native language' and Col2 is not null", 0 ) )
Your custom function will receive a 2D array of values as its sole argument. You can test the above formula with a simple custom function like this:
function MyCustomFunction(array2D) {
return JSON.stringify(array2D);
}
Nevertheless, chances are that the complex calculation you refer to may be easiest to implement using a plain vanilla spreadsheet formula. They are surprisingly expressive.
I am attempting to create a manual archive function in a google sheet (based on form responses). It's a bit of a Frankenstein effort at this point as I've gathered bits and pieces to put it together. I am so close to completion, but I've hit a wall when I try to add formulas back into the sheet after clearing it to the archive.
I'm sure it's no surprise that am new to this, and I feel like I am missing something simple here. The formulas below are copied directly from the active spreadsheet where they are working fine, but for some reason, I can't get the script to parse in order to put them back after clearing the sheet. I would appreciate any assistance anyone is willing to offer.
I get the error:
Missing ) after argument list.
on the two lines of "cell.setFormula" code that won't "code block" below:
function addFormulas(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sourcesheet = sheet.getSheetByName("Form Totals");
//Add formula back into Column A
var cell = sourcesheet.getRange("A2:A1000");
cell.setFormula("=D2");
//Add formula back into Column U
var cell = sourcesheet.getRange("U2:U1000");
cell.setFormula("=IF(ISNUMBER(FIND("14.29",P2)),14.29,IF(ISNUMBER(FIND("5.24",P2)),5.24,""))");
//Add formula back into Column V
var cell = sourcesheet.getRange("V2:V1000");
cell.setFormula("=IF(ISNUMBER(FIND("14.29",U2)),U2*Q2,IF(ISNUMBER(FIND("5.24",U2)),U2*Q2,""))");
}
What's going on here? Are my formulas "wrong" even though they work in the spreadsheet?
In JavaScript, double quotes are used to denote string type. If you place anything inside " ", it tells the JS code parser to treat anything between these double quotes as a string.
String is also the only valid argument type for setFormula() method of the Range class, so anything that goes inside the brackets should be of this type.
Take a look at this part in your formula
cell.setFormula("=IF(ISNUMBER(FIND("14.29",
The syntax parser would recognize the part between the first pair of double quotes as a string, but 14.29 will be treated a a number as that's where the string ends. The parser will immediately stop and throw an error.
The solution is to use single quotes for strings inside your formula, e.g.
range.setFormula("=IF(ISNUMBER(FIND('14.29',P2)),14.29,IF(ISNUMBER(FIND('5.24',P2)),5.24,''))");
You must be carefull with the use of the "". Like you write it, the console get it like
cell.setFormula("=IF(ISNUMBER(FIND("
and he don't find the missing ).
You should write it like
cell.setFormula("=IF(ISNUMBER(FIND(\"14.29\",U2)),U2*Q2,IF(ISNUMBER(FIND(\"5.24\",U2)),U2*Q2,\"\"))");
I have a small query regarding automatic formula value calculation in excel.
In my project I will be having 200 questions and corresponding 200 answers( numerical values of 10,20 and 30). Those questions and answers are obtained from webpages and all the questions and answers are stored in my sql database. I will collect the answers that are posted in mysql database to excel with the help of mysql add-in.
My question is I have some formulas
given in my excel sheet ex:mean(C204), STDEV(C205), final risk( my own formula F209)
I want the formulas to automatically calculate the formula values whenever I import the
data from mysql. Is it possible in excel if not is there any alternative? Please help!
This is kind of a stab in the dark since I'm not at all familiar with the add in or how it operates. It seems odd that it would import data and not allow a application.calculate event to take place after import.
Perhaps... you can run the application.calculate method on worksheet change. In your VBE, double click the worksheet upon which the mysql data is dropped. Then add this code to that worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.Calculate
End Sub
There's fairly good chance that the add in also snuffs events by setting application.enableEvents = false which means this won't work, but... it's worth a shot.
Maybe I'm trying to do too much here, but I've worked for hours on this with no luck. I hope you can help.
I am creating a function whose only parameter is a named range on a another sheet in the same workbook. My problem is that I can't figure out how to pass that name into the function and use it.
My goal is call the function to sum the column specified by the named range on the other worksheet, called Client Payments.
Here's my code that works:
Function PayPerMonth()
PayPerMonth = Application.WorksheetFunction.Sum(Worksheets("Client Payments").Range("C:C"))
End Function
I get a total that is correct, but of course I specified the column in the function. Not too useful.
Here's what I tried that doesn't work:
Function PayPerMonth(ColumnToAdd)
PayPerMonth = Application.WorksheetFunction.Sum(Worksheets("Client Payments").Range("ColumnToAdd"))
End Function
It doesn't work when I remove the quotes around ColumnToAdd, and many other variations I have tried.
What I want to do is to enter =PayPerMonth(MBPADV) or =PayPerMonth(SBTSADV) etc. to call the function and aim at the right column, where MBPADV and SBTSADV are named columns.
I'm not hung up on using the column names. It just makes it more readable (to me, anyway!).
Can this be done?
Range("named range") returns a range in the WorkBook so it should be good to pass into your function that takes a range.
Assuming you have a named range in the workbook called ColumnToAdd, this should work:
Function PayPerMonth(ColumnToAdd)
PayPerMonth = Application.WorksheetFunction.Sum(Range("ColumnToAdd")
End Function
Update per comments:
Function PayPerMonth(ColumnToAdd As Range)
PayPerMonth = Application.WorksheetFunction.Sum(Range(ColumnToAdd))
End Function
Usage:
Dim MyRange as Range
MyRange = Sheet.Columns("C")
Amount = PayPerMonth(MyRange)
Note:
Your function call will return a variant. You may want to declare As Integer, As Single or As Float at the end of Function PayPerMonth(ColumnToAdd As Range) to help A) speed the processing, since Excel won't have to spend time trying to figure out what type of variable it's working with, and B) yourself/the next coder when it comes time to maintain the code - being explicit makes your code more readable.
In a spreadsheet I can enter =SIN(45)+123 in a cell, and it will be evaluated.
How can I evaluate spreadsheet functions within a custom function, something like an "eval"
function that would work like this :
function myFunc() {
return Sheet.eval("=SIN(45)+123")
}
is it possible ?
Note that I don't care about the SIN function in particular, what I want is to have access to the complete arsenal of spreadsheet functions (PMT, QUERY, NPER, etc..)
Spreadsheet functions from Apps-Script
Not possible - This has been asked many times. Suggest you check the google-apps-script issue list to see if anything has changed. But last I checked, there is no way to do it, and they have no plan to add it. https://code.google.com/p/google-apps-script-issues/issues/list
Ethercalc - java script spreadsheet formulas
If you need to, you can always copy the code from "ethercalc" as it has a java script versions of the spreadsheet formulas.
https://github.com/audreyt/ethercalc
I know this is an old question, but it might help someone.
just assign the formula to a range, then grab the value.
//asign a formula to the range
var range = sheet.getRange("A1").setFormula("=SUM(D1:D100)");
//get the result
var result = range.getValue();
//clean up
range.setFormula("");
I got this working. Using set value will do the trick. Thus something like this:
function MyFun1(){
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('A1').setValue(Myfun2())
}
function MyFun2(){
return "=SIN(45)+123"
}
Hope this helps!
I think you need to divide this issue up into two different concerns.
Do you want to grab data that is already on the spreadsheet, perform a calculation, and then print a result, or do you want to use the sin() function on calculations in code unrelated to the data in the spreadsheet?
If you are trying to do the latter, you should be able to reference spreadsheet functions by using Math.sin() in your Google Apps Script. For more information on using the sin() function in JavaScript, check this post out: http://www.w3schools.com/jsref/jsref_sin.asp
If you are trying to do the former, then what you should do is use a readRows() function (more information available here: http://gassnippets.blogspot.com/2012/11/create-your-first-google-apps-script.html) to load your spreadsheet data into a variable (or variables) in memory, perform your calculations, and print the final result out to the spreadsheet using a similar function.
Let me know if this helps.
I came across this question in an attempt to find a way to evaluate part of a function like it is possible in Excel.
Here is my dirty workaround - instead of outputting the result in an msgbox, you could simply store the value or displayvalue of the activecell in a variable and use it to your liking.
Notice however, that the function will temporarily overwrite whatever you have in your currently selected cell and it will need to recalculate the sheet before the result is available. Hence it's not a viable solution if you need to evaluate multiple cell values.
function evalPart() {
var ui = SpreadsheetApp.getUi();
myPart = Browser.inputBox("Enter formula part:", ui.ButtonSet.OK_CANCEL);
if (myPart != "cancel") {
myActiveCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
myBackup = myActiveCell.getFormula();
myActiveCell.setFormula(myPart);
Browser.msgBox("Result of \\n \\n" + myPart + " \\n \\n " + myActiveCell.getDisplayValue());
myActiveCell.setFormula(myBackup);
}
}
I don't know if it's possible with high-level functions. However, it's possible with some common and easy-to-understand functions like (sum, subtract etc).
Following is the code I used to set values after the calculation is done in scripting itself.
function MyFun1() {
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('A1').setValue(MyFun2());
}
function MyFun2() {
var one = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Dashboard");
var two = one.getRange('A2').getValue();
var three = one.getRange('A3').getValue(); return two*three;
}
Don't forget to add a trigger "onEdit" on Myfun1() to automatically update the return value.