Removing 'undefined' from output before writing to Google Sheets - google-apps-script

My script below returns 'undefined' to the Google Sheet when I add dfStatus.error.count to the array to be written.
function getDatafeedStatus() {
var d = new Date();
var ar = [];
for (var a in FEEDS) {
for (var i = 0; i < FEEDS[a].length; i++) {
try {
var dfStatus = ShoppingContent.Datafeedstatuses.get(a, FEEDS[a][i]);
// see https://developers.google.com/shopping-content/v2/reference/v2/datafeedstatuses for detail on this API call
ar.push([d, a, FEEDS[a][i], dfStatus.processingStatus, dfStatus.lastUploadDate, dfStatus.itemsValid, dfStatus.errors.count]);
} catch (e) {
Logger.log(e.message); // check View > Logs after running the script if a feed does not appear to be fetching correctly
}
}
}
appendArrayToSheet(ar, 'status');
}
/**
* Add an array to the bottom of a sheet. If the sheet doesn't exist, it is created.
* #param {array} ar - the array to write
* #param {string} sheetName - the name of the sheet to which to write
*/
function appendArrayToSheet(ar, sheetName){
if (ar.length !== 0 && ar[0].length !== 0){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
if (sheet == null) {
sheet = ss.insertSheet();
sheet.setName(sheetName);
};
var range = sheet.getDataRange();
var row = range.getLastRow() + 1;
var newRange = sheet.getRange(row, 1, ar.length, ar[0].length);
newRange.setValues(ar);
}
Any ideas whats wrong with it? I must say I'm not a JavaScript expert. I'm trying modify the code which is already used somewhere else.

Related

=URL() Script code issue | ReferenceError: btn is not defined (line 9, file "Code")

I am having an issue trying to use a script to extract the URL from one test with hyperlink.
Here is the script I am using:
function URL(reference) {
var sheet = SpreadsheetApp.getActiveSheet();
var formula = SpreadsheetApp.getActiveRange().getFormula();
var args = formula.match(/=\w+\((.*)\)/i);
try {
var range = sheet.getRange(args[1]);
}
catch(e) {
throw new Error(args[1] + 'is not a valid range');
}
var formulas = range.getFormulas();
var output = [];
for (var i = 0; i < formulas.length; i++) {
var row = [];
for (var j = 0; j < formulas[0].length; j++) {
var url = formulas[i][j].match(/=hyperlink\("([^"]+)"/i);
row.push(url ? url[1] : '');
}
output.push(row);
}
return output
}
After I run the script I get this error message:
TypeError: Cannot read property '1' of null (line 9, file "Code")
Any idea where the issue comes from and I can solve this?
You have try/catch block that throws error, but in catch block you are trying to iterate null object again:
try {
var range = sheet.getRange(args[1]);
}
catch(e) {
throw new Error(args[1] + 'is not a valid range'); // <- `args[1]` is producing new error
}
If you change catch content to throw new Error(formula + 'is not a valid range');, it should work.
Retrieve the hyperlink with the Advanced Sheets Service and assign the script to a button
The way you are following so far (extracting a hyperlink from a formula) is an old solution that does not work anymore
Currently, to retrieve a spreadsheet you need to use the Sheets API method spreadsheets:get
To use the Sheest API in Apps Script, you need to enable it in the editor
Sample script:
function URL() {
var spreadsheet =SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var id = spreadsheet.getId();
var range = sheet.getActiveRange();
var linkArray = Sheets.Spreadsheets.get(id, {ranges: sheet.getName() + "!" + range.getA1Notation(), fields: "sheets/data/rowData/values/hyperlink"});
var link = linkArray.sheets[0].data[0].rowData[0].values[0].hyperlink;
var cellInB = sheet.getRange(range.getRow(), 2);
cellInB.setValue(link);
}
As mentioned in the comments, in your use case it is not possible to use custom formulas, instead create a drawing and assign the script to it:
Now, select a cell in column A, click on the button and the link will be populated in column B.
UPDATE:
To retrieve all URLs at once you can use the followign script and run it manually:
function getAllURLs() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var id = spreadsheet.getId();
var lastRow = sheet.getRange("A2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
var range = sheet.getRange(2,1,lastRow-1, 1);
var linkArray = Sheets.Spreadsheets.get(id, {ranges: sheet.getName() + "!" + range.getA1Notation(), fields: "sheets/data/rowData/values/hyperlink"});
var links = [];
for (var i = 0; i< linkArray.sheets[0].data[0].rowData.length; i++){
var link = linkArray.sheets[0].data[0].rowData[i].values[0].hyperlink;
links[i] = [];
links[i].push(link);
}
var cellsInB = sheet.getRange(2,2,lastRow-1, 1);
cellsInB.setValues(links);
}

How do I pull a Row from an Array in Google apps script Google sheets

My spreadsheet is composed of a main sheet that is populated using a form plus several other sheets for the people who work with the responses submitted through the form. A script delegates the form responses to these other sheets depending on the type of item described in the response.
The problem is, when Person A deletes an item from their respective sheet, it doesn't delete in the main sheet.
My idea is that when you type a set password into the corresponding cell in row 'Q' in Person A's sheet, it matches the item by timestamp to the original form submission and deletes both the version of the item in Person A's sheet as well as the main sheet. However, I can't figure out what to set the range to to get it to point to the row in the array. Everything I have tried has sent back "undefined" in the debugger and won't delete anything. I think the problem is that I don't know how to get the row from the array that I have made. See my code below:
function onEdit() {//copies edited items from individual selector sheets back onto main spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var actSheet = ss.getActiveSheet();
var responseSheet = ss.getSheetByName("Item Request");
var actCell = actSheet.getActiveCell();
var actRow = actCell.getRow();
var actVal = actCell.getValue();
var actLoc = actCell.getA1Notation();
var last = actSheet.getLastRow();
var respLast = responseSheet.getLastRow();
var dataA = responseSheet.getRange(1, 1, respLast, 1).getValues(); //compiles an array of data found in column A through last row in response sheet
var tstamp1 = actSheet.getRange(actCell.getRow(), 1);
var tsVal1 = tstamp1.getValue();
var colEdit = actCell.getColumn();
//===========THIS IS WHERE I'M STUCK=======================
if ((actVal == "p#ssword") && (colEdit == 17)) {
for (i = 1; i < dataA.length; i++) {
if (dataA[i][0].toString == tsVal1.toString()) {
responseSheet.deleteRow(i + 1);
actSheet.deleteRow(actRow);
break;
}
}
}
else if (colEdit == 15) { //checks the array to see if the edit was made to the "O" column
for (i = 1; i < dataA.length; i++) {//checking for timestamp match and copies entry
if (dataA[i][0].toString() == tsVal1.toString()) {
var toEdit = responseSheet.getRange(i + 1, 16);
toEdit.setValue(actVal);
}
}
}
else if (colEdit == 16) { // checks the array to see if the edit was made in the "P" column
for (i = 1; i < dataA.length; i++) {//checking for timestamp match and copies entry
if (dataA[i][0].toString() == tsVal1.toString()) {
var toEdit = responseSheet.getRange(i + 1, 17);
toEdit.setValue(actVal);
}
}
}
else {return;}
}//end onEdit
I don't believe these are proper commands delRow.deleteRow();actCell.deleteRow(); Take a look at the documentation;
Okay I rewrote that function for you a bit but I'm stilling wondering about a couple of lines.
function onEdit(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var actSheet = ss.getActiveSheet();
var responseSheet = ss.getSheetByName("Item Request");
var actCell = actSheet.getActiveCell();
var actRow = actCell.getRow();
var actVal = actCell.getValue();
var colEdit = actCell.getColumn();
var respLast = responseSheet.getLastRow();
var dataA = responseSheet.getRange(1, 1, respLast, 1).getValues();
var tstamp1 = actSheet.getRange(actRow, 1);
var tsVal1 = tstamp1.getValue();
for(var i=0;i<dataA.length;i++)
{
if(new Date(dataA[i][0]).valueOf()==new Date(tsVal1).valueOf())
{
if (actVal=="p#ssword" && colEdit==17)
{
responseSheet.deleteRow(i + 1);
actSheet.deleteRow(actRow);
}
else if(colEdit==15)
{
var toEdit = responseSheet.getRange(i + 1, 16);//?
toEdit.setValue(actVal);//?
}
else if (colEdit == 16)
{
var toEdit = responseSheet.getRange(i + 1, 17);//?
toEdit.setValue(actVal);//?
}
}
}
}
Can you explain the function of the lines with question marked comments?

Zillow and Google Script

I have a script that pulls data from Zillow into a google doc....see below. It has worked fine for a couple of years but recently stopped working. It appears to run but takes a long time and no data is populated. The Zillow ID is located in Column B of the active sheet and according to the script the Zestimate should be written in Column 48. I've replaced my ZWS-ID with "X1-XXXXXXXXX_XXXX"
Any help is greatly appreciated.
Thanks
KIWI
function getZillowEstimates() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var specificRow = ""
var endRow;
if(specificRow == "")
{
specificRow = 1;
endRow = numRows;
}
else
{
specificRow = specificRow - 1;
endRow = specificRow;
}
for (var i = specificRow; i <= endRow; i++)
{
try
{
var row = values[i];
var response = UrlFetchApp.fetch("http://www.zillow.com/webservice/GetZestimate.htm?zws-id=X1-XXXXXXXXX_XXXX&zpid=" + row[1]);
var xmlDoc = XmlService.parse(response.getContentText());
var documentElement = xmlDoc.getRootElement();
var destinationRange = sheet.getRange(i + 1, 48, 1, 1);
if( null != documentElement )
{
var responseElement = documentElement.getChild("response");
if (null != responseElement)
{
var zestimateElement = responseElement.getChild("zestimate");
if( null != zestimateElement)
{
var amountElement = zestimateElement.getChild("amount");
if( null != amountElement)
{
var rowValue = [];
var cellValue = [];
cellValue.push(amountElement.getText());
}
}
}
}
else
{
cellValue.push("Not Found");
}
rowValue.push(cellValue);
destinationRange.setValues(rowValue);
}
catch(exception)
{
}
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var menuItems = [
{name: 'Get ZEstimate', functionName: 'getZillowEstimates'},
];
spreadsheet.addMenu('Zestimates', menuItems)
};
Today it is working. Yesterday the script was taking 6 minutes to run, today 1.6 seconds. I'm guessing there was a problem with Zillow or with the API.

for each in ss.getSheets() get a range of data

I'm struggling on a child task within a function I'm working on.
For each sheet in sheets, I would like to get the data in range A16:D, combine into one big array and then out put the combined data into a new sheet. But each time I try to select each data range it comes as undefined?
How can I get the data from each sheet in sheets and then add into one big array?
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ranges = [];
function combineData() {
var activeSheetName = ss.getActiveSheet().getName();
var sheets = ss.getSheets();
sheets.forEach(function(e) {
var sheetName = e.getName();
if (sheetName != activeSheetName && sheetName != 'Report Configuration' && sheetName != 'Sheet1')
var wee_data = e.getRange('A16:D').getValues(); // TROUBLE HERE, WEE_DATA IS UNDEFINED
for(var j = 0; j<wee_data.length; j++) {
store.push(wee_data[j]);
}
ranges.push(wee_data);
});
if (ranges.length) {
Logger.log('range length is: ' + ranges.length);
adjustSheetLength(); // ensure there are enough rows in the destination sheet.
// figure out how to output data array "ranges" into a sheet "combined".
}
}
function adjustSheetLength(){
var comb = ss.getSheetByName('combined');
var lastRow = 4;
var maxRows = comb.getLastRow();
comb.deleteRows(lastRow, maxRows-lastRow);
var datapullSize = ranges.length;
comb.insertRows(4, datapullSize-2);// insert exactly the number of rows you need.
}
I think your issue is in the .forEach callback function. When I debugged those functions I got a not allowed in callback exception.
Change the foreach to a for in I think that'll fix your issue.
for( var i in sheets ) {
Logger.log(sheets[i]);
...
}

Can Drive export spreadsheet data to JSON?

Or any other parseable format such as XML. Currently only spreadsheet formats such as Excel, OO seem to be supported.
Can't be done directly, but the following Apps-script will convert a sheet to JSON within the spreadsheet. That JSON sheet can then be exported such that a client app can download it.
/**
* Retrieves all the rows in the active spreadsheet that contain data and logs the
* values for each row.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
NB Sheet 1 must be JSON and it is this sheet which is published as text to the app
Sheet 2 is the Java string version of Sheet 1
*/
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
var jsonOutput="";
/**
* main function
*/
function createJson() {
jsonOutput = "{nEwLiNe";
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var startSheet = 2;
for (var i = startSheet; i < sheets.length; i++) { // foreach sheet (except first two)
if (i > startSheet) {
jsonOutput+=",";
}
doSheet(sheets[i]);
}
jsonOutput += "nEwLiNe}";
Logger.log("nEwLiNenEwLiNe==nEwLiNenEwLiNenEwLiNe"+jsonOutput);
// write the output to A1
SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange("A1").setValue(jsonOutput.replace(/nEwLiNe/g," "));
// write a Java string to B1
var java='jsonS = "'+jsonOutput.replace(/"/g,'\\"').replace(/nEwLiNe/g,' ')+'";';
SpreadsheetApp.getActiveSpreadsheet().getSheets()[1].getRange("A1").setValue(java);
};
/**
* for each sheet
*/
function doSheet(sheet) {
jsonOutput+="nEwLiNe";
jsonOutput+='"'+sheet.getName()+'" : '
var rows = sheet.getDataRange();
var values = rows.getValues();
var rowCount=values.length;
// look for a blank column which is the end of columns to process,ie any extra columns to the right are ignored
var colCount=values[0].length;
for (var c = 0; c < colCount; c++) {
// Logger.log(values[0][c]);
if (values[0][c] == "" || values[0][c] == null) {
colCount=c;
break;
}
}
if (rowCount > 2) {
jsonOutput+="nEwLiNe[";
}
for (var r = 1; r < rowCount; r++) { // for each data row
if (r>1) {
jsonOutput+=',';
}
jsonOutput+='nEwLiNe{nEwLiNe';
for (var c = 0; c < colCount; c++) {
if (c==0) {
jsonOutput+='nEwLiNe';
} else {
jsonOutput+=',nEwLiNe';
}
var n=values[0][c].replace(/^\s+|\s+$/g, "");
var v=(""+values[r][c]).replace(/^\s+|\s+$/g, "");
v=v.replace(/\n/g,"").replace(/\r/g,"");
// Logger.log(sheet.getName()+":"+r+" "+n+":"+v);
jsonOutput+=' "'+n+'" : "'+v+'"'
}
jsonOutput+='nEwLiNe}nEwLiNe';
}
if (rowCount > 2) {
jsonOutput+="nEwLiNe]nEwLiNe";
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Create JSON",
functionName : "createJson"
}];
sheet.addMenu("Tmph", entries);
};
If it is a Google Sheet you can export parseable XML through the Google Sheet API (https://developers.google.com/google-apps/spreadsheets/) using a list based feed or a cell based feed.