Google Apps Scripts send 2 form input to 2 difference column but in same Row - google-apps-script

Hello there actually im new using this Apps scripts and trying to build something that can be achieve with spreadsheet. The problem is when i submit new data to a second form the output is below the new data.,
here the code:
Code.gs
function processForm(input1, input2, input3) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("B4:D4");
range.setValues([[input1, input2, input3]]);
var values = range.getValues();
var lastRow = sheet.getLastRow();
var nextRow = lastRow + 1;
sheet.insertRowAfter(lastRow);
sheet.getRange(nextRow, range.getColumn(), 1, 3).setValues([[input1, input2, input3]]);
return true;
}
function processForm1(input4, input5, input6) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("G4:I4");
range.setValues([[input4, input5, input6]]);
var values = range.getValues();
var lastRow = sheet.getLastRow();
var nextRow = lastRow + 1;
sheet.insertRowAfter(lastRow);
sheet.getRange(nextRow, 7, 1, 3).setValues([[input4, input5, input6]]);
return true;
}
i have try many option but still cant figure it out.,
the row is still follow the lastrow of processform.
refer the image what im trying to achieve

How about modifying your script using this sample script?
Modified script:
// Ref: https://stackoverflow.com/a/44563639
Object.prototype.get1stNonEmptyRowFromBottom = function (columnNumber, offsetRow = 1) {
const search = this.getRange(offsetRow, columnNumber, this.getMaxRows()).createTextFinder(".").useRegularExpression(true).findPrevious();
return search ? search.getRow() : offsetRow;
};
function processForm(input1, input2, input3) {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.get1stNonEmptyRowFromBottom(2) + 1; // Last row of column "B".
// sheet.insertRowAfter(row); // If you want to use this line, please enable this.
sheet.getRange(row, 2, 1, 3).setValues([[input1, input2, input3]]);
return true;
}
function processForm1(input4, input5, input6) {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.get1stNonEmptyRowFromBottom(7) + 1; // Last row of column "G".
// sheet.insertRowAfter(row); // If you want to use this line, please enable this.
sheet.getRange(row, 7, 1, 3).setValues([[input4, input5, input6]]);
return true;
}
By this modification, at processForm, the values are put to the next row of the last row of column "B". At processForm1, the values are put to the next row of the last row of column "G".
Reference:
Related thread.
Determining the last row in a single column

Related

Loop function from a certain row till the last row

