Getlink script Google Sheet hyperlink - function

I have been trying to use a getlink function for extracting the URL of a hyperlink. The cell from which I need to extract a link is not configured with a hyperlink formula.
Screenshot Spreadsheet with link to URL (hovered above cell)
However when I use the script below, I always get:
*TypeError: Cannot read properties of null (reading 'getLinkUrl') (line 5). Why is that? *
The formula that I use for this function:
=GETLINK(CELL("Address";R2))
Script that I use:
function GETLINK(input){
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(input);
var value = range.getRichTextValue();
var url = value.getLinkUrl(0,1);
return url;
}

Modification points:
From your following sample image and your error message of TypeError: Cannot read properties of null (reading 'getLinkUrl'),
I thought that your current issue might be due to the number value. In the current stage, when the cell value is the number value, range.getRichTextValue() returns null. (This has already been reported to the Google issue tracker. Ref) In this case, an error like your error message is shown even when the cell has a hyperlink.
In order to remove this issue and retrieve the hyperlink, how about the following modification?
Modified script:
Please copy and paste the following script to the script editor of Google Spreadsheet and save the script.
In this modification, this script cannot be used as the custom function because of setNumberFormat. So, I proposed a sample script for retrieving the URLs from the source range and putting the URL into the destination range.
When you use this script, please set the values of srcRange and dstRange, and run the script by the script editor. By this, the script is run and retrieves the URL from srcRange, and the retrieved URLs are put to dstRange.
function sample() {
var srcRange = "Sheet1!A1:A10"; // Please set the source range you want to use.
var dstRange = "Sheet2!B1:B10"; // Please set the destination range you want to use.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange(srcRange);
var orgNumberFormats = range.getNumberFormats();
var values = range.setNumberFormat("#").getRichTextValues();
var urls = values.map(r => r.map(c => c && (c.getLinkUrl() || "")));
range.setNumberFormats(orgNumberFormats);
ss.getRange(dstRange).setValues(urls);
}
When this script is run, the number formats of srcRange are saved, the cell values are converted to the string values, and the rich text values are retrieved from srcRange. And then, the URL is retrieved and the URLs are put to dstRange.
Note:
In the case that your error is removed from your showing script, the following script can be used. But, in this case, when the cell value is the number value, no value is returned even when the cell has a hyperlink. Please be careful about this.
function GETLINK(input) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(input);
var value = range.getRichTextValue();
return value && value.getLinkUrl(0, 1);
}
References:
map()
getNumberFormats()
setNumberFormats(numberFormats)

Related

How to Preserve Sheet Formats and Translate? ( Google Apps Script, google sheet )

How can i Preserve Sheet Formats and Translate?
I don't want to use the translation latency(1000) or translate cell by cell. it was worked well but I have a large amount of text I want to translate.
I used the following code:
var range1 = sheet1.getRange("A:A");
text1 = range1.getValues();
translatedtext = LanguageApp.translate(text1, 'ko', 'en');
This is the starting language. from log. after getValues from sheet.
If I 'setValue' this into the sheet as it is, it will be written in each cell as it is.
[안녕하세요], [사과], [], [바나나]
This is how it is translated.
Line breaks are gone and replaced with commas, when pasting them into a sheet, it puts all the text in one cell.
hello, apple,, banana
I believe your goal is as follows.
You want to translate the cell values of the sheet by reducing the process cost.
In this case, how about the following modification?
Modified script 1:
In this pattern, the cell values are translated after the retrieved values were converted to the string. By this flow, LanguageApp.translate is used by one call.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1"); // Please set your sheet name.
var range = sheet.getRange("A1:A" + sheet.getLastRow())
var values = JSON.parse(LanguageApp.translate(JSON.stringify(range.getValues()), 'ko', 'en'));
range.offset(0, 1).setValues(values);
When this script is run, the values are retrieved from column "A", and the values are translated, and then, the translated values are put into column "B".
Modified script 2:
In this pattern, the cell values are retrieved as the CSV data, and translated it. And then, the translated values are parsed and put into the cells. By this flow, LanguageApp.translate is used by one call.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1"); // Please set your sheet name.
var url = `https://docs.google.com/spreadsheets/export?exportFormat=csv&id=${ss.getId()}&gid=${sheet.getSheetId()}`;
var res = UrlFetchApp.fetch(url, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } });
var csv = res.getContentText();
var translated = LanguageApp.translate(csv, 'ko', 'en');
var ar = Utilities.parseCsv(translated).map(([a]) => [a]);
sheet.getRange(1, 2, ar.length).setValues(ar);
// DriveApp.getFiles(); // This comment line is used for automatically detecting the scope of Drive API.
When this script is run, the values are retrieved from column "A", and the values are translated, and then, the translated values are put into column "B".
If an error related to the scopes occurs, please include the scope of Drive API.
Reference:
map()

Google Sheet App Scripts : How to parse JSONs in Sheet A column A to Sheet B?

