How to copy data using Google script, writing to "-nth" column - javascript

I have a script that successfully copies data from one Google Spreadsheet to another. What I'm trying to figure out is how to write the data to say Column 5 and not Column 1. When I alter the script to write the data to Column 5, it processes the data but shows a "cell reference out of range" error.
Here is the code that successfully copies data to Column 1.
'function copy_data() {
var source = SpreadsheetApp.openById('1iQm5NDahmUqXXLDAFvVkrNqooHd2-AAEDVRXndEWXbw').getSheetByName('Account-Category Database');
var target = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet25');
var lastdatarow = source.getLastRow();
var criteria = target.getRange('A1').getValue();
var codedata = source.getRange(3,2,lastdatarow,2).getValues();
var codeout = [];
for (var i=2 in codedata) {
if (codedata[i][0] == criteria || codedata[i][0] == "All") {
codeout.push(codedata[i])
}
}
target.getRange(2,1,codedata.length,codedata[0].length).setValues(codedata).sort(2);
}
PROBLEM:
When I change the bottom of the formula to:
target.getRange(2,5,codedata.length,codedata[0].length).setValues(codedata).sort(2);
}
That's when I get the "Cell reference out of range" error. Again, the data still copies, it just stops the next function from running because of the error.

Turns out I'm just an idiot =) The error with the code was trying to ".sort(2)"... That means I was trying to sort the target sheet by Column 2, when I was writing data to columns 5... thus Column 2 was out of range... Changing it to ".sort(5)" corrected the issue.
Hopes this helps others understand their potential future issue.

Related

Paste the static value in the column besides if the particular cell is empty in google sheets

I might not be able to explain better, but I will try my best. I have two columns say A and B, in column A there are formulas so values in them get changed depending on some other conditions, Now what I want in column B is to paste/setvalue the value for the first time whenever a value appears in column A, so that when there are any further changes in column A, it wouldn't affect the value that is pasted in column B. Although I have tried my best to write the script, it does paste the value but it pastes in all the column and does not care if any cell in column A is empty.
I have gone through a lot of research but could not find an answer. Although OnEdit can work but as the column from which the value is to be got has formulas in it and OnEdit doesn't work on formulas. So once the script is corrected, we can trigger it to time driven.
I just need the help to make this function work correctly, I will be highly thankful for any help. thank you.
function pastevalue(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet1');
var lastrow = ss.getRange("A2:B").getValues().filter(String).length;
var range = ss.getRange(2,1,lastrow);
var pasterange = ss.getRange(2,2,lastrow);
var values = range.getValues().filter(String);
var pastevalues = pasterange.getValues();
for (i=0; i<values.length; i++){
if(pastevalues[i] == ""){
var value = pasterange.setValue(values[i])
}
}
}
I presume that your goal is to grab the numerical value of a formula immediately after you enter it, so that if the displayed value in the cell of the formula changes in the future, you still possess the original value that the formula yielded. The following script accomplishes that:
function onEvent(e){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
if (e.range.getColumn() == 1 && typeof e.oldValue == 'undefined'){
sheet.getRange(e.range.getRow(), 2).setValue(e.range.getValue());
}
}
Note that it is an event trigger, meaning it runs every time the spreadsheet is, well, edited. As the parameter of the function we grab the event that triggered the script (you can read how they are structured here), and then we check for two conditions that both have to be true to copy the value into the B column:
First we check that the column of the cell modified is the A (1st) column.
Then we check that the cell was blank before modification. This will mean that the value will only be copied when a formula is written in a blank cell.

How can I compare Sheet A with Sheet B and add new cells to Sheet B?