I have a list of urls in column A, and I'm copying and pasting formulas from a row that contains the formulas (Template row) against the URLs to extract data.
The code then does a SpreadsheetApp.flush(); and then copies the the results from that particular row and pastes it as values onto the same row.
The code I've put together to do this is as follows.
function scraper(){
copypasteFormulas();
copypasteResultValues();
}
function copypasteFormulas() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var sourceRange = sheet.getRange('B2:T2'); //Copy formulas from template row
var sourceFormulas = sourceRange.getFormulasR1C1();
var targetRange = sheet.getRange('B5:T5'); //Paste formulas
targetRange.setFormulasR1C1(sourceFormulas);
}
function copypasteResultValues() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
SpreadsheetApp.flush(); //Delay between paste of formula and copypaste of values onto it's self
var copyFromRange = 'Sheet1!B5:T5'; // Copies result range
var copyToRangeStart = 'Sheet1!B5'; // Pastes results into itself as values
var source = sheet.getRange(copyFromRange);
source.copyTo(sheet.getRange(copyToRangeStart), {contentsOnly: true});
}
However I'd like for this to loop through every row till the last row and start again from B5:T5 to the end of the rows.
For example the following stays constant since thats where the formulas are copied from.
var sourceRange = sheet.getRange('B2:T2'); //Copy formulas from template row
var sourceFormulas = sourceRange.getFormulasR1C1();
The rest needs to change as each row gets filled in
var targetRange = sheet.getRange('B5:T5'); //Paste formulas
targetRange.setFormulasR1C1(sourceFormulas);
var copyFromRange = 'Scraper!B5:T5'; // Copies result range
var copyToRangeStart = 'Scraper!B5'; // Pastes results into itself as values
I'm not sure how to do this.
****** UPDATE ******
I managed to put together the following code to loop through from a certain row to the last row.
function iterativeCopyPaste() {
// Get array of values in the search Range
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Scraper");
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(2,2, lastRow-1, lastColumn-1);
var rangeValues = searchRange.getValues(); // Loop through array and if condition met, add relevant
var sourceRange = sheet.getRange(2,2,1,19); //Copy formulas from template row
var sourceFormulas = sourceRange.getFormulasR1C1();
// Copy paste formulas and copy paste result to values iteration
for ( j = 5 ; j < lastRow - 1; j++){
var i = 2;
if(rangeValues[j][i] === ""){
var targetRange = sheet.getRange(j, i, 1, 19); //row range to which the formulas are pasted
targetRange.setFormulasR1C1(sourceFormulas);
SpreadsheetApp.flush();
};
var source = sheet.getRange(j, i, 1, 19); // result range to copy
SpreadsheetApp.flush();
source.copyTo(sheet.getRange(j, i, 1, 19), {contentsOnly: true}); // Pastes results into itself as values
SpreadsheetApp.flush();
};
};
However it stops two rows before the last row, so I had to add two dummy rows at the end of the list on column A so the urls get looped through.
The formulas that get copied into the rows use importxml to extract data and sometimes they get stuck on "Loading", one of the formulas I use as follows.
=if(iserror(IMPORTXML($A2,"//h1[contains(#class,'ch-title')]")),"Loading",IMPORTXML($A2,"//h1[contains(#class,'ch-title')]"))
Is there any way that the iteration only goes ahead only if none of the cells in sheet.getRange(j, i, 1, 19) show as loading.
EDIT: It appears that if I use a
SpreadsheetApp.flush();
Utilities.sleep(100000);
under //row range to which the formulas are pasted it appears to slowly go through all the URLs loading up all the data and then copying and pasting on itself as values. So far it seems to work well.
This is the final code I put together that works for what I wanted.
And set a time trigger to run every 30 minutes incase there is a timeout.
function iterativeCopyPaste() {
// Get array of values in the search Range
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Scraper");
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(2,2, lastRow-1, lastColumn-1);
var rangeValues = searchRange.getValues(); // Loop through array and if condition met, add relevant
var sourceRange = sheet.getRange(2,2,1,10); //Copy formulas from template row
var sourceFormulas = sourceRange.getFormulasR1C1();
var counter = 0;
// Copy paste formulas and copy paste result to values iteration
for ( j = 5 ; j < lastRow - 1; j++){
var i = 2;
counter++;
var targetRange = sheet.getRange(j, i, 1, 10); //row range to which the formulas are pasted
if(targetRange.isBlank()){
//var targetRange = sheet.getRange(j, i, 1, 10); //row range to which the formulas are pasted
targetRange.setFormulasR1C1(sourceFormulas);
SpreadsheetApp.flush();
Utilities.sleep(100000); // Delay before the copy and paste of result values
};
var source = sheet.getRange(j, i, 1, 19); // result range to copy
SpreadsheetApp.flush();
source.copyTo(sheet.getRange(j, i, 1, 19), {contentsOnly: true}); // Pastes results into itself as values
SpreadsheetApp.flush();
if (counter === 4) { // Delay after every 5 rows
Utilities.sleep(240000);
SpreadsheetApp.flush();
counter = 0;
};
};
};

Google Sheets Script to import data based on cell value and not duplicate information

I need to pull/import data from "sheet 1" to "sheet 2" based on column 4 being a specific text string. The script should not pull lines that already exist.
I have no idea if this is possible. I can pull the data but it just recopies everything so I have duplicates.
Any help would be super appreciated.
function onEdit() {
var ss = SpreadsheetApp.openById('1Ognzsi6C0DU_ZyDLuct58f5U16sshhBpBoQ8Snk8bhc');
var sheet = ss.getSheetByName('Sheet 1');
var testrange = sheet.getRange('D:D');
var testvalue = (testrange.getValues());
var sss = SpreadsheetApp.getActive();
var csh = sss.getSheetByName('Sheet 1');
var data = [];
var j =[];
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'Dan') {
data.push.apply(data,sheet.getRange(i+1,1,1,11).getValues());
j.push(i);
}
}
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
Sheet 1
Sheet 2
Solution
You should be able to replace your code with this and it will work. You would put this script in the target sheet (Sheet 2), and replace the ID in the first line of the function with the origin (Sheet 1).
I'll leave it up to you to change to an onEdit or to make it a menu item. Right now it can be run from the script editor. onEdit doesn't make sense to me as an appropriate trigger. Maybe you prefer a Time-Driven Trigger. Though a custom menu would be the best way IMO.
function pullData() {
var sourceSs = SpreadsheetApp.openById('[YOUR_SPREADSHEET_ID]');
var sourceRange = sourceSs.getSheetByName('Sheet1').getDataRange();
var sourceHeight = sourceRange.getHeight();
var sourceWidth = sourceRange.getWidth();
var sourceData = sourceSs.getSheetByName('Sheet1').getRange(2, 1, sourceHeight - 1, sourceWidth).getValues();
var targetSs = SpreadsheetApp.getActive();
var targetRange = targetSs.getSheetByName('Sheet1').getDataRange();
var targetHeight = targetRange.getHeight();
var targetWidth = targetRange.getWidth();
var sourceDataChecker = [];
var targetDataChecker = [];
sourceData.forEach((row) => {
sourceDataChecker.push(row[0] + row[1] + row[2] + row[3]);
})
if (targetHeight != 1) {
var targetData = sourceSs.getSheetByName('Sheet1').getRange(2, 1, targetHeight - 1, targetWidth).getValues();
targetData.forEach((row) => {
targetDataChecker.push(row[0] + row[1] + row[2] + row[3]);
});
};
sourceData.forEach((row, i) => {
if (!(targetDataChecker.includes(sourceDataChecker[i]))) {
targetSs.appendRow(row);
};
});
}
Explanation
This script builds an "index" of each row in both sheets by concatenating all the values in the row. I did this because I noticed that sometimes you have "joe" in two rows, and so, you can't simply use column 4 as your index. You are basically checking for any row that is different from one in the target sheet (Sheet 2).
If the target sheet is blank, then all rows are copied.
References
Append Row to end of sheet
Get Data Range (range of sheet that contains data)
Get Range Height (to deal with headers)
Get Range Width
for Each