I have a google spreadsheet with Sheet A having JSONs in column A and I'd like to populate Sheet B with the data with respective rows and columns. However I'm not entirely sure how to start. I'm a bit confused about the whole process. First declaring sheet. I've seen people using the following:
function parseJSON()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the Active Spreadsheet
var sheet = ss.getSheets()[0]; // Gets the first sheet
var parsed = JSON.parse(json);
sheet.appendRow([json.items[i].id, json.items[i].name, json.items[i].url]);
}
but I have in 1 active spreadsheet from sheet A to sheet B. So would i need to declare a second sheet (my sheet B)?
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the Active Spreadsheet
var sheet1 = ss.getSheets()[0]; // Gets the first sheet
var sheet2 = ss.getSheets()[1]; // Gets the first sheet
sheet2.appendRow([json.items[i].id, json.items[i].name, json.items[i].url]);
or i dont need those declarations and i just
function parseJSON(parsed)
{
return [parsed.items[i].id, parsed.items[i].name, parsed.items[i].url]
}
so in Sheet B A1 i just put =parseJSON(SheetB!A) or something equivalent which im still unsure.
Also how do i declare what are headers and the values according to the JSON? Should the headers be declared?
const headers = ["dish_name","dish_price","dish_quantity"];
or is it possible to get the header from the JSON? How about the corresponding values? Does Apps Ssripts accept foreach loop?
For additional context (for selected answer that helped)
JSON Obj - {"55":{"dish_name":"(Ala Carte) Claypot Soup with Rice and Char Kuih","dish_price":17,"dish_quantity":1,"dish_size_name":"default","dish_size_price":0,"dish_addon_name":"default","dish_addon_price":0,"dish_variation_name":"default","dish_variation_price":0}}
the selected answer was able to split it up in key value pairs. so constant keys were headers, rows were the corresponding values.
In your situation, how about the following modification?
Modification points:
About your following script,
function parseJSON()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the Active Spreadsheet
var sheet = ss.getSheets()[0]; // Gets the first sheet
var parsed = JSON.parse(json);
sheet.appendRow([json.items[i].id, json.items[i].name, json.items[i].url]);
}
In this case, sheet, json are not declared. By this, an error occurs.
When sheet, json are declared, parsed is not used.
Answer for question 1:
but I have in 1 active spreadsheet from sheet A to sheet B. So would i need to declare a second sheet (my sheet B)?
I think that it's yes. I think that when you want to retrieve the values from the column "A" of Sheet "A" and the values are put to Sheet "B", it is required to declare both sheets.
Answer for question 2:
Also how do i declare what are headers and the values according to the JSON? Should the headers be declared? or is it possible to get the header from the JSON? How about the corresponding values? Does Apps Ssripts accept foreach loop?
I think that it's yes. When I saw your JSON data, it seems that several properties are existing. And, in your output situation, it is required to put the values in order. In this case, when the header value is used, the script can be easily prepared.
Sample script:
In order to achieve your goal, how about the following sample script?
function myFunction() {
// 1. Retrieve source and destination sheets.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const [srcSheet, dstSheet] = ["Sheet1", "Sheet2"].map(s => ss.getSheetByName(s));
// 2. Retrieve values from source sheet.
const values = srcSheet.getRange("A1:A" + srcSheet.getLastRow()).getValues();
// 3. Create an array for putting to the destination sheet using the header value.
const headers = ["dish_name","dish_price","dish_quantity"];
const ar = [["", ...headers], ...values.flatMap(([a]) => Object.entries(JSON.parse(a)).map(([k, v]) => [k, ...headers.map(h => v[h] || "")]))];
// 4. Put the array to the destination sheet.
dstSheet.getRange(1, 1, ar.length, ar[0].length).setValues(ar);
}
This sample script retrieves the values from column "A" of the source sheet "Sheet1" and converted the values to the 2-dimensional array and put the array to the destination sheet "Sheet2".
Please modify the sheet names of the source "Sheet1" and destination "Sheet2" sheets for your actual situation, respectively.
References:
map()
getValues()
setValues(values)

Google Sheets 'Exception: Range not found' error for URL formula

I have this formula that extracts the link from a word with hyperlink. Now when I'm trying to move it to another spreadsheet and run it I get an 'Exception: Range not found' error. I was reading this might be cuz I need a 'getRangeList' insted of getRange, but it doesn't work this way either. Now I get the 'Exception: The parameters (number) don't match the method signature for SpreadsheetApp.Sheet.getRangeList.'
Here's the code I'm using:
function URL(refrence) {
var sheet = SpreadsheetApp.getActiveSheet();
var formula = SpreadsheetApp.getActiveRange().getFormula();
var a1 = formula.replace("=url(","");
a1 = a1.replace(")","");
var url = sheet.getRange(a1).getRichTextValue().getLinkUrl();
return url
}
FINDINGS
The part getRange(a1) is incorrect as the variable a1 contains an invalid Sheet range.
SUGGESTION
If your main goal is to easily extract the URL from a cell with hyperlink like =HYPERLINK("http://www.google.com/","Google") you may use these tweaked scripts below:
These scripts were derived from the answers of these posts How to extract URL from Link in Google Sheets using a formula & Google Apps Script Regular Expression
This version of the script will only show the url value from the Apps Script editor's log results:
function URL() {
var sheet = SpreadsheetApp.getActiveSheet();
var formula = sheet.getActiveRange().getFormula();
var regExp = new RegExp("\"(.*)\",\"", "gm");
var url = regExp.exec(formula)[1];
Logger.log(url)
}
Note: Before running, make sure the cell with hyperlink is selected on your sheet (in my case it was on cell A1).
Sample result on the logs:
This another version will let you to use your script as a custom function =URL() on your spreadsheet file:
function URL(refrence) {
var regExp = new RegExp("\"(.*)\",\"", "gm");
var url = regExp.exec(refrence)[1]
return url
}
Sample Result as a custom function:
=URL(FORMULATEXT(A1))
Reference:
FORMULATEXT function