first of all I need to say that I do not have any experience in programming. I tried to wrap my head around JavaScript in the course of the last 7 days and although I find the world that opens up through programming really fascinating, I did not get past a very, very rough general understanding.
What I have so far:
I´m currently working on a Google Sheet that automatically imports JSON data out of a list from a webpage. The import of the JSON data works fine und the result is a Google Sheet with 100 cells and 13 columns after the JSON-Import that gets updated every minute through a Timer.
What my problem is:
The list on the webpage I´m scraping my data from contains only 100 cells (never more then 100 cells). So when new data is fed in the list of the webpage, older entries just vanish out of the list and make space for newer entries. This leads to the situation that with every JSON import I do, only the most recent 100 cells will be imported, although I still want to keep the old cells in my Google Sheet that are not shown on the webpage anymore.
Basically I´m looking for a script that extracts the most recent JSON import from my main sheet (Name:"TXs") into a new sheet (Name:Convert). "Convert" should then be constantly compared to "TXs" if new values have been added/scraped. What will happen is that after some time the list of the most recent JSON Imports in "TXs" will contain cells that are not yet updated in "Convert" and cells that vanished/made space in "TXs" that are still present in "Convert".
Webpage Scrapes in "TXs" before cell update on webpage:
Type
Result balance
Column C
ADDRESS D
3947
...
ADDRESS C
9386
...
ADDRESS B
9286
...
ADDRESS A
1837
...
Webpage Scrapes in "TXs" after cell update on webpage:
Type
Result balance
Column C
ADDRESS E
1456
...
ADDRESS D
3947
...
ADDRESS C
9386
...
ADDRESS B
9286
...
While Address E is a new cell that got updated on the page, Address A is now missing and not listed anymore.
Sheet "Convert" however should contain ALL the information, even the Addresses that are not present anymore on the webpage:
Sheet "Convert" after running the script:
Type
Result balance
Column C
ADDRESS E
1456
...
ADDRESS D
3947
...
ADDRESS C
9386
...
ADDRESS B
9286
...
ADDRESS A
1837
...
What I´ve tried so far:
I experimented a bit with the code someone provided here on stackoverflow, however this code does not really work for me. It keeps copying all rows from "TXs" into "Convert" after it detects a change in "TXs".
function updateSheet() {
var ss = SpreadsheetApp.getActive();
var sourceValues = ss.getSheetByName("TXs").getRange("A2:M").getValues().filter(String);
var targetSheet = ss.getSheetByName("Convert");
var targetRange = targetSheet.getRange("A2:M");
var targetColumn = targetRange.getColumn();
var targetRow = targetRange.getRow();
var targetValues = targetRange.getValues().filter(String);
var diff = targetValues.showDif(sourceValues)
targetRange.clearContent();
targetValues = (diff && diff.length) ? targetValues.concat(diff) : targetValues;
targetSheet.getRange(targetRow, targetColumn, targetValues.length, targetValues[0].length).setValues(targetValues);
}
Array.prototype.showDif = function (array) {
var that = this;
return array.filter(function (r) {
return !that.some(function (x) {
return r.join() === x.join();
})
})
}
I hope I explained it more or less understandable. Sorry in case I´ve used wrong terminology at some points, as I said: I´m a total newbie.
Many thanks in advance,
Jan
Here the link to my sheet:
https://docs.google.com/spreadsheets/d/1js11rdG6IWdfps00kuFaWk5VOP_Ve7ltvfdPWKlKVrA/

Copying & Modifying specific values from each Form submit when copying to another sheet

I got a situation where 2 independent parties need access to the same data, but their back-end that uses the data needs a different format, e.g. one party needs to see "Soccer", the other needs to see "1".
This input comes from various users through a Google Form.
I previously ran a time interval script that would copy over all data from sheet 1, then copy it to sheet 2, then a double loop would kick (using var i) in to search all columns and replace specific strings on sheet 2 with a numeric value.
This script worked, but due to it's inefficiency it started to crash once I started to have more data.
So I am trying to reduce the dataset by just handling the data that comes from each individual Form Submit.
I tried 2 different approaches:
1) Grab values to copy, modify values, then copy to new sheet
2) Grab values to copy, copy to new sheet, then modify these new values (lastrow)
I know the copy bit works in both scripts I wrote but my modification does not, when using the debugger it shows me the modified data is same as the original and this is in fact what happens the copy is identical.
I realize I am probably making a very basic mistake, but I am blind as to what it is. Searching for similar threads on Stackoverflow and other sites I did not come to a resolution.
Current code:
function onFormSubmit(e){
var responses = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var projects = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var row = responses.getLastRow();
var col = responses.getLastColumn();
var copy = responses.getRange(row, 1, 1, col)
var modify = copy.getValues();
for (var i=0; i < modify.length; i++){
if (modify [i] == "SearchString1"){
modify [i] = "1";
}
else if (modify [i] == "SearchString2"){
modify [i] = "0";
}
else if (modify [i] == "SearchString3"){
modify [i] = "1";
}
projects.appendRow(modify);
}
}
This code will copy the data, but not modify it.
I had a variation where i used .setvalues but that resulted in the same end result.
Solved, it was all about location identifiers.
The getvalues created a double array and the append was in the loop instead of outside of it. I had to specify the append and modification better.
Fixed code:
for (var i=0; i < modify[0].length; i++){
if (modify[0][i] == "SearchString1"){
modify[0][i] = "1";
}
else if (modify[0][i] == "SearchString2"){
modify[0][i] = "0";
}
else if (modify[0][i] == "SearchString3"){
modify[0][i] = "1";
}
}
projects.appendRow(modify[0]);
}