Google Script: copy values from one sheet to another determining the range

I have two sheets with unique IDs in one column. I need to make sure whenever a new ID is added in one sheet (Sheet1), it is copied to the last empty row in the other sheet (Sheet2). The IMPORTRANGE won't work as being dynamic any static information added in the other sheet would be irrelevant to the respective ID.
In another thread [1], I got help developing this script that will do exactly that. However, this script will insert the data in the other sheet in Column A. How can I modify the script so I can decide the specific range where I want the script to insert the data (in Sheet 2).
Update: I created this spreadsheet as an example. I'm trying to ensure that the script does the calculation (ie. adding vlaues that are not duplicated in the first available empty row), starting in cel C10 in "Sheet2". It would be also great if I can somehow change that range if I need to: https://docs.google.com/spreadsheets/d/1abESAXFrOHoqRQRNqQGfmAFxlbD10wlprAf1tca4y7o/edit#gid=132361488
Thanks!
function updateSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = "Sheet1";
var destinationSheet = "Sheet2";
var source_sheet = ss.getSheetByName(sourceSheet);
var target_sheet = ss.getSheetByName(destinationSheet);
var lastCol = target_sheet.getLastColumn();
var lastRow = target_sheet.getLastRow();
if (lastRow > 1) { // <--- Added
var r = target_sheet.getRange(2,1, lastRow - 1, lastCol);
r.sort([{column: 1, ascending: true}]);
}
_updateSpreadsheet(source_sheet, target_sheet);
}
function _updateSpreadsheet(source_sheet, target_sheet) {
var last_row = target_sheet.getLastRow();
var source_data = source_sheet.getRange("A4:A" + source_sheet.getLastRow()).getValues(); // <--- Modified
var target_data = target_sheet.getDataRange().getValues();
var resultArray = [];
for (var n = 0 ; n < source_data.length ; n++) { // <--- Modified
var keep = true;
for(var p in target_data) {
if (source_data[n][0] == target_data[p][0]) {
keep = false; break;
}
}
var columnsToKeep = [0];
var tempData = [];
if(keep){
for(var c in columnsToKeep){ tempData.push(source_data[n][columnsToKeep[c]])}
resultArray.push(tempData);
}
}
last_row++;
resultArray = resultArray.filter(String); // <--- Added
if(resultArray.length>0){
target_sheet.getRange(last_row,1,resultArray.length,resultArray[0].length).setValues(resultArray);
}
}
[1] Google Script: Append new values in column to another sheet
target_sheet.getRange(last_row,1,resultArray.length,resultArray[0].length)
.setValues(resultArray);
This line
Takes the sheet stored in the variable target_sheet
Accesses the defined range
Sets values
The syntax to access a range used in your code is getRange(row, column, numRows, numColumns)
whereby the start column is numerical - in your case it's 1 which corresponds to column A.
If you want to modify the start column from A to B:
Just change your range definition from
getRange(last_row,1,resultArray.length,resultArray[0].length)
to
getRange(last_row,2,resultArray.length,resultArray[0].length)

How do you use a cell value to find the matching sheet name?

