How do I extract data from certain columns in AppScript? - javascript

I am trying to fecth some data from a google spreadsheet in an AppScript standalone file.
I tried with this piece of code, but it is definitely incomplete. It raises this error:
TypeError: Cannot read property 'getDataRange' of undefined
My function:
var sheet=SpreadsheetApp.openById('1n2a5iecKo7seMXcef81V_pxWSRjE4agQ9DSoROtf0').getSheets()[0]
function getColumnId(sheet, namecol) {
var data = sheet.getDataRange().getValues();
var col = data[0].findIndex((name) => name === namecol) + 1;
return col;
}
After extracting the column data, I want to store that data in a normal list:
var IDCol=getcolumnId(sheet, 'ID')
var AFCol=getcolumnId(sheet, 'AF')
Is that possible in this way? I'd do debugging but I do not know how to proceed first with my function.

I believe your goal is as follows.
You want to retrieve the values from a column using the function getColumnId(sheet, namecol).
Modification points:
Your function name is getColumnId. But you are trying to call the function with getcolumnId. I think that an error occurs.
var sheet=DriveApp.getFileById('1n2a5ieOMcKo7seMXcef81V_pxWSRjE4agQ9DSoROtf0').getBlob() is Blob. In your script, an error occurs at var data = sheet.getDataRange().getValues().
In order to retrieve the values from the column, I think that it is required to retrieve the values using the value of col. For this
Modified script:
function getColumnId(sheet, namecol) {
var data = sheet.getDataRange().getValues();
var col = data[0].findIndex((name) => name === namecol);
var transpose = data[0].map((_, c) => data.map(r => r[c])); // Here, "data" is transposed.
return transpose[col];
}
// Please run this function.
function sample() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set the sheet name.
var IDCol = getColumnId(sheet, 'ID')
var AFCol = getColumnId(sheet, 'AF')
console.log(IDCol)
console.log(AFCol)
}
When this modified script is run, the values of columns with the header values of ID and AF.
Reference:
map()
Added:
From your following replying and your updated question,
Hi Tanaike, I will definitely use your approach mapping the values as you said. But first of all I need to read the data from gsheet properly. Please see my Edit and the error is raised. My code is not place in the google spreadsheet itself but in a StandAlone file in AppsScript
I tried with this piece of code, but it is definitely incomplete. It raises this error:
TypeError: Cannot read property 'getDataRange' of undefined
If you are trying to directly execute the function getColumnId(sheet, namecol) by the script editor, such an error occurs, because sheet is undefined. I thought that this might be the reason for your current issue. From this situation, I thought that you might want to use sheet, IDCol and AFCol as the global variable. If my understanding is correct, how about the following sample script?
Sample script:
var sheet = SpreadsheetApp.openById('###').getSheets()[0];
function getColumnId(sheet, namecol) {
var data = sheet.getDataRange().getValues();
var col = data[0].findIndex((name) => name === namecol);
var transpose = data[0].map((_, c) => data.map(r => r[c]));
return transpose[col];
}
var IDCol = getColumnId(sheet, 'ID')
var AFCol = getColumnId(sheet, 'AF')
// Please run this function.
function myFunction() {
console.log(IDCol)
console.log(AFCol)
}
In this function, when myFunction is run, you can see the values at the log.

Related

How to count all non-blank cells using Excel Javascript Addins?

I'm creating an office js addin that inserts data from the bottom of Table 1 into Table 2 but I am unable to find a method of doing this that works.
I have tried using Excel.Functions.countA() but I can't seem to get a value other than NaN out of it. Here is the code I'm using:
async function run() {
try {
await Excel.run(async context => {
var sheet1Name = "Sheet1";
var sheet1RangeAddress = "B:B";
var sheet2Name = "Sheet2";
var sheet2RangeAddress = "A2:P2";
var sheet2Range = context.workbook.worksheets.getItem(sheet2Name).getRange(sheet2RangeAddress);
sheet2Range.insert("Down");
var sheet1CellAddress = context.workbook.worksheets.getItem(sheet1Name).getRange(sheet1RangeAddress).load("address");
var sheet1RangeLength = Number(context.workbook.functions.countA(sheet1CellAddress));
var sheet1LastCell = context.workbook.worksheets.getItem(sheet1Name).getRangeByIndexes(3,1,sheet1RangeLength,1).getLastCell();
var sheet2Cell = context.workbook.worksheets.getItem(sheet2Name).getRange("A2");
sheet2Cell.values = [[ context.workbook.worksheets.getItem(sheet2Name).getRange("A2").copyFrom(sheet1LastCell) ]]
await context.sync();
});
} catch (error) {
console.error(error);
}
}
I can't find anything useful in Microsoft's documentation or a working example online. Does anyone know what I'm doing wrong?
This line in your code looks problematic:
var sheet1RangeLength = Number(context.workbook.functions.countA(sheet1CellAddress));
The Functions.countA method returns an Excel.FunctionResult object which I don't think can be cast to a Number. The count returned by the function will be in the value property of the returned object. You need to load that value to read it. Try these two lines as a replacement:
var sheet1RangeLength = context.workbook.functions.countA(sheet1CellAddress).load("value");
await context.sync();
BTW, the following line is returning a Range object, not an address. That's OK because countA accepts a Range object parameter, but your variable is misleadingly named. Also, I don't think the load("address") on the end is serving any purpose.
var sheet1CellAddress = context.workbook.worksheets.getItem(sheet1Name).getRange(sheet1RangeAddress).load("address");
If you haven't already, please see this article: Call built-in Excel worksheet functions.

