Copy data from sheet to the last row of another workbook - javascript

I want to copy columns A2:K (or: all data on sheet apart from row 1) to a completely different workbook and paste in the last row every time (this way I can keep running the script and it won't overwrite any previous pasted data).
Here is my code:
function dataLog() {
var ss = SpreadsheetApp.getActive();
var ss = ss.getSheetByName('Data Sheet');
var target = SpreadsheetApp.openById('xxxxxx');
var ss = target.getSheetByName("Copy Of DataInput");
var vs = ss.getRange('A2:K').getValues();
ss.getRange(lastRow + 1,1,vs.length,vs[0].length).setValues(vs);
}
I'm getting an error on line 6:
TypeError: Cannot read properties of null (reading 'getRange') dataLog # Untitled.gs:6

Based on the error, maybe you're trying to access a sheet that doesn't exist and that's why it is returning null. Make sure the sheet names Data Sheet or Copy Of DataInput are spelled correctly and it does exist in your Spreadsheet. Tested the script and made a couple of updates and it works. You can try the following:
function dataLog() {
var ss = SpreadsheetApp.getActive();
var ss = ss.getSheetByName('Data Sheet');
var vs = ss.getRange('A2:K').getValues();
var target = SpreadsheetApp.openById('XXX');
var ss2 = target.getSheetByName('Copy Of DataInput');
ss2.getRange(ss2.getLastRow() + 1,1,vs.length,vs[0].length).setValues(vs);
}

Related

Exception: Document is missing (perhaps it was deleted, or you don't have read access?)

I'm working on a project that take "profiles" stored in a Google Sheet, makes a unique Google Doc for each profile, and then updates the unique Google Doc with any new information when you push a button on the Google Sheet.
I have some other automations built into my original code, but I simplified most of it to what's pertinent to the error I'm getting, which is this:
Exception: Document is missing (perhaps it was deleted, or you don't have read access?
It happens on Line 52 of my script in the fileUpdate funtion. Here's the appropriate line for reference:
var file = DocumentApp.openById(fileName);
And this is the rest of my code:
function manageFiles() {
//Basic setup. Defining the range and retrieving the spreadsheet to store as an array.
var date = new Date();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var array = sheet.getDataRange().getValues();
var arrayL = sheet.getLastRow();
var arrayW = sheet.getLastColumn();
for (var i = 1; i < arrayL; i++) {
if (array[i][arrayW-2] == "") {
//Collect the data from the current sheet.
//Create the document and retrieve some information from it.
var docTitle = array[i , 0]
var doc = DocumentApp.create(docTitle);
var docBody = doc.getBody();
var docLink = doc.getUrl();
//Use a for function to collect the unique data from each cell in the row.
docBody.insertParagraph(0 , "Last Updated: "+date);
for (var j = 2; j <= arrayW; j++) {
var colName = array[0][arrayW-j];
var data = array[i][arrayW-j];
if (colName !== "Filed?") {
docBody.insertParagraph(0 , colName+": "+data);
}
}
//Insert a hyperlink to the file in the cell containing the SID
sheet.getRange(i+1 , 1).setFormula('=HYPERLINK("'+docLink+'", "'+SID+'")');
//Insert a checkbox and check it.
sheet.getRange(i+1 , arrayW-1).insertCheckboxes();
sheet.getRange(i+1 , arrayW-1).setFormula('=TRUE');
}
else if (array[i][arrayW-2] !== "") {
updateFiles(i);
}
}
sheet.getRange(1 , arrayW).setValue('Last Update: '+date);
}
//Note: I hate how cluttered updateFiles is. I'm going to clean it up later.
function fileUpdate(rowNum) {
//now you do the whole thing over again from createFiles()
//Basic setup. Defining the range and retrieving the spreadsheet to store as an array.
var date = new Date();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var array = sheet.getDataRange().getValues();
var arrayL = sheet.getLastRow();
var arrayW = sheet.getLastColumn();
//Collect the data from the current sheet.
var fileName = array[rowNum][0];
var file = DocumentApp.openById(fileName);
//retrieve the body of the document and clear the text, making it blank.
file.getBody().setText("");
//Use a for function to collect the the unique date from every non-blank cell in the row.
file.getBody().insertParagraph(0 , "Last Updated: "+date);
for (var j = 2; j <= arrayW; j++) {
var colName = array[0][arrayW-j];
var data = array[rowNum][arrayW-j];
file.getBody().insertParagraph(0 , colName+": "+data);
}
}
If you'd like to take a look at my sample spreadsheet, you can see it here. I suggest you make a copy though, because you won't have permissions to the Google Docs my script created.
I've looked at some other forums with this same error and tried several of the prescribed solutions (signing out of other Google Accounts, clearing my cookies, completing the URL with a backslash, widening permissions to everyone with the link), but to no avail.
**Note to anyone offended by my janky code or formatting: I'm self-taught, so I do apologize if my work is difficult to read.
The problem (in the updated code attached to your sheet) comes from your URL
Side Note:
In your initial question, you define DocumentApp.openById(fileName);
I assume your realized that this is not correct, since you updated
your code to DocumentApp.openByUrl(docURL);, so I will discuss the
problem of the latter in the following.
The URLs in your sheet are of the form
https://docs.google.com/open?id=1pT5kr7V11TMH0pJea281VhZg_1bOt8YDRrh9thrUV0w
while DocumentApp.openByUrl expects a URL of form
https://docs.google.com/document/d/1pT5kr7V11TMH0pJea281VhZg_1bOt8YDRrh9thrUV0w/
Just adding a / is not enough!
Either create the expected URL manually, or - much easier / use the method DocumentApp.openById(id) instead.
For this, you can extract the id from your URL as following:
var id = docURL.split("https://docs.google.com/open?id=")[1];
var file = DocumentApp.openById(id)

In Google Sheets Apps Script, how to check if a sheet exists, and if it doesn't add one

I am creating a spreadsheet to sort events based on the date inputted. I have successfully gotten the program to add a new sheet with the contents of the event that I want to copy over, but I have not been able to add to the script to allow for two options. My goal is for it to go something like this:
Option 1: The sheet already exists
. A2:D2 cells will be copied from the template sheet to the sheet that is titled the same date as is in cell A2.
. A2:D2 will be cleared from the template sheet as to leave a blank canvas.
Option 2: The sheet does not exist
. Using the template sheet as a template for the new sheet, all the information will be copied over, with the date in A2 as the name of this new sheet.
. A2:D2 will be cleared from the template sheet as to leave a blank canvas.
I have tried to use a try catch statement, trying to find the sheet, and if that doesn't work, the catch creating the sheet with the new name. I get the error "A sheet with the name "____" already exists." though I am confused as to why, since I am receiving this error, it is not going on with the catch.
I have also tried an if else statement with a similar idea, stating that if getSheetByName didn't work, it would create a sheet, or else it would set a new Active Sheet. This one has the same error.
As for my code, I will show it, but I have to warn it's a bit chunky (for whatever reason, it won't acknowledge the variables within the try catch statement unless I restate them).
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
ss.setActiveSheet(ss.getSheets()[0])
var range = sheet.getRange("A2");
var A2 = range.getValue();
var templateSheet = ss.getActiveSheet();
var value = sheet.getRange("A2").getValue();
var val = Utilities.formatDate(new Date(A2), "GMT+1", "MM/dd/yyyy");
range.setValue(new Date(A2)).setNumberFormat("MM/dd/yyyy");
A2 = SpreadsheetApp.getActiveSheet().getRange('A2').getValue();
try {
ss.setActiveSheet(ss.getSheetByName(A2));
var sheet1 = ss.getSheetByName("GUI");
var sheet2 = ss.getSheetByName(A2);
sheet1.getRange("A2:D2").copyTo(sheet2.getRange(sheet2.getLastRow()+1,1,1,4), {contentsOnly:true});
ss.setActiveSheet(ss.getSheets()[0]);
sheet.getRange("A2:D2").clearContent();
} catch (e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var A2 = range.getValue();
var templateSheet = ss.getActiveSheet();
var val = Utilities.formatDate(new Date(A2), "GMT+1", "MM/dd/yyyy");
ss.insertSheet(val, ss.getSheets().length, {template: templateSheet});
ss.setActiveSheet(ss.getSheets()[0]);
sheet.getRange("A2:D2").clearContent();
}
}
If anyone has any ideas why this isn't working, I'd love to know. Thanks!
The function getSheetByName returns null when it doesn't exist a sheet with that name. If you implement the code that way I think It will be easier.
Code would be something like this:
var sheet2 = ss.getSheetByName(A2);
if( ss.getSheetByName(A2) == null)
{
//if returned null means the sheet doesn't exist, so create it
var val = Utilities.formatDate(new Date(A2), "GMT+1", "MM/dd/yyyy");
ss.insertSheet(val, ss.getSheets().length, {template: templateSheet});
sheet2 = ss.insertSheet(A2);
}
//Rest of the behavior...

Importrange to change cells in multiple spreadsheets at once with a script

I want all spreadsheets to update with data i put into a main spreadsheet. I keep getting the following error:
TypeError: Cannot call method "getRange" of null. (line 8, file "Code")
here is line 8: var sourcerange = sourcesheet.getRange('A:A');
I want to put data in WORK sheet and have NUMBER sheet update on different spreadsheets.
function getdata() {
var files = DriveApp.getFolderById("1CXEKiJBHNKk_-aI3lcEcSUSXq98uotVk").getFiles()
while (files.hasNext()) {
var file = files.next();
var shoot = SpreadsheetApp.openById(file.getId());
var sourcesheet = SpreadsheetApp.getActive().getSheetByName('WORK');
var sourcerange = sourcesheet.getRange('A:A');
var sourcevalues = sourcerange.getValues();
var destsheet = shoot.getSheetByName('NUMBER');
var destrange = destsheet.getRange('A:A');
destrange.setValues(sourcevalues);
}
}
It's very likely that the error occurs because there isn't a sheet named WORK or NUMBER. Please bear in mind that the Google Apps Script methods are case sensitive.

Google Scripts - Function Error with Time Trigger

This function/trigger combo is intended to keep a log of live data on a daily basis. The intent is that N2:P2 get pasted as values at the bottom of Columns C:E.
pullvalue() works fine if I run it manually.
HERE'S THE ISSUE: Setting up a time-driven trigger causes the values to be pasted in at C1:E1 instead of at the bottom of the columns.
My suspicion is that target_range is breaking down when Clast returns a zero value, but I can't figure out why.
What am I missing? Thanks for your help/feedback!
function pullvalue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.getActiveSpreadsheet();
var source_sheet = ss.getSheetByName("Production");
var target_sheet = target.getSheetByName("Production");
var source_range = source_sheet.getRange("N2:P2");
var Cvals = ss.getRange("C1:C").getValues();
var Clast = Cvals.filter(String).length;
var target_range = target_sheet.getRange("C"+(Clast+1)+":E"+(Clast+1))
source_range.copyTo(target_range, {contentsOnly:true});}
Please verify this line:
var Cvals = ss.getRange("C1:C").getValues();
variable ss return currently activespreadsheet only, but when it runs from a time-driven trigger there is no active sheet, so you need to indicate the sheet, you can use getSheetByName() or getSheets() the line should look like this:
var sheet = ss.getSheetByName("Sheet1");
var Cvals = sheet.getRange("C1:C").getValues();
Hope this will help you.
Thanks.