I am trying to find a way to copy information from one sheet to another. I know how to find the information from the sheet to copy from, but I'm having trouble finding the sheet to copy to. I want to copy to a sheet based off of a value in my original sheet.
I have a list of names in column C, ex. John, Mark, and Will that starts in row 40. I would like to then copy John's row of information to the sheet titled "John", and Mark's information to a sheet titled "Mark", etc. so that each person's information is summarized on their own sheet. I am having trouble using the value found in column C (the person's name), and then using that value to find a sheet with the coordinating name.
function CopyInfo() {
var CopyFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Summary");
var ColumntoSearch = 3;
var LastRow = CopyFrom.getLastRow();
//Gets column to search for names to compare
var Range = CopyFrom.getRange(40, ColumntoSearch, LastRow, 1);
var Values = Range.getValues();
//Sets the amount of data to copy over
var NumberofColumns = 11;
var NumberofRows = 1;
//Compares all the names in the Summary sheet
var d=0;
for(var i=0;i<Values.length;i++) {
var Name = CopyFrom.getRange(i-d+40, 3);
var CopyTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(Name);
if(Name == ????????){
var RangetoCopy=CopyFrom.getRange(i-d+40,1,NumberofRows,NumberofColumns);
var DestRange=CopyTo.getRange(CopyTo.getLastRow()+1,1,NumberofRows,NumberofColumns);
RangetoCopy.copyTo(DestRange);
d++;
}
}
}
You want to copy the values from Summary sheet to each sheet with the sheet name retrieved from the column "C" in Summary sheet.
There are values for copying in the column "A:K".
For example, when the row 45 of Summary sheet has the values of a45, b45, c45, d45, e45, f45, g45, h45, i45, j45, k45, the values are copied to just below the last row of the sheet name of c45.
If my understanding is correct, how about this modification? I think your script is almost correct. So I modified your script a little.
Modified script:
function CopyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Added
var CopyFrom = ss.getSheetByName("Summary"); // Modified
var ColumntoSearch = 3;
var LastRow = CopyFrom.getLastRow();
//Gets column to search for names to compare
var Range = CopyFrom.getRange(40, ColumntoSearch, LastRow, 1);
var Values = Range.getValues();
//Sets the amount of data to copy over
var NumberofColumns = 11;
var NumberofRows = 1;
//Compares all the names in the Summary sheet
// var d=0; // Removed
for (var i = 0; i < Values.length; i++) {
var Name = Values[i][0]; // Modified
var CopyTo = ss.getSheetByName(Name); // Modified
if (Name) { // Modified
if (!CopyTo) CopyTo = ss.insertSheet(Name); // Added
var RangetoCopy = CopyFrom.getRange(i + 40, 1, NumberofRows, NumberofColumns); // Modified
var DestRange = CopyTo.getRange(CopyTo.getLastRow() + 1, 1, NumberofRows, NumberofColumns);
RangetoCopy.copyTo(DestRange);
// d++; // Removed
}
}
}
Note:
In this modified script, if the sheet name is not found, new sheet of the sheet name is inserted. If you don't want to insert new sheet, please replace if(!CopyTo) CopyTo = ss.insertSheet(Name) to the following script.
if (CopyTo) {
var RangetoCopy = CopyFrom.getRange(i + 40, 1, NumberofRows, NumberofColumns);
var DestRange = CopyTo.getRange(CopyTo.getLastRow() + 1, 1, NumberofRows, NumberofColumns);
RangetoCopy.copyTo(DestRange);
}
If I misunderstood your question and this was not the result you want, I apologize.

SORT script works for owner but not editors

I've written script to sort a google sheet by column A, and then take you to the cell next to the one you just edited, and I have it working perfectly for me the owner, but for editors, nothing seems to work starting from the "sort" function.
I assume this means some part of it is an installable trigger? but as far as I can tell I've made it all with simple triggers.
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var NEXTcell = sheet.getActiveRange().offset(0,1);
var range = e.range;
var columnOfCellEdited = range.getColumn();
var sheet = spreadsheet.getActiveSheet();
// When Column A edited
if (columnOfCellEdited === 1) {// Column 1 is Column A
//Set marker
NEXTcell.setValue('sorting');
// Sort whole sheet excluding first 2 rows by Column A.
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).activate();
spreadsheet.getActiveRange().offset(2, 0, spreadsheet.getActiveRange().getNumRows() - 2).sort({column: 1, ascending: true});
// Find original cell after sorting
var rowoffset = 3;
var rng = sheet.getRange(rowoffset, 2, 600);
var data = rng.getValues();
var search = "sorting";
for (var i=0; i < data.length; i++) {
if (data[i][0] == search) {
data[i][0] = "";
rng.setValues(data);
var foundcell = sheet.getRange((i+rowoffset), 2);
foundcell.activate();
break;
}
}
}
}
So Stackdriver logs for-the-win.
Turns out protections I hadn't considered are the culprit.