Concatenate a few cells and creating a link from concatenation - google-apps-script

I am trying to create a script where by assume
Column I contains Address
Column J contains City
Column K contains Zip code
Assume the there are thousands of entries
I wanted a script that would concatenate these values and create a google maps link on column I itself.
I did manage to get the link part working partly but could not get it to concatenate it before creating the link.
function googlemaps() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getActiveRange() + ss.getActiveRange().offset(0, 0, 1, 2);
// var t = r.offset(1, 0, 2);
var v = r.getValues();
for(var i=0;i<v.length;i++) {
for(var j=0;j<v[0].length;j++) {
v[i][j] = '=HYPERLINK("http://google.com/maps/places/'+v[i][j]+'","'+v[i][j]+'")'
}
}
r.setValues(v);
};
It keeps giving me this error
// typeError: Cannot find function getValues in object RangeRange
I know it's the offset thing but I can't get it to work.
An example of what i want would be
I3 = 1515 SW 2 CT
J3 = Miami
K3 = 33196
And with this script run, it would change I in
=hyperlink("http://google.com/maps/places/1515 SW 2 CT Miami 33196", "1515 SW 2 CT")
should be able to work across a range.
Anyone please help.
I tried this as well:
function googlemaps() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getActiveRange();
var r2 = ss.getActiveRange().offset(0, 1);
var r3 = ss.getActiveRange().offset(0, 2);
var v = r.getValues();
var v1= r2.getValues();
var v2= r3.getValues();
var vf= v + v1 + v2;
for(var i=0;i<vf.length;i++) {
for(var j=0;j<vf[0].length;j++) {
vf[i][j] = '=HYPERLINK("http://google.com/maps/places/'+vf[i][j]+'","'+vf[i][j]+'")'
}
}
r.setValues(vf);
};
and that does not work as well, gives me the error Cannot find method setValues(string)

You can also do this with just a formula.
I3 = 1515 SW 2 CT
J3 = Miami
K3 = 33196
L3 = =HYPERLINK(CONCATENATE("http://maps.google.com/maps? f=q&source=s_q&hl=en&geocode=&q=",I3," ",J3," ",K3),"Google Map")
Sorry I did not understand your requirement. Try this.
function googlemaps() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow()
var r = ss.getSheetValues(3,9,lr-2,3);//Assunes address data starts on row 3
for(var i=0;i<lr-2;i++) {
var addr = r[i][0]+' ' +r[i][1]+' ' +r[i][2] // Concatenates address data
r[i][9] = '=HYPERLINK("http://maps.google.com/maps? f=q&source=s_q&hl=en&geocode=&q='+addr+'","'+addr+'")'
ss.getRange(i+3,9).setFormula(r[i][9]);
ss.getRange(i+3,10).clear(); //Clears City
ss.getRange(i+3,11).clear(); //Clears Zip
}
};
Here is another version than creates an array of the hyperlinks and writes them back once instead of a row at a time. It is much faster. I tested it with 4000 addresses. Also, I changed it to start on row 2 (assuming a header row). If you need to adjust where it starts, Google setRange(1,1,1,1) notation for an explaination of what each number means. It controls the start row. Also the lr-1 would need to be changed if you change the start row so the total number of rows will be correct.
function googlemaps1() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow()
var r = ss.getSheetValues(2,9,lr-1,3);//Assunes address data starts on row 2
var arr = []
for(var i=0;i<lr-1;i++) {
var addr = r[i][0]+' ' +r[i][1]+' ' +r[i][2] // Concatenates address data
r[i][9] = '=HYPERLINK("http://maps.google.com/maps? f=q&source=s_q&hl=en&geocode=&q='+addr+'","'+addr+'")'
arr.push([r[i][9]])
}
var clr = ss.getRange(2,10,arr.length,2).clear();//clear state and zip
var destrange = ss.getRange(2,9,arr.length,1);
destrange.setFormulas(arr);// set all hyperlinks
};

Related

getting lat/long from address with geocode in google apps script