Google Sheets - Basic Script

I have a working code that I want to be able to pull down on all my rows but at the moment it only returns data from the first cell rather than updating as I drag down.
I have tried so many different things but no luck. Please help me. Here is the current Sheet https://docs.google.com/spreadsheets/d/1tKy_1BugK1vlq4hPAbjkTCmeunlb6LU0C7pv1rPeSqs/edit?usp=sharing
I believe your goal as follows.
You want to retrieve the values from URLs at the column "B" using the custom function.
The screen shot of your sample Spreadsheet is as follows.
Your current script is as follows. (This script is from your sample Spreadsheet.)
function AsxPrice() {
var url = SpreadsheetApp.getActiveSheet().getRange('B2').getValue();
var response = UrlFetchApp.fetch(url);
var content = response.getContentText();
Logger.log(content);
var json = JSON.parse(content);
var last_price = json["last_price"];
return last_price;
}
In your script, the cell range is constant like B2. So in this answer, I would like to propose to retrieve the URLs as the arguments for the custom function. The sample script is as follows.
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet. And in this custom function, when your sample Spreadsheet is used, please put the formula of =AsxPrice2(B2:B4) to a cell. By this, the URLs are retrieved from the cells "B2:B4" and retrieve the values.
function AsxPrice2(values) {
const reqs = values.flat().map(url => ({url: url, muteHttpExceptions: true}));
return UrlFetchApp.fetchAll(reqs).map(r => [r.getResponseCode() == 200 ? JSON.parse(r.getContentText()).last_price : ""]);
}
Result:
When above scvript is used for your sample Spreadsheet, it becomes as follows.
Note:
When a lot of URLs are used, an error might occur. Please be careful this.
References:
Custom Functions in Google Sheets
fetchAll(requests)
Solution
You only have to modify your function to have an input parameter which is the url
Code
function AsxPrice(url) {
var response = UrlFetchApp.fetch(url);
var content = response.getContentText();
Logger.log(content);
var json = JSON.parse(content);
var last_price = json["last_price"];
return last_price;
}
References:
Custom functions

What is VBA's format function equivalent in Google Scripts/Sheets?

I'm having some trouble to achieve next VBA code's goal in Google Scripts (changing the number format of a variable adding zeros at the left up to figures)
'VBA CODE
sub addingZeros()
dim num1 as double
'Cell A1's value is 1, so I get 0001
num1 = format(thisWorkbook.Sheets("MySheet").range("A1"),"0000")
end sub
When I was researching, everything pointed out to use the setNumberFormat function, which is not a solution for me, because makes me to change the number in the sheet and I need only to change the variable value for further purposes... There was only one different solution in those I found, which uses a text function but I couldn't make it work (link for that solution)
I'd like a code similar to this:
//Google Scripts CODE
function myFunction() {
var ss = SpreadsheetApp.openById(`XXXXXXXXXXXXX`);
var sheet = ss.getSheetByName('MySheet');
var num1 = format(sheet.getRange('a1').getValue(),"0000");
//Cell A1's value is 1, so I'm expecting to get 0001
Logger.log(num1);
};
All the help will be much appreciated.
Antonio
I believe your goal as follows.
You want to retrieve a value from a cell and you want to convert the format from 1 to 0001.
You want to achieve this using Google Apps Script.
Pattern 1:
In this pattern, Utilities.formatString is used.
Sample script:
function myFunction() {
var ss = SpreadsheetApp.openById(`XXXXXXXXXXXXX`);
var sheet = ss.getSheetByName('MySheet');
var res = Utilities.formatString("%04d", sheet.getRange("A2").getValue()); // Modified
Logger.log(res)
}
In this modification, the value of 1 is retrieved from the cell "A1" and the format is converted to 0001 using Utilities.formatString.
Pattern 2:
In this pattern, setNumberFormat is used.
Sample script:
function myFunction() {
var ss = SpreadsheetApp.openById(`XXXXXXXXXXXXX`);
var sheet = ss.getSheetByName('MySheet');
var res = sheet.getRange("A1").setNumberFormat("0000").getDisplayValue(); // Modified
Logger.log(res)
}
In this modification, the format of cell "A1" is changed using setNumberFormat and retrieved the display value using getDisplayValue.
Note:
These modified scripts are the simple modification. So please modify them for your actual situation.
References:
formatString(template, args)
setNumberFormat(numberFormat)
getDisplayValue()