Pulling JSON into Google Sheet via API resulting in undefined values in cells

I have an issue with one of my API's I am trying to establish an API to call on a Customer Relationship Management tool called Streak, I am attempting to pull data via a HTTP Basic Auth GET which parses a JSON file through my script logic and then into my Google Sheets spreadsheet. The Google App Script after a few hours of development is working flawlessly (for my requirements) par one thing, my script is inserting the string 'undefined' into my google sheet cells whenever it cannot locate a value, a completely empty non existent field.
Image of Google Sheet Output issue can be seen below
Note: I have highlighted both the field property names and undefined values that are causing me grief
https://drive.google.com/file/d/0B4rXaBEqs2UzSU5fMFUxYW8zTm8/view?usp=sharing
The entire Code Snippet that is ran to extrapolate hundreds of records to my Google Sheet can be seen below. From my understanding my problem is within the statement row.push(field 1001 -> 1021), it is always attempting to push all fields to the sheet; however, not all records contain these fields as I may not have populated them within the source CRM. In response to this the script is populating "undefined" strings in the corresponding cells within my Sheet.
I am hoping to prevent this "undefined" string from being populated in the sheet, instead of this the cell should be blank, can someone please advise how I can tweak my code snippet to achieve this? Much appreciated! I have tried for nearly 2-3 hours to work around this issue but I am not experienced enough to find the answer, I have tried various IF statements and looked into defining variable types (i.e. integer, floating, char etc) none of which seem to work. I am sure a solution is simple once you know it, your assistance is greatly appreciated!
//Within this API we need to achieve collecting my data from Streak CRM us
//
// Notes on Google API
// https://developers.google.com/apps-script/guides/services/external
//
// Notes on Streak API
// https://www.streak.com/api/
//
//API Key YOUR_API_KEY Here
function myStreak() {
//Google Sheet Data
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getSheetByName("StreakCRM");
//Streak API Call
var consumerKey = 'YOUR_API_KEY_HERE'
var url = "https://www.streak.com/api/v1/boxes";
var headers = {
"contentType": "application/json",
"headers":{
"User-Agent": "MY_APP_NAME (App URL/your email address)",
"Authorization": "Basic " + Utilities.base64Encode(consumerKey)
},
"validateHttpsCertificates" :false
};
//Fetch Streak Data
var response = UrlFetchApp.fetch(url, headers);
var dataAll = JSON.parse(response.getContentText());
//Write Captured Streak Data to Google Sheet
var dataSet = dataAll;
var rows = [],
data;
for (i = 0; i < dataSet.length; i++) {
data = dataSet[i];
rows.push([data.name,
data.stageKey,
// data.fields['1001'], empty field
data.fields['1002'],
data.fields['1003'],
// data.fields['1004'], empty field
data.fields['1005'],
data.fields['1006'],
data.fields['1007'],
data.fields['1008'],
data.fields['1009'],
data.fields['1010'],
data.fields['1011'],
data.fields['1012'],
// data.fields['1013'], empty field
data.fields['1014'],
data.fields['1015'],
// data.fields['1016'], empty field
data.fields['1017'],
data.fields['1018'],
data.fields['1019'],
// data.fields['1020'], empty field
data.fields['1021'],
data.fields['1023']]);//your JSON entities here
}
dataRange = sheet.getRange(3, 1, rows.length, 19); // 19 Denotes total number of entites
dataRange.setValues(rows);
//Capture response code success or errors
var text = response.getResponseCode();
Logger.log(text);
Logger.log(response);
}
You've already accepted a good answer but if I could offer an alternative modified approach.
//Write Captured Streak Data to Google Sheet
var dataSet = dataAll,
rows = [],
data,
dataFields = ['name', 'stageKey', '1001' … ]; //include all the JSON fields you want to transfer including any deliberate blanks you don't exist.
for (i = 0; i < dataSet.length; i++) {
data = dataSet[i];
rows.push(dataFields.map(function (f) {
return data[f] || '';
});
}
The point here is to control the direct mapping of data fields once at the outset.
At the end of the loop then you'll see another alternative to the ternary if thrown in for good measure.
return data[f] || '';
Which is in the form
var foo = bar || 'default';
|| is the OR you know from if statements. In effect this pattern says "let foo be bar unless it is falsey in which case use 'default'.
This is the expected behaviour, since those properties are missing entirely from a given row of data, they are undefined variables. When you write an undefined variable to a sheet, it is converted into the string "undefined".
To handle this, you should do a check on each property name to make sure it exists, and if it doesn't use a desired default value instead.
You mentioned you tried various If statements. The way to check if a value is specifically undefined is to do:
if(data.fields['somefieldname'] === undefined)
However, usually you just want to know if the value evaluates to false, in which case you can simply do:
if(data.fields['somefieldname'])
Which will evaluate as False if data.fields['somefieldname'] is any value that evaluates to false, such as null, false, 0 or undefined, and true for any other value.
Finally, since if statements are a bit long for this particulay usage, I suggest using the "Conditional Operator" or "Ternary Operator" to handle this in your code:
( (data.fields['1002'])? data.fields['1002'] : '' )
Which can be read as "if data.fields['1002'] is true, return data.fields['1002'], else return empty string"
Here is some documentation on the the Conditional Operator:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
In a snippit of your code, it would look like this:
rows.push([data.name,
data.stageKey,
// data.fields['1001'], empty field
(data.fields['1002'])?data.fields['1002']:'',
(data.fields['1003'])?data.fields['1002']:'',
...
...
]);
You can specify any value for the "else" condition, a 0 instead of an empty string, for example.

Google Docs - spreadsheet loop

This one might be a bit basic and easy to answer, but I've been pulling out my hair for a while now!
I've built the following code - which is semi-pseudo as I can't find the right way to make things work!
var s = "Test";
function onEdit(event)
{
var ss = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if (ss.getName() == s)
{
results = {"Currently On": 0, "Next Up": 0, "On Hold": 0, "Waiting on someone else": 0, "zDone": 0};
last = ss.getMaxRows();
start = ss.getRange("F3:"+last).getValues();
var output = "J11";
for (x=0;x<start.length;x++)
{
results[start[x]]++;
}
for (y=0;y<results.length;y++)
{
row = ss.getRow(output);
row.value = results[y];
output++;
}
}
}
I've got an example of the data in this image
The basic idea is to run through all the possible categories of each task and keep a numeric list on the side of how many of each there are. I'd also like to make it dynamic (so I don't have to hard code in the list of categories) but I'm more interested in just making it work for the moment.
The Google Apps debugger is very frustrating!
Thanks for your help all!
Firstly, this particular use case would be easily achievable with a spreadsheet formula, eg:
=QUERY(A2:F;"select F, count(A) where F != '' group by F label count(A) 'Count'";1)
but there may be a reason why you want to do this with GAS.
So secondly, this is where I think there may be some syntax issues:
last = ss.getMaxRows();
I would just use var last = ss.getLastRow() here.
start = ss.getRange("F3:"+last).getValues();
The range reference would evaluate to something like "F3:100", which is a valid reference in GSheets (don't know about whether GAS can handle it), but nevertheless you really want something like "F3:F100", so I would use var start = ss.getRange("F3:F"+last).getValues();.
results[start[x]]++;
When you create an array from a getValues() call it is a 2D array, so you would need to use results[start[x][0]]++;.
With the next loop and the output variable, I must admit I'm a bit lost with what you're doing there. How did you want your result table laid out?
You have
output = "J11";
And then you do
ss.getRow(output);
output++;
This is invalid.First of all, ss is a Sheet under which there is not getRow method. So, what you should really be doing is something like this
var row = 11 ;
var col = 10 ; //Col J
for (y=0;y<results.length;y++)
{
ss.getRange(row,col,1,1).setValue(results[y]);
row++:
}
Like AdamL, I suggest that this is better handled within the native capability of the spreadsheet. Seems to me that you want a pivot table, which would update dynamically. Alternatively a formula like =countif(F:F,"Currently On" ) would meet your immediate request. =Unique(F:F) will give you the list of categories in an array

Categories

Resources