I've got this working code that gets the lat/long combo from an address.
function testgeocode(){
var responses = SpreadsheetApp.openById('###').getSheetByName('Form Responses');
var range = responses.getRange('AD2:AD');
var addresses = range.getValues();
var row = range.getRow();
var column = range.getColumn();
var destination = new Array();
destination[0] = 31; // column + 1;
destination[1] = 32; // column + 2;
var geocoder = Maps.newGeocoder();
var count = range.getHeight();
for(i in addresses) {
var location = geocoder.geocode(addresses[i]).results[0].geometry.location;
responses.getRange(row, destination[0]).setValue(location.lat);
responses.getRange(row++, destination[1]).setValue(location.lng);
Utilities.sleep(200);
}
}
I'm having difficulty modifying it so that the lat/long combo is outputted into one column with the format 'lat,long'.
Explanation / Issues:
First of all, your code is quite inefficient. The reason for that is because you are using getRange and setValue inside a for loop but also two times per iteration. As it is explained in the best practices, the proper way to achieve your goal is to store the values into an empty array and then use setValues outside the for loop to set them to your sheet.
The other modification is already mentioned in the other answer. You want to concatenate location.lat, location.lng separated by a comma.
Solution:
function testgeocode(){
var responses = SpreadsheetApp.openById('###').getSheetByName('Form Responses');
var range = responses.getRange('AD2:AD');
var addresses = range.getValues();
var row = range.getRow();
var column = range.getColumn();
var destination = new Array();
destination[0] = 31; // column + 1;
destination[1] = 32; // column + 2;
var geocoder = Maps.newGeocoder();
var count = range.getHeight();
var data = [];
for(i in addresses) {
var location = geocoder.geocode(addresses[i]).results[0].geometry.location;
data.push([location.lat + ',' + location.lng]) // new code
Utilities.sleep(200);
}
responses.getRange(2,destination[0],data.length,1).setValues(data); // new code
}
From what I understood, currently you're getting the latitude and longitude values and writing them to different cells, but you want to have them both in a single cell, separated by a comma.
If that's the case, then you can make the following changes.
From:
var location = geocoder.geocode(addresses[i]).results[0].geometry.location;
responses.getRange(row, destination[0]).setValue(location.lat);
responses.getRange(row++, destination[1]).setValue(location.lng);
To:
var location = geocoder.geocode(addresses[i]).results[0].geometry.location;
responses.getRange(row, destination[0]).setValue(location.lat + ',' + location.lng);
You can adjust the parameters of getRange() if you want to write it to a different cell.

append columns in google script

I have been able to append a new row of data from an imported and live updating postgres import on google sheets. My requirement is to get the data to append in a new column, next to the one previous.
// function to save data
function saveData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var count = sheet.getRange('Sheet1!A3').getValue();
var date = sheet.getRange('Sheet1!B3').getValue();
sheet.insertColumnAfter(sheet.getMaxColumns());
sheet.getRange(1,sheet.getLastColumn(),2).setValues([count,date]);
}
Im getting the error of not being able to turn an object into an array - any help?
function append() {
var tabLists = "append"; //my sheet is named as "append"
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
sheet.clear()
var date = new Date('October 11, 2018 09:15:00')
var sr = 4
var sft = 1
var sc = 1
var nr = 1
var nc = 1
for(var i=0; i<5;i++){ //I'm appendind 5 columns for now.
sheet.getRange(sr,sc,nr,nc)//(start row, start column, number of rows, number of
columns)
.setValues([[
date
]]);
sc = sc + 1
}
}

Optimal way to set cell values in Google Sheet via Script

I have a template sheet with checkboxes and I want to copy the checked ones to a new sheet. I have a working version that involves adding rows but I am looking for something faster. I thought getting a range of values on both the new and old sheets and working on the arrays would be best but I hit a error:
'Cannot covert Array to Object[][]".
I think the issue has to do with the fact that this is a new unpopulated sheet. The code below is the simplest example of what is happening. Am I doing something wrong, or is this just not possible?
function test(){
var s = SpreadsheetApp.getActiveSpreadsheet().insertSheet();
var r = s.getRange(1,1,5);
var v = r.getValues();
for ( var i=0; i < 5; i++) {
v[i] = i;
}
r.setValues(v); //ERROR: Cannot covert Array to Object[][]`enter code here`
}
It looks like the line v[i] = i; converts the Object[][] to an array. So , i think (bizarre) I need to create a new array[][] asfollows:
function test(){
var s = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var r = s.getRange(1,1,5,1);
var v = r.getValues();
var ta = [];
for ( var i=0; i < 5; i++) {
ta[i] = [];
ta[i].push(i) ;
}
r.setValues(ta);
}
Ok. Here is the full solution.
The function looks for the sheet "Work" that has 2 columns; the first is a checkbox, the second is the string value of interest. For every checked box (value == true), the 2nd column's value, Font weight, and Font size are copied into appropriately 'shaped' structures.
Once constructed, a new sheet is created, a range in the new sheet is retrieved and used to set the values, weights and sizes of a single column.
function copyCheckedItems () {
var cl = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Work');
if (cl) {
var cnt = cl.getLastRow();
var range = cl.getRange(1,1, cnt, 2 );
var values = range.getValues();
var weights = range.getFontWeights();
var sizes = range.getFontSizes();
// Compute data needed for new sheet in the right shape.
var tv = [];
var tw = [];
var ts = [];
var newCnt = 0;
for (var row in values) {
if(values[row][0]){
tv[newCnt] = [];
ts[newCnt] = [];
tw[newCnt] = [];
tv[newCnt].push(values[row][1]);
tw[newCnt].push(weights[row][1]);
ts[newCnt].push(sizes[row][1]);
newCnt++;
}
}
// construct the new sheet in a minimum of calls
var name = Browser.inputBox('Enter WorkSteet name');;
var sheetOut = SpreadsheetApp.getActiveSpreadsheet().insertSheet(name);
var ro = sheetOut.getRange(1,1,newCnt,1);
ro.setValues(tv);
ro.setFontSizes(ts);
ro.setFontWeights(tw);
//Browser.msgBox("Done.");
}
else {
Browser.msgBox('Work sheet not found!');
}
}