How to fix 'TypeError: Cannot call method "getMessages" of undefined.'

I just joined a company and I'm having issues with a script written by someone who no longer works here. I keep receiving a TypeError. I'm also new to this code.
I've gone through some other threads and didn't see anything related to this particular TypeError.
function csatGmailPull() {
var threads = GmailApp.search("label: name");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.openById("SheetID").getSheetByName('Import');
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
var labelOld = GmailApp.getUserLabelByName("LabelName");
var labelNew = GmailApp.getUserLabelByName("LabelName2");
threads[0].addLabel(labelNew);
threads[0].removeLabel(labelOld);
}
}
I've removed the sheet ID and label names. But this code is supposed to open up Gmail, get the emails under the label identified in the GmailApp.search, load the data into a preset Google Spreadsheet, and then tag the message with a new label. However, I keep getting "TypeError: Cannot call method "getMessages" of undefined." when I test it. Any help would be appreciated!

Issue with pulling JSON data in SuiteScript - NetSuite

I am trying to see if a value in the "apply" sublist for customer payment data has changed and do some action based on it.
My SuiteScript is as follows:
define(['N/record', 'N/https'],
function(record,https)
{
function afterSubmit(context)
{
var oldRec = context.oldRecord;
log.debug({title: 'oldRec ', details: oldRec });
// This log shows that the JSON has an
// attribute called sublists which contains "apply" which has all the applied payments
// eg: {"id":"1234", "type":"customerpayment", "fields":{all the fields},
// "sublists": {"apply" : {"line 1"...}}}
var oldRecSublists = oldRec.sublists;
log.debug({title: 'oldRecApply ', details: oldRecSublists });
// This returns empty or null though there is data
What am I doing wrong here?
Basically what I am trying to achieve is compare the context.oldRecord.sublists.apply and context.newRecord.sublists.apply to find if the amt has changed or not.
Is there a better way to do this is SuiteScript 2.0?
Thanks in advance!
Part of what is going on there is that it looks like you are trying to spelunk the NS data structure by what you see in the print statement. You are not using the NS api at all.
When you send the NS object to the log function I believe it goes through a custom JSON.stringify process so if you want to just inspect values you can do:
var oldRecObj = JSON.parse(JSON.stringify(oldRec));
now oldRecObj can be inspected as though it were a simple object. But you won't be able to manipulate it at all.
You should be using the NS schema browser
and referring to the help docs for operations on N/record
A snippet I often use for dealing with sublists is:
function iter(rec, listName, cb){
var lim = rec.getLineCount({sublistId:listName});
var i = 0;
var getV = function (fld){
return rec.getSublistValue({sublistId:listName, fieldId:fld, line:i});
};
var setV = function(fld, val){
rec.setSublistValue({sublistId:listName, fieldId:fld, line:i, value:val});
};
for(; i< lim; i++){
cb(i, getV, setV);
}
}
and then
iter(oldRec, 'apply', function(idx, getV, setV){
var oldApplied = getV('applied');
});

Cannot read property 'map' of undefined - Google chart

I have problem with google chart. I get error in console:
overview-statistic-chart-ctrl.js:102 Uncaught (in promise) TypeError: Cannot read property 'map' of undefined at callback (overview-statistic-chart-ctrl.js:102) at loader.js:242
When I refresh or click on some other link and go back to the same link it's work great. But I get this error only when I first time load page.
This is my code:
google.charts.load('current', {
callback: function () {
var teamNames = $scope.teams.map(team => team.team_name);
var days = $scope.teams.map(team => team.date_activity);
var avgMaxHRLastDays = $scope.teams.map(team => team.avgMaxHRLastDays);
var days = $scope.teams.map(team => team.date_activity);
var withDates = avgMaxHRLastDays.map(data => data);
var newArray = matrixTranspose(withDates);
var dataChart = newArray.map(data => [''].concat(data));
console.log("dataChart ", dataChart);
var filled = dataChart.map(data => fillWithZeros(data, $scope.teams.length));
var dataToVisualize = [
["Teams"].concat(teamNames),
].concat(filled);
var data = new google.visualization.arrayToDataTable(dataToVisualize);
var chart = new google.visualization.LineChart(document.getElementById('heartOverviewChart'));
chart.draw(data, optionsDesktop);
},
packages: ['corechart']
});
Thank you for help!
Your $scope.teams seem to not be set properly (this will default the 'teams' property to undefined) So when you are trying to map over the expected 'teams' array you see the error.
Make sure your $scope and the properties in $scope (here $scope.teams) are set properly before you try accessing them in the callback function.
Maybe a couple of log statements or debugging it with a couple of break points might help.
When I refresh or click on some other link and go back to the same link it's work great.
this might happen because by the time you perform those "other" operations the $scope.teams might have the expected value or maybe those "other" operations are setting the $scope.teams value.

Google Script not Appending Spreadsheet

I'm trying to write a little script to make my coworkers and mine lives easier. I am trying to append lines to a spreadsheet based on information entered into a custom form. The code posted below just the doPost block which should be appending the google spreadsheet.
function doPost(form) {
var PN = form.PartNumber;
var REV = form.Revision;
var DATE = form.RevisionDate;
var DESC = form.Description;
var NOTE = form.PartNotes;
var URL = form.myFile.getURL();
var ss = SpreadsheetApp.openById("ID HERE"); // removed ID for sake of safety (let me be paranoid)
var sheet = ss.getSheetName('Uploads');
sheet.appendRow([PN,REV,DATE,DESC,NOTE,URL]);
}
I am unsure why it isn't writing to the spreadsheet but it isn't throwing me any errors. If you can offer any insight as to what is wrong I would greatly appreciate it; there are many guides online but most seem to be based on deprecated functions/code/etc.
Thanks for your time.
Instead of using doPost, set up a "On form submit" trigger.
You need to get the namedValues to be able to pull specific values and take the first output.
Also, it should be "getSheetByName('Uploads')" .
As pointed out in the previous answer, it is unclear what you are trying to achieve by "form.myFile.getURL();" If you want to get the form url you might as well create it as a string, as it always stays the same.
Here is a working example of your code:
function doPost(form) {
var formResponses = form.namedValues;
var PN = formResponses.PartNumber[0];
var REV = formResponses.Revision[0];
var DATE = formResponses.RevisionDate[0];
var DESC = formResponses.Description[0];
var NOTE = formResponses.PartNotes[0];
//var URL = form.myFile.getURL(); //Not sure what you are tyring to get here as form URL will always be the same.
var URL = "Your form's url"; //You can put the form url in here so it will be pushed in to every row.
var ss = SpreadsheetApp.openById("ID HERE"); // removed ID for sake of safety (let me be paranoid)
var sheet = ss.getSheetByName('Uploads');
sheet.appendRow([PN,REV,DATE,DESC,NOTE,URL]);
}
The form fields are nested in a "parameter" property in the doPost parameter.
So, you should access them using:
function doPost(form) {
var actualForm = form.parameter;
var PN = actualForm.PartNumber;
//etc
To double check all parameters your receiving and their names, you could append to your sheet everything stringfied, like this:
sheet.appendRow([JSON.stringify(form)]);
--edit
This form.myFile.getURL() also looks odd. I guess another good debugging trick you could do is to wrap everything in a try-catch and email yourself any errors you get. For example:
function doPost(form) {
try {
//all your code
} catch(err) {
MailApp.sendMail('yourself#etc', 'doPost error', err+'\n\n'+JSON.stringify(form));
}
}
On form submit
onFormSubmit works. "doPost" looks wrong.
Simple example:
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for(var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("SendGoogleForm")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
}
function SendGoogleForm(e)
{
try
{
Full example - Scroll down to the code http://www.labnol.org/internet/google-docs-email-form/20884/ (Note: example sends email)
Trigger docs: https://developers.google.com/apps-script/guides/triggers/events
Notes: I think the problem is doPost, Does it work with google Forms? Never seen it used with google forms.
First and foremost, thank you everyone who has responded with information thus far. None of the solutions posted here worked for my particular implementation (my implementation is probably to blame, it is very crude), but they definitely set me down the path to a working version of my form which we now lightly use. I have posted some of the code below:
function sheetFill(form, link) {
try {
var formResponses = form.namedValues;
var toForm = [0,0,0,0,0,0,0];
for (i=0;i < form.PartNumber.length;i++){
toForm[0] = toForm[0]+form.PartNumber[i];
}
... (several for loops later)
var d = new Date();
var ss = SpreadsheetApp.openById("IDHERE");
var sheet = ss.getCurrentSheet;
ss.appendRow([toForm[0], toForm[1], toForm[2], toForm[3], toForm[4], toForm[5], toForm[6], link, d]);
} catch(err) {
MailApp.sendEmail('EMAIL', 'doPost error', err+'\n\n'+JSON.stringify(form));
}
}
It is not very versatile or robust and isn't elegant, but it is a starting point.

Categories

Resources