How to script the addition of a row in one sheet when the source sheet has a row added?

I have a google form which populates a google spreadsheet (source sheet). I located and customized a script to pull certain columns -in their entirety- from the source sheet into a new tab/sheet. Apparently there has to be the same number of rows in both sheets for the script to run properly. If not, it turns back an error. Every time a new form is submitted, a row is added to the source sheet, putting the two sheets out of sync and breaking the script.
I'd like help figuring out what function I need to add to the existing script (or what changes I can make to it) so when a new row appears in the source sheet (because a form has been submitted), a blank row appears in the target sheet.
Do I need to tweak my script or add a new function?
function importFunction(a) {
var ss = SpreadsheetApp.openById("0ApTaY3v27-UqdElwZTBvanNpaC1UckpxaTJRZS1XNWc");
var sourceSheet = ss.getSheets()[0];
var ss2 = SpreadsheetApp.openById("0ApTaY3v27-UqdElwZTBvanNpaC1UckpxaTJRZS1XNWc");
var targetSheet = ss2.getSheets()[1];
var values1 = sourceSheet.setActiveSelection("C:C").getValues();
var values2 = sourceSheet.setActiveSelection("AD:AD").getValues();
var values3 = sourceSheet.setActiveSelection("D:E").getValues();
var values4 = sourceSheet.setActiveSelection("AE:AE").getValues();
var values5 = sourceSheet.setActiveSelection("F:H").getValues();
var values6 = sourceSheet.setActiveSelection("N:U").getValues();
targetSheet.setActiveSelection("A:A").setValues(values1);
targetSheet.setActiveSelection("B:B").setValues(values2);
targetSheet.setActiveSelection("C:D").setValues(values3);
targetSheet.setActiveSelection("E:E").setValues(values4);
targetSheet.setActiveSelection("F:H").setValues(values5);
targetSheet.setActiveSelection("I:P").setValues(values6);
}
Per the suggestion below, I tried to change script to the following, but I get an error - Cannot find method appendRow(). How do I fix that?
function importFunction(a) {
var ss = SpreadsheetApp.openById("0ApTaY3v27-UqdElwZTBvanNpaC1UckpxaTJRZS1XNWc");
var sourceSheet = ss.getSheets()[0];
var ss2 = SpreadsheetApp.openById("0ApTaY3v27-UqdElwZTBvanNpaC1UckpxaTJRZS1XNWc");
var targetSheet = ss2.getSheets()[1];
var targetMax = targetSheet.getMaxRows();
var values1 = sourceSheet.setActiveSelection("C:C").getValues();
var values2 = sourceSheet.setActiveSelection("AD:AD").getValues();
var values3 = sourceSheet.setActiveSelection("D:E").getValues();
var values4 = sourceSheet.setActiveSelection("AE:AE").getValues();
var values5 = sourceSheet.setActiveSelection("F:H").getValues();
var values6 = sourceSheet.setActiveSelection("N:U").getValues();
if(targetMax == values1.length) {
targetSheet.setActiveSelection("A:A").setValues(values1);
targetSheet.setActiveSelection("B:B").setValues(values2);
targetSheet.setActiveSelection("C:D").setValues(values3);
targetSheet.setActiveSelection("E:E").setValues(values4);
targetSheet.setActiveSelection("F:H").setValues(values5);
targetSheet.setActiveSelection("I:P").setValues(values6);
}
else
targetSheet.appendRow();
}
You could simply check the number of available rows in sheet SS2 before writing the values using getMaxRows() and compare it to the length of your data arrays value1.length, then, depending on this comparison add the rows you need using appendRow() eventually in a for next loop.
EDIT : following your EDIT, I tested a bit further and it appears that appendRow() doesn't work as I thought, it appends Rows at the begining of an empty sheet... so I tried this :
if(targetMax < values1.length) {
var RowsToAdd = values1.length-targetMax
for(nn=0;nn<RowsToAdd;++nn){targetSheet.insertRowAfter(targetMax)}
}
Just place it right after var value6=...
sorry for this little error ;-)

Categories

Resources