Script for copy range from a sheet onto another, delete copied range and paste new formulas from a third sheet

I'm trying to develop a script to do the following on google spreadsheets:
1) Copy the range B3:K102 on Tab Source1 on spreadsheet 1.
2) Paste the copied range (as values) onto the last available row of Tab Destination1 on Spreadsheet 2.
3) Clear the range B3:K102 on spreadsheet 1.
4) Copy range C3:K102 on Tab 'Source2' spreadsheet 1.
5) Paste the copied range from 'Source2' onto 'Source1!B3:K102'(as formulas).
Below is the script that Im trying and can't make it work. PLEASE HELP!
Notice that I have little to no clue on what Im doing, I got this script from a friend who know's a little bit, but he's no longer able to help me. So if anyone could please help me by correcting the mistakes and adding what it's missing, I will really appreciate if you could paste the entire final script so I don't mess it up.
THANKS A LOT!
function Copy() {
var sss = SpreadsheetApp.openById('19BsivpPDO8ov3tHXslCzNQi0cB8YeP1gQ-5Zt-4Eb64');
var ss = sss.getSheetByName('Source1');
var range = ss.getRange('B3:K102');
var data = range.getValues();
var tss = SpreadsheetApp.openById('1tVnIMNQ7oE8YuxLU2KpBSL-Py3T8IqJwV6j59Pfo3j0');
var ts = tss.getSheetByName('Destination1');
var endOfFile = ts.getLastRow();
var cantColumns = 10;
for (var i = 0; i < cantColumns; i++) {
endOfFile = endOfFile + 1
for (var cont = 1; cont < ss.getLastColumn(); cont++) {
ts.getRange(endOfFile, cont + 1).setValue(data[i][cont -1]);
}
}
range.clearContent();
var sss = SpreadsheetApp.openById('19BsivpPDO8ov3tHXslCzNQi0cB8YeP1gQ-5Zt-4Eb64');
var ss = sss.getSheetByName(‘Source2’);
var range = ss.getRange(‘C3:K102’);
var data = range.getValues();
var tss = SpreadsheetApp.openById('19BsivpPDO8ov3tHXslCzNQi0cB8YeP1gQ-5Zt-4Eb64');
var ts = tss.getSheetByName(‘Source1’);
var endOfFile = ts.getLastRow();
var cantColumns = 9;
for (var i = 0; i < cantColumns; i++) {
endOfFile = endOfFile + 1
// Recorremos la fila y vamos insertando los valores
for (var cont = 1; cont < ss.getLastColumn(); cont++) {
ts.getRange(endOfFile, cont + 1).setValue(data[i][cont -1]);
}
This sample script may not be what you want since I cannot see your sample sheet. So if this isn't what you want, feel free to tell me.
When it imports many data to cells, "setValues()" is faster than "setValue()". https://developers.google.com/apps-script/reference/spreadsheet/range#setValues(Object)
"getValues()" can retrieve the values of cells. "getFormulas()" can retrieve the formulas of cells. In this sample, both values and formulas are retrieved and copy from Source2 to Source1.
For copying from Source2 to Source1, do you want to copy the data to last row of Source1 or to 'B3:K102'? At current sample, it's last row of Source1 like your script. If Source1 has cells (less than 102) except for 'B3:K102', formulas from Source2 may not work at Source1.
Sample script :
function Copy() {
var srcs = '19BsivpPDO8ov3tHXslCzNQi0cB8YeP1gQ-5Zt-4Eb64';
var dest = '1tVnIMNQ7oE8YuxLU2KpBSL-Py3T8IqJwV6j59Pfo3j0';
var srcs_ss = SpreadsheetApp.openById(srcs);
var dest_ss = SpreadsheetApp.openById(dest);
var src1 = srcs_ss.getSheetByName('Source1');
var src2 = srcs_ss.getSheetByName('Source2');
var dest = dest_ss.getSheetByName('Destination1');
var src1_range = src1.getRange('B3:K102');
var src1_f = src1_range.getFormulas();
var src1_dat = src1_range.getValues();
src1_f.forEach(function(e1, i1){
e1.forEach(function(e2, i2){
if (e2 != "") src1_dat[i1][i2] = e2;
});
});
src1_range.clearContent();
dest.getRange(dest.getLastRow(), 2, src1_dat.length, src1_dat[0].length).setValues(src1_dat);
var src2_dat = src2.getRange('C3:K102').getValues();
src1.getRange(src1.getLastRow(), 2, src2_dat.length, src2_dat[0].length).setValues(src2_dat);
}

Unable to process the operation because it contains too much data. Google Apps Script

I have two sheets.
First is data from JSON with max results 100 rows. It contains 8 columns.
Second is the data I add manually and then write to the first sheet based on matched title.
For example, if both titles match then create a new column "Category" in first sheet from second sheet. The second sheet contains 50 rows and 8 columns.
When I run this script it throws error: We're sorry, we were unable to process the operation because it contains too much data. I tried to remove line by line to figure out what is causing it. And it seems like when I remove this line:
data[i][11] = descr; // this is a paragraph long description text
It is working fine. Also, if I remove all the other data I want to write in, and run only data[i][11] = descr; it also chokes. So, it doesn' seem like there is too much data. Any ideas how to make it work? Workarounds?
Edit: here is a copy of the spreadsheet:
https://docs.google.com/spreadsheet/ccc?key=0AhVWrVLsk5a5dFRaeFQxZUc3WlZOR0h4N09pOGJBdGc&usp=sharing
Thanks!
function listClasses(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //list of all upcoming classes
var sheet1 = ss.getSheets()[1]; //list of titles
var data = sheet.getDataRange().getValues(); // read all data in the sheet
var data1 = sheet1.getDataRange().getValues();
for(n=1;n<data1.length;n++){
var title1 = data1[n][0];
var category = data1[n][1];
var image_url = data1[n][2];
var available = data1[n][3];
var descr = data1[n][4];
var prerequisites = data1[n][5];
var mAccess = data1[n][6];
var notes = data1[n][7];
// compare Check if title appears in column B of sheet 1.
if (ArrayLib.find(data1, 0, title1) != -1) {
// Yes it does, do something in sheet 0
for( var i = data.length -1; i >= 0; --i )
if (data[i][1] == title1)
{
//Logger.log(descr);
if (data[i].length < 14){
data[i].push(' ');
}
data[i][8] = category;
data[i][9] = image_url;
data[i][10] = available;
data[i][11] = descr;
data[i][12] = prerequisites;
data[i][13] = mAccess;
data[i][14] = notes;
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
}
}
I had a look at your code, but I could not make it work.
I too get such error messages, but so far have encountered them when I am processing a few thousand rows (with only 4 columns) but each row containing as much text or more than your description.
I only know how to use a simple way, which I tried for your case too. The following code I think does what you need:
function listClasses2(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //list of all upcoming classes
var sheet1 = ss.getSheets()[1]; //list of titles
var data = sheet.getDataRange().getValues(); // read all data in the sheet
var data1 = sheet1.getDataRange().getValues();
var newDataArray = [data[0]];
for(var n=1; n < data.length ; n++){
for(var j=0; j< data1.length ; j++){
if(data[n][1] == data1[j][0]){
newDataArray.push([data[n][0] ,data[n][1] ,data[n][2] ,data[n][3] ,data[n][4] ,data[n][5] ,data[n][6] ,data[n][7] ,data1[j][1] , data1[j][2] , data1[j][3] , data1[j][4] , data1[j][5] , data1[j][6], data1[j][7] ]) ;
break;}
}
newDataArray.push(data[n])
}
sheet.getRange(1, 1, newDataArray.length, newDataArray[0].length).setValues(newDataArray);
}
(I have just noticed that my var n is not the same as your var n ... sorry for the possible confusion)