Moving rows to another google spreadsheet based on a condition - google-apps-script

I'd like to know if its possible to move automatically rows to another Google spreadsheet based on a condition in editing (onEdit) the specific column entry that can be text, date, null or specific number.
I tried many times without being able to solve this puzzle.
Source (shared):
https://docs.google.com/spreadsheets/d/1Of4NUdvcxvCUWNSwpbkC4X8nqHpBetHCvyyiGqUPaJk/edit?usp=sharing
Destination (scripts) (shared):
https://docs.google.com/spreadsheets/d/1J7ChXoodQNg47LOrnp_GF-KLR1jKHxdDGmfAErVTP_U/edit?usp=sharing
Any help is appreciated. vagner

I'm getting an error on line 10 of your code:
This is what your current code looks like:
function onEdit(){
Logger.log("it ran!");
var ss = SpreadsheetApp.openById("1Of4NUdvcxvCUWNSwpbkC4X8nqHpBetHCvyyiGqUPaJk").getActiveSheet();
var ssd = SpreadsheetApp.openById("1J7ChXoodQNg47LOrnp_GF-KLR1jKHxdDGmfAErVTP_U").getActiveSheet();
Logger.log("ss: " + ss);
Logger.log("ssd: " + ssd);
var sheet1 = ss.getSheetByName('Source');
var sheet2 = ssd.getSheetByName('Destination');
Logger.log("sheet1: " + sheet1);
Logger.log("sheet2: " + sheet2);
There is a problem with these two lines:
var ss = SpreadsheetApp.openById("1Of4NUdvcxvCUWNSwpbkC4X8nqHpBetHCvyyiGqUPaJk").getActiveSheet();
var ssd = SpreadsheetApp.openById("1J7ChXoodQNg47LOrnp_GF-KLR1jKHxdDGmfAErVTP_U").getActiveSheet();
You should remove .getActiveSheet().
var ss = SpreadsheetApp.openById("1Of4NUdvcxvCUWNSwpbkC4X8nqHpBetHCvyyiGqUPaJk");
var ssd = SpreadsheetApp.openById("1J7ChXoodQNg47LOrnp_GF-KLR1jKHxdDGmfAErVTP_U");
That error was not showing up until I ran the code from inside of the code editor. And I needed to authorize some things for it to run for the first time.
I ran it in Debug mode.
When you chain the .getActiveSheet() method on the end, it returns the SHEET class, NOT the SPREADSHEET class. There are hierarchies of classes. The SHEET class is a lower level under the SPREADSHEET class. So, you were trying to use a method for the SPREADSHEET class, on a variable that contained a SHEET return type.

Related

Inserting variable data into an existing Google Sheet in Google Scripts

I'm building a script that will ultimately take data from a csv file, populate a spreadsheet, use that spreadsheet to autofill a number of documents, and then automatically e-mail those documents to customers. It's also moving the documents from each time the script runs to a new folder with just that day's reports. I'm pretty new to Google Scripts, and this has been my learning project.
The steps I've got to work so far is the creation of documents for the spreadsheet with dummy data.
I ended up creating a second script to send e-mails which sends e-mails, but it is set up to look for all documents in the folder that are google docs, so it send a copy of every document to each customer. I thought that if I pointed the e-mail back to the original spreadsheet to grab just the correct document IDs (instead of the type) , I could only send customers the reports that belonged to them (all in PDF form). The step of creating a new folder and moving the documents into it afterwards works fine.
What I'm having an issue with is inputting data into my document ID column in the original spreadsheet. I have been able to watch it put the document ID of the first document into every row that has info to iterate over in the column, and then replace every row again with the second document's ID, etc.
I looked for ways to add data to a spreadsheet. Every method I've found so far involves creating a new column or row with new information from data within the spreadsheet. I need to put in data that I'm just now creating outside of the spreadsheet and then put it in the right place so I can point to it later.
I've gone over the methods within the documentation. It looks like .getCell.setvalue(variable) should work...if I could find a way to get the cell from the range (Which keeps showing me out of range).
function createDocument() {
var headers = Sheets.Spreadsheets.Values.get('17jXy9IlLt8C41tWEG5iQR31GjzOftlJs73y2L_0ZWNM', 'A1:P1');
var tactics = Sheets.Spreadsheets.Values.get('17jXy9IlLt8C41tWEG5iQR31GjzOftlJs73y2L_0ZWNM', 'A2:P');
var templateId = '1DU13OJHWyYnO5mLFovm97pWwXuU7ZTTDVJb2Mpdeebk';
for(var i = 0; i < tactics.values.length; i++){
var customer = tactics.values[i][0];
var pcname = tactics.values[i][1];
var date = tactics.values[i][2];
var virusvalue = tactics.values[i][3];
var cpuuse = tactics.values[i][4];
var ramuse = tactics.values[i][5];
var harddrive = tactics.values[i][6];
var netuse = tactics.values[i][7];
var downtime = tactics.values[i][8];
var cpuperform = tactics.values[i][9];
var ramperform = tactics.values[i][10];
var harddiskperform = tactics.values[i][11];
var reccomend = tactics.values[i][13];
var custID = tactics.values[i][14];
var newdoc = tactics.values[i][15];
//Make a copy of the template file
var documentID = DriveApp.getFileById(templateId).makeCopy(DriveApp.getFolderById('1zV-WpzUKoRurE9FnBcfjBygBA5rCO67I')).getId();
//rename the copied file
DriveApp.getFileById(documentID).setName('MCHA ' + customer + ' - ' + pcname);
Logger.log('value1 ' + documentID);
//THIS IS THE AREA I'M TRYING TO FIX
var ss = SpreadsheetApp.openById('113aqWVAjjUYCmI2oFc_BTbXkWMPFPjk_SschsKEx6qU');
var cell = ss.getRange('P2:P').getCell([i], [15]);
cell.setValue(documentID);
SpreadsheetApp.flush();
Logger.log('value2 ' + documentID);
//This area has code to replace the tags in the document with values from the spreadsheet. I cut it for not being relevant.
}
}
Obviously defining the range is just going to fill and autofill each cell. That code worked when I tried it
I originally tried using the variable from my earlier list for the autofill, but I've since realized that shouldn't work at all.
I tried to set the range of cells and then set the current cell by the same notation ([i][15] etc.) which throws an 'Range not found' error. I feel like I must be missing some syntax.
A link to the folder with all the documents is below, if that helps.
https://drive.google.com/drive/folders/1sRhti3R8R-Cym0hr2S4XkAVn3wyBbSRu?usp=sharing
I may not have entirely understood the problem you are facing. But I can see the cause of the 'Range not found' error.
Your loop starts with a value of 0 for i. This causes the script to look for a range called P0 in the first iteration.
One way to avoid that is to try :
var cell = ss.getRange("P"+(i+1));
For code efficiency, I'd also suggest moving some of the code outside the loop. For example, the following line runs each time in the loop. But it could be defined once outside the loop and then the variable ss could be reused inside the loop.
var ss = SpreadsheetApp.openById('113aqWVAjjUYCmI2oFc_BTbXkWMPFPjk_SschsKEx6qU');
Similarly, you could define the template file outside the loop and then sue it inside to make copies:
var templateFile = DriveApp.getFileById(templateId); // Outside the loop
And then inside the loop:
var documentID = templateFile.makeCopy(DriveApp.getFolderById('1zV-WpzUKoRurE9FnBcfjBygBA5rCO67I')).getId();
Google apps script best practices suggests minimising calls to the spreadsheet, i.e. get the data in one call, process it, and then post the data to the sheet in one call. More here.
Hope this helps.

Google Sheets Macro not completing

I'm trying to parse a CSV file using Google Sheets macros. I've recorded all the steps as individual macros, and one by one they work fine, but when I combine into one macro, it doesn't run properly. The point at which it stops working is after the PODdateformatting part has completed and it's run through the first three lines of Daystodeliverformula. Cell H2 is populated with the formula, but the formula doesn't then autofill down the rest of the column. Any ideas? Or indeed, am I going about this all wrong and need a good talking to? :-)
function TheWholeShebang() {
var spreadsheet = SpreadsheetApp.getActive(); // start of DeletedUnwantedColumns
spreadsheet.getRange('AA:DE').activate();
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('W:X').activate();
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('R:U').activate();
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('H:P').activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('P1'));
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('A:E').activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('E1'));
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns()); // end of DeletedUnwantedColumns
var spreadsheet = SpreadsheetApp.getActive(); // start of Addcolumnsandheaderlabels
spreadsheet.getRange('A:F').activate();
spreadsheet.getActiveSheet().insertColumnsAfter(spreadsheet.getActiveRange().getLastColumn(), 6);
spreadsheet.getActiveRange().offset(0, spreadsheet.getActiveRange().getNumColumns(), spreadsheet.getActiveRange().getNumRows(), 6).activate();
spreadsheet.getRange('G1').activate();
spreadsheet.getCurrentCell().setValue('POD Date (formatted)');
spreadsheet.getRange('H1').activate();
spreadsheet.getCurrentCell().setValue('Days to Deliver');
spreadsheet.getRange('G2').activate(); // end of Addcolumnsandheaderlabels
var spreadsheet = SpreadsheetApp.getActive(); // start of PODdateformatting
spreadsheet.getRange('G2').activate()
.setFormula('=DATE(LEFT(D2,4),mid(D2,5,2),right(D2,2))');
spreadsheet.getActiveRange().autoFillToNeighbor(SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES); // end of PODdateformatting
var spreadsheet = SpreadsheetApp.getActive(); //start of Daystodeliverformula
spreadsheet.getRange('H2').activate()
.setFormula('=NETWORKDAYS(E2,G2,Instructions!$B$15:$B$40)-1');
spreadsheet.getActiveRange().autoFillToNeighbor(SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES); // end of Daystodeliverformula
};
After messing about with range.autoFillToNeighbor() and failing (see comments above) I was still suspicious about that method.
When I used this the range.autoFill() method instead it all worked fine. See code below.
// start of PODdateformatting
//var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('G2').activate().setFormula('=DATE(LEFT(D2,4),mid(D2,5,2),right(D2,2))');
var sourceRange = spreadsheet.getRange("G2:G2");
var destination = spreadsheet.getRange("G2:G369");
sourceRange.autoFill(destination,SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
//start of Daystodeliverformula
var spreadsheet = SpreadsheetApp.getActive();
var range = spreadsheet.getRange('H2').activate().setFormula('=NETWORKDAYS(E2,G2,Instructions!$B$15:$B$40)-1');
var sourceRange = spreadsheet.getRange("H2:H2");
var destination = spreadsheet.getRange("H2:H369");
sourceRange.autoFill(destination,SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
In hindsight I now believe that range.autoFillToNeighbor() was never right for your use case in the first place!
range.autoFillToNeighbor() expects to build autofill formulas based on data that is contained in neighbouring columns. It tries to do this intelligently, but neighbouring columns do not contain anything useful! Its amazing it ever worked... maybe sometimes defaulting to range.autoFill()!
range.autoFill() on the other hand, just duplicates the formula (data) above or below ( NOT looking to neighbouring cells for help).
You can copy and paste these over the corresponding functions in function TheWholeShebang() and should all work.
Note I assume a fixed range of 369 as per your data, but you can calculate this based on actual size if you prefer, in case no of rows is changed.

Copy Paste Script Google Sheets

I work for a major Motor Manufacturer and I need some help with a google sheets script that I need to write (I assume a script is the way forward?)
I have a google sheets file that is used to monitor issues and planned improvements for multiple departments. The workbook has multiple tabs that I need to somehow copy and paste data around within it.
I have included a sample file to try and help explain it, it's quite a complicated file to try and explain...I will do my best. It sounds like I need to use a script but I am new to using scripts.
Link to Sheet
Explanation of file:
On a weekly basis I update the sheet with latest data into the "Master data" sheet, this sheet feeds the "electrical" sheet using a query.The dept owner for electrical updates updates the "electricalinput" sheet with his actions and timing and this feeds into the "electrical" sheet also. The "electrical" sheet in turn feeds the "improvement data" sheet which feeds the chart.
It is arranged like this so what when new issues are added and the order changes the comments follow on the "electrical" sheet, and the owner only needs to update the "electricalinput" sheet with comments that he hasn't already done.
What I would like try and do:
I would like to be able to run a script that filters or extracts anything in the electrical sheet with #N/A against it (which means the 3 cell combination hasn't been found in the input sheet) and copy and paste just those items into the "electricalinput" sheet at the next available line that isn't populated. In the actual file there are multiple depts so variations of the script will have to run to cover the different depts.
I've updated the spreadsheet that you shared with relevant code.
You can run the script via Add Ons->Master Data Utils->Clean Up Keys menu. The menu was created in the OnOpen function from this script.
Note that there are a couple of requirements as below for the script to work.(already taken care of in the shared ss)
Departments lists and details helpful for processing all the data as shown below.
There should be a NamedRange called Department_List which would be top left cell of the table shown above.
Column to Clean -> Action Summary
is the column we would be using to search of #N/A
Display Sheet Name -> Electrical
is where the #N/A would be.
Input Sheet Name -> Electricalinput
is the sheet name that would be updated.
Copy Cols From(Disp) -> B:D
the columns that would be copied over
Similar to d but this is where sata would be copied to
But at the moment the code doesn't use this and just pastes into first available cell in col B
Here's the code I attempted, let me know of any suggestions or alterations that would make it easier to use.
function cleanComponentList(curSS) {
Logger.log("Init script cleanComponentList 'Department_List'")
curSS = curSS || SpreadsheetApp.getActiveSpreadsheet()
var deptListStart = curSS.getRangeByName("Department_List")
if(deptListStart==null){
Logger.log("This script cannot be used without the named range 'Department_List'")
return
}
var dept = deptListStart.offset(1,0)
while( ! dept.isBlank() ){
Logger.log("Started processing " + dept.getDisplayValue() + " Dept.")
//Get Department Sheet
var deptSht = curSS.getSheetByName(dept.offset(0,1).getValue())
//Get Column that has Action Summary in department sheet
var actSummCol=deptSht.getRange(2, 1)
//Get Department Input Sheet (Target Sheet where we need to copy the final values to
var deptInputSht = curSS.getSheetByName(dept.offset(0,2).getValue())
//Find column with the "Column Header"/"Summary" in which we search #N/A
while( ! (actSummCol.getDisplayValue() === dept.offset(0,3).getDisplayValue())){
var tmp = actSummCol.getDisplayValue()
var actColRng = actSummCol.getA1Notation()
actSummCol=actSummCol.offset(0,1)
}
var actSummColAddress = actSummCol.getA1Notation();
Logger.log("Found key \"" + dept.offset(0,3).getDisplayValue() + "\" for " + dept.getDisplayValue() + " # " + actSummColAddress)
var errRows = []
//Get all rows that have error Action Summary
var lastRow = deptSht.getLastRow()
for(nRow=1;nRow<lastRow;nRow++){
//There should be a better of checking #N/A
if(actSummCol.offset(nRow,0).getDisplayValue().equals("#N/A")){
errRows.push(nRow+actSummCol.getRow())
}
}
Logger.log("Got " + errRows.length + " error rows for " + dept.getDisplayValue() + " Dept.")
//Get Cell where data append should start from.
var deptInputLastAvailableRow = deptInputSht.getRange("B1")
while(!deptInputLastAvailableRow.isBlank() || deptInputLastAvailableRow.isPartOfMerge()){
deptInputLastAvailableRow=deptInputLastAvailableRow.offset(1,0)
}
Logger.log(dept.getDisplayValue() + " Dept." + " Input will be updated from " + deptInputLastAvailableRow.getA1Notation())
//Copy CDE from the filtered rows to Department Input Sheet
var srcCols=deptSht.getRange(dept.offset(0,4).getDisplayValue())
//There should be a better way of iterating. for-of throws syntax error!!!
for(idx in errRows){
var row = errRows[idx];
var lc = srcCols.getLastColumn()
var fc = srcCols.getColumn()
var errKeyRangeAddress=srcCols.getCell(row,1).getA1Notation() + ":" + srcCols.getCell(row,lc-fc + 1).getA1Notation()
var errKeyRange=deptSht.getRange(errKeyRangeAddress)
errKeyRange.copyTo(deptInputLastAvailableRow)
deptInputLastAvailableRow=deptInputLastAvailableRow.offset(1,0)
}
Logger.log("Copied " + errRows.length + " entries to Sheet \"" + deptInputSht.getName() + "\"")
Logger.log("Finished Processing " + dept.getDisplayValue() + " Dept.")
dept=dept.offset(1,0)
}
}
function onOpen(){
//Choose which way you want your menu to appear.
//SpreadsheetApp.getActiveSpreadsheet().addMenu("Monitor", [{name:"Clean Up Keys",functionName:"cleanComponentList"}])
SpreadsheetApp.getUi().createAddonMenu().addItem("Clean Up Keys", "cleanComponentList").addToUi()
}
This is a simple copy script to help you get started. copyTo is documented here. The rest of the commands can be found in the same documentation.
After you've done a few of your own scripts you'll find it a lot easier to make up your own rather than spending all of your time copying scripts.
function copyPasteSelectedRows()
{
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('Sheet2');
var sh0=ss.getSheetByName('Sheet1');
var rg0=sh0.getDataRange();
var vA=rg0.getValues();
for(var i=1;i<vA.length;i++)
{
if(vA[i][10]==1)//condition to meet to copy
{
var src=sh0.getRange(i+1,1,1,vA[i].length);//source range
var tar=sh1.getRange(sh1.getLastRow() + 1,1,1,vA[i].length);//target range
src.copyTo(tar);
}
}
}
This is Sheet1:
This is Sheet2 after the copy:

Importing Data into a spreadsheet and reading the values with Google Script

We use a master spreadsheet containing all the information of the students. I want to create a UI to capture the marks of each student and write it to a Google Sheet from which I will generate their report cards.
I use the following code to import the data from the master list - the names gets imported correctly, but I cannot seem to pull the values? I just get "undefined"
/**
* A function that inserts a custom menu when the spreadsheet opens to generate the Report Spreadsheet.
*/
function onOpen() {
var menu = [{name: 'Capture Report Data', functionName: 'setUpProgressReport_'}];
SpreadsheetApp.getActive().addMenu('Progress Report', menu);
}
/**
* A set-up function that creates a Report Sheet based on the class selected
*/
function setUpProgressReport_() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Report 1');
var ui = SpreadsheetApp.getUi(),
response = ui.prompt(
'Enter Class',
'Please enter the class you would like to enter marks for',
ui.ButtonSet.OK_CANCEL),
selectedClass = response.getResponseText();
//Import names of learners by selected class from Master Sheet
var cell = sheet.getRange("A1");
cell.setFormula('=QUERY(IMPORTRANGE("1Dxjt6W54e7n2F8a2zlRZV0n-VtCoPZTC2oZgeMPd8mE","MasterList!A1:Z2000"),"SELECT Col1, Col2,Col4 WHERE Col4 contains ' + "'" + selectedClass + "'" + ' Order by Col2 asc")');
// Freezes the first row to be used as headings
sheet.setFrozenRows(1);
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var values = SpreadsheetApp.getActiveSheet().getRange(lastRow, lastColumn).getValues();
Browser.msgBox(values[0][22]);
}
Use SpreadsheetApp.flush() to apply all pending spreadsheet changes before getting the values of cells previously modified by the script.
From https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush()
Spreadsheet operations are sometimes bundled together to improve
performance, such as when doing multiple calls to Range.getValue().
However, sometimes you may want to make sure that all pending changes
are made right away, for instance to show users data as a script is
executing.
Also could be helpful to include a test loop to be sure that the IMPORTRANGE task is complete. This test loop could check every certain amount of time,let say 500 millisecondes if certain change already occurred, in example, the script could get the last row before doing the import and compare it with the last row after it and doing a loop until the last is greater than the first.
An alternative is to use Utilities.sleep(milliseconds) alone. This could work but since the IMPORTRANGE execution time isn't deterministic we can not know for sure how many time is required.
I am no expert but I think I kind of figured out what the problem was... well in theory and maybe not in the correct technical details.
var ss = SpreadsheetApp.getActive() sets the current spreadsheet as the ss value, and this is without the imported data. So referencing this variable actually references the data before it was imported. By creating a seperate function and "refreshing" the var ss = SpreadsheetApp.getActive() solved the issue and I could retrieve data normally.

Copying Data Sheet1 to Sheet2 so you can sort & edit both sheets (google apps script?)

I am working in goggle sheets and think I need to use a google apps script to do what I want, but I am a psychologist at a non-profit University hospital trying to do some good and not a programmer (which probably shows) and I am desperately in need of help. I am trying to set up a series of spreadsheets to track participation in workshops for our treatment method.
1) I have a sheet “Participant_Registration” where basic information is entered
2) I want to transfer information from only the first four columns (A:D) of “Participant_Registration” to a second sheet “Learning_Sessions_Attendance”
3) I am also transferring the same information to a third sheet 'Consultation1_Attendance' – but I need to first filter and select only those people assigned to that group.
Here is a link to a copy of my spreadsheet.
https://docs.google.com/spreadsheets/d/17d0bT4LZOx5cyjSUHPRFgEZTz4y1yEL_tO3gtSJ4UJ8/edit?usp=sharing
More generically this is what I am trying to do. Is this possible in google app scripts? It seems it should be.
1) I have original data in sheet1
2) I want the first four columns (A:D) to transfer to sheet2 (it is fine if I need a trigger variable)
3) I want them to transfer in such a way that if you sort either sheet, the data are still fine (still linked to the right line).
4) Ideally if there is a change to the data in the source sheet (Sheet1) the same change will be made in Sheet2.
5) Ideally this would all happen automatically without human intervention through a script.
Any ideas?? I so need your help. I have been all over the forum, git hub, and done a ton of searches and tried following a lot of examples I saw but nothing works. I really need help.
Here are my sample scripts each with a problem:
//The following code copies a range from sheet1 to sheet2 as I wanted. A problem occurs if after if we copy the data from sheet1 we add data to other columns on sheet2. Later if we sort on some variable (which people are bound to do) if the function is deployed again it will overwrite data meaning the data from sheet1 are not connected to the right individual on sheet2
function CopyRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Participant_Registration");
var range = sheet.getRange("A14:D");
var values = range.getValues();
var target = ss.getSheetByName("Learning_Sessions_Attendance");
var target_range = target.getRange("A10:D");
range.copyTo(target_range);
}
So I tried again. This time I tried to just copy the last edited row from sheet1 to sheet2. This function does not appear to work for me.
function CopyRow2() {
// Get Spreadsheets
var source = SpreadsheetApp.openById("1egn6pnRd6mKMGuQxX_jtgwYDtkuMUv2QJItLdh7aIEs");
var target = SpreadsheetApp.openById("1egn6pnRd6mKMGuQxX_jtgwYDtkuMUv2QJItLdh7aIEs");
// Set Sheets
var source_sheet = source.getSheetByName("Participant_Registration");
var target_sheet = target.getSheetByName("Learning_Sessions_Attendance");
var rowIdx = source_sheet.getActiveRange().getRowIndex();
var rowValues = source_sheet.getRange(rowIdx,1,1,source_sheet.getLastRow()).getValues();
Logger.log(rowValues);
var destValues = [];
destValues.push(rowValues[0][0]);// copy data from col A to col A
destValues.push(rowValues[0][1]);//copy data from col B to col B
destValues.push(rowValues[0][2]);//copy data from col C to col C
destValues.push(rowValues[0][3]);//copy data from col D to col D
var dest=source.getSheets()[4];
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);//update destination sheet with selected values in the right order, the brackets are there to build the 2D array needed to write to a range
}
So I tried again and again. I have lots of examples but none seem to work.
Thanks so much.
Chandra
For that to happen automatically (one sheet's change updating another sheet), you will surely need an "event/trigger" to run a script whenever you change a cell. (that is the "onEdit()" function).
But since scripts are likely to fail sometimes (even when they are perfect, that's because of some Google issues), it's not guaranteed that the sheets will always contain the same data.
But, if I could suggest another way, do not let ID be optional. If that is a real ID (like the person ID card number), create another ID exclusively for working with the sheet.
I have edited your second sheet showing a suggestion of how to do it without using scripts. The only things you must be aware of are:
Do not create two people with the same ID.
You have to insert (only) the ID manually in the second sheet.
The VLOOKUP forumla will search for that ID in the first sheet and return the data in the same line. You can sort any sheet in whatever way you like. As long as you don't change people's IDs.
So, in sheet 2, use this in the First Name, Last Name and Email address:
=vlookup(A10,Participant_Registration!$A:$D,2,false)
=vlookup(A10,Participant_Registration!$A:$D,3,false)
=vlookup(A10,Participant_Registration!$A:$D,4,false)
Just extend this formula downwards
I hope this helps. I would avoid scripting for that at any cost. It would be my last resort. (Scripts also need to be changed if you want to rearrange your sheet, and if not, they might cause trouble, write over existing data...)
I also added a button (insert - drawing) and put a script in it (right button, click down arrow, "transfer? script" -- translated from Portuguese).
If you lock all four columns in sheet2 and lock the ID column in sheet 1, people will not be able to chang IDs and cause mess. They can edit people in sheet 1 and not change the formula in sheet2. Script is not affected by sorting or empty spaces (it adds the person in the first empty row it finds).
I added "named ranges" for the four column headers. (With named ranges, the script can refer to names instead of coordinates, which enables you to rearrange the sheet inserting and deleting columns, or moving them with CUT and paste - but the VLOOKUP formula will need manual update if you rearrange columns).
Here is the code: (it could get better if you manage to create dialog boxes and ask for the person's data inside that dialog, then you could lock everything - and you would need an edit button besides the add).
function AddPerson()
{
var S1Name = "Participant_Registration";
var S2Name = "Learning_Sessions_Attendance";
var ID1Name = "regID";
var ID2Name = "learnID";
//these vars are not used in this script
var FN1Name = "regFirstName";
var FN2Name = "learnFirstName";
var LN1Name = "regLastName";
var LN2Name = "learnLastName";
var Email1Name = "regEmail";
var Email2Name = "learnEmail";
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var Sheet1 = sSheet.getSheetByName(S1Name);
var Sheet2 = sSheet.getSheetByName(S2Name);
var ID1 = getRangeByName(sSheet, Sheet1.getName(), ID1Name);
var ID2 = getRangeByName(sSheet, Sheet2.getName(), ID2Name); Logger.log("ID2: " + ID2.getValue());
var Empty1 = getFirstEmpty(ID1);
var Empty2 = getFirstEmpty(ID2);
var Biggest1 = getBiggestID(ID1); Logger.log("Biggest 1: " + Biggest1);
var Biggest2 = getBiggestID(ID2); Logger.log("Biggest 2: " + Biggest2);
if (Biggest1 !== Biggest2)
Browser.msgBox("Warning: there are IDs in one sheet that are not in the other sheet");
var Biggest;
if (Biggest1 > Biggest2) Biggest = Biggest1;
else Biggest = Biggest2;
Biggest++;
Empty1.setValue(Biggest);
Empty2.setValue(Biggest);
}
function getFirstEmpty(Header)
{
while (Header.getValue() !== "")
{
Header = Header.offset(1,0);
}
return Header;
}
function getBiggestID(Header)
{
var Sheet = Header.getSheet();
var LastRow = Sheet.getLastRow();
var Values = Sheet.getRange(Header.getRow(), Header.getColumn(), LastRow - Header.getRow() + 1).getValues();
var len = Values.length;
var MaxID = 1;
for (var i = 0; i < len; i++)
{
var val = Number(Values[i]);
if (!isNaN(val) && val > MaxID)
MaxID = val;
}
return MaxID;
}
function getRangeByName(spreadSheet, sheetName, rangeName)
{
Logger.log("Trying range: " + "'" + sheetName + "'!" + rangeName);
return spreadSheet.getRangeByName("'" + sheetName + "'!" + rangeName);
}