I have tried and combined a few pieces of script to delete rows, but this does not reset the counter. Help resetting responses would be appreciated.
My copy sheet function, and delete all rows function works, but the counter remains, showing 58 responses.
I use the triggers to set the copy and delete functions to occur daily. (sheet url excluding the "docs.google.com..." 0AvTM4SfinH2NdGp1MHdzWms2QnpUMnFiMHJXd1dlV1E&usp) This is what I have so far:
function CopySheet() {
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getSheets()[0];// here I chose to always get the first sheet in the spreadsheet
var inputRange = ss.getRange(1,1,ss.getLastRow(),7);
var data = inputRange.getValues();
var newData = [];
newData.push(['Timestamp','Full Name?','Email?','RAG']);
for(var n=1;n<data.length;++n){ // skip headers by starting at 1
for(var c=0;c<7;c=c+3){
var row = [];
if(c==0){row.push(data[n][0]) ; c++}else{row.push('')};
row.push(data[n][c])
row.push(data[n][c+1]);
row.push(data[n][c+1+1]);//Keep adding a new row and +1 for each extra column
newData.push(row);
}
}
//This next bit creates a copy of the sheet. I would rather a spreadsheet copy but could only get document copy to work
sh.insertSheet().getRange(1,1,newData.length,newData[0].length).setValues(newData);
var doc = DocumentApp.create('Responses document'); // create document
var file = DocsList.getFileById(doc.getId());
file.removeFromFolder(DocsList.getRootFolder());
file.addToFolder(DocsList.getFolder("Folder 1"));
var table = doc.getBody().appendTable(newData); // create table in a separate process so I can set the style below
var style = {};
style[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER; // this one has no effect
style[DocumentApp.Attribute.FONT_FAMILY] = DocumentApp.FontFamily.ARIAL;
style[DocumentApp.Attribute.FONT_SIZE] = 10;
style[DocumentApp.Attribute.FOREGROUND_COLOR] = '#0000ff';
style[DocumentApp.Attribute.BORDER_COLOR] = '#dddddd' ;
table.setAttributes(style);
}
//This section deletes the sheet, leaving the headers; "function deleteAllResponses()" at the bottom should reset counter but does not work
function DeleteSheet() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
for (i=lastrow;i>=2;i--) {
var tempdate = values[i-1][2]; // arrays are 0 indexed so row1 = values[0] and col3 = [2], If I add more columns I need to up this number
{
sheet.deleteRow(i);
function deleteAllResponses() {}
}
}
}
If you mean the counter responses shown on the form:
One option may be to use deleteAllResponses() (read carefully the documentation) from Class Form.
A minimal implementation can be:
/* CODE FOR DEMONSTRATION PURPOSES */
function deleteAllResponses() {
var form, urlForm = SpreadsheetApp.getActiveSpreadsheet().getFormUrl();
if (urlForm) {
form = FormApp.openByUrl(urlForm);
if (form) form.deleteAllResponses();
}
}
#user2847142, #brian-tompsett, #wchiquito
New Google Forms allows you to delete even individual responses from within a Google Form itself without the need of a script.
There is now a simpler method than the answer given by #wchiquito.
--This is now possible on the New Google Forms--
Google announcement on the 10th of February 2016. (googleappsupdates.blogspot.com/2016/02/new-google-forms-now-default-option.html)
How to delete ALL of the responses:
How to delete individual responses:
To delete individual responses you click on the "Responses" tab and choose "Individual". You locate the record you wish to delete and click on the trash can icon to delete that individual response.
This will also reset the counter.
However. The response/s will NOT be deleted from the connected to the form spreadsheet. You will have to manually delete those ones (or using a script).
Related
I have a Google Sheet with the 'Form Responses' sheet being populated by an external integration (JotForm).
I have an onChange trigger which responds to the incoming row, and copies the data to either one worksheet or another (Quote or Order based on a specific column value). This works fine, but I would like to split the row into multiple rows - using a 'new line' delimiter that will be present in one of the fields. The purpose of this is to enable granular updates to line items by a 3rd party.
Image of incoming data
Image or resulting data that I wish to have
It can be something like this:
function main() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var table = split_rows(data);
sheet
.clearContents()
.getRange(1,1,table.length,table[0].length)
.setValues(table);
}
function split_rows(data) {
var rows = [];
while (data.length) {
var row = data.shift();
var items = row[4].split('\n');
while(items.length) {
var item = items.shift();
rows.push([row[0], ...row.slice(2,4), item, ...row.slice(5)]);
}
}
return rows;
}
Input:
Output:
Update
Here is the example of the main function that takes a last row from the active sheet, splits it (with the same as above function split_rows()) and appends the result rows at the end of the sheet 'Sheet2':
function main_append_rows() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var last_row = data.pop();
var new_rows = split_rows([last_row]);
var dest_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
while(new_rows.length) dest_sheet.appendRow(new_rows.shift());
}
I have a problem where I have two sheets. one sheet is the source spreadsheet and another is a target spreadsheet. The source spreadsheet has a source sheet has which is the master database and the target spreadsheet has the target where we want to fetch data from source sheet based on emails provided in the Emails tab in the target spreadsheet.
I want the following things to happen with a script and not with IMPORTRANGE or QUERY:
The target spreadsheet will have multiple copies so I want to connect the target spreadsheet with the source spreadsheet based on the source spreadsheet's id.
I want the email matches to be case insensitive so that the users of the target spreadsheet can type emails in any case.
The Emails can go up to 50 or let's say get the last row for that column.
It will be great if the script shows a pop up saying updated after it has fetched the data.
The source sheet might have data up to 15000 rows so I am thinking about speed too.
I have shared both of the spreadsheets with hyperlinks to their names. I am not really great at scripts so it will be helpful if you can leave comments in it wherever you feel like. I would truly appreciate your help.
Thanks in advance!
Script here:
function fetch() {
//get the sheets
var source_Ssheet = SpreadsheetApp.openById('19FkL3rsh5sxdujb6x00BUPvXEEhiXfAeURTeQi3YWzo');
var target_Ssheet = SpreadsheetApp.getActiveSpreadsheet();
//get the tabs
var email_sheet = target_Ssheet.getSheetByName("Emails");
var target_sheet = target_Ssheet.getSheetByName("Target Sheet");
var source_sheet = source_Ssheet.getSheetByName("Source Sheet");
//get ranges
var email_list = email_sheet.getRange("B2:B");
var target_sheet_range = target_sheet.getRange("A1:F100");
var source_sheet_range = source_sheet.getRange("A1:F100");
//get last rows
var last_email_name = email_list.getLastRow();
var last_target_sheet_range = target_sheet_range.getLastRow();
var last_source_sheet_range = source_sheet_range.getLastRow();
//start searching for emails
for (var i=3; i < last_email_name.length+1; i++)
{
for(varj=3; j< last_source_sheet_range.length+1; j++ )
{
if(source_sheet_range[j][3].getValue() == email_list[i][3].getValue())
{
//copy matches to target sheet
target_sheet.getRange((last_target_sheet_range + 1),1,1,10).setValues(master_sheet_range[j].getValues());
}
}
}
}
Several things
last_email_name and last_source_sheet_range are numbers - they do not have any length, this is why your first forloops are not working
You are missing a space in varj=3;
email_list[i][3].getValue() does not exist because email_list only includes B - that only one column. I assume you meant email_list[i][0].getValue()
ranges cannot be addressed with the indices [][], you need to retrieve the values first to have a 2D value range.
You email values in the different sheets do not follow the same case. Apps Script is case sensitive, to suee the == comparison you need to use the toLowerCase() method.
Also mind that defining getRange("B2:B") will include many empty rows that you don't need and will make your code very slow. Replace it through getRange("B2:B" + email_sheet.getLastRow());
Have a look here at the debugged code - keep in mind that there is still much room for improvement.
function fetch() {
//get the sheets
var source_Ssheet = SpreadsheetApp.openById('19FkL3rsh5sxdujb6x00BUPvXEEhiXfAeURTeQi3YWzo');
var target_Ssheet = SpreadsheetApp.getActiveSpreadsheet();
//get the tabs
var email_sheet = target_Ssheet.getSheetByName("Emails");
var target_sheet = target_Ssheet.getSheetByName("Target Sheet");
var source_sheet = source_Ssheet.getSheetByName("Source Sheet");
//get ranges
var email_list = email_sheet.getRange("B2:B" + email_sheet.getLastRow()).getValues();
var target_sheet_range = target_sheet.getRange("A1:F100").getValues();
var source_sheet_range = source_sheet.getRange("A1:F100").getValues();
var last_target_sheet_range = target_sheet.getLastRow();
//start searching for emails
for (var i=1; i < email_list.length; i++)
{
for(var j=1; j< source_sheet_range.length; j++ )
{
if(source_sheet_range[j][0].toLowerCase() == email_list[i][0].toLowerCase())
{
target_sheet.getRange((last_target_sheet_range + 1),1,1,6).setValues([source_sheet_range[j]]);
}
}
}
}
I have the following app script associated with a Google Spreadsheet that is accepting data from a Google Form:
function writePatientData() {
var spreadsheet = SpreadsheetApp.openById("<spreadsheet id>");
var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
//get last row in active/main sheet
var numRows = sheet.getLastRow();
//get last row of data
var last_row = sheet.getSheetValues(numRows, 1, 1, 23);
//get patientID (column V) in last row of sheet
var lastPatientID = sheet.getRange(numRows,3).getValue();
//find patient sheet based on patientID and make it active, then write to it
var patientSheet = SpreadsheetApp.getActive().getSheetByName(lastPatientID);
var activePatientSheet = SpreadsheetApp.getActive().getSheetByName(lastPatientID);
activePatientSheet.getRange(activePatientSheet.getLastRow()+1, 1,1,23).setValues(last_row);
}
What this script is doing is writing data (a row) to another sheet within this spreadsheet based on the the patientID (column V). This works as it should when I manually run the script. However, when I set a trigger to run this script (either onSubmit or edit) nothing happens. I created another function that just writes a message to the logs and set a trigger for that function and it works, so I think there is something in the script that is causing it to fail. Any ideas appreciated.
There are a few issues with your code. I tried to fix it while commenting each line I changed. Hopefully that is clear enough, please comment if you have any questions and I'll try to clarify.
function writePatientData() {
var spreadsheet = SpreadsheetApp.getActive(); //no need for id if the script is on the same spreadsheet
//var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
//setActiveSheet will not work from a trigger like on-form-submit (what if no-one has the sheet open, or multiple have)
var sheet = spreadsheet.getSheets()[0]; //if you want the first sheet, just get it, no need to "activate"
var numRows = sheet.getLastRow();
var last_row = sheet.getSheetValues(numRows, 1, 1, 23)[0]; //added [0] since it is just one row
//var lastPatientID = sheet.getRange(numRows,3).getValue(); //you already have this in memory
var lastPatientID = last_row[2]; //arrays are zero based, that's why 2 instead of 3
//btw, you mention column V, but this is actually C
//var patientSheet = SpreadsheetApp.getActive().getSheetByName(lastPatientID);
//you already have the spreadsheet, no need to get it again
var patientSheet = spreadsheet.getSheetByName(lastPatientID);
//var activePatientSheet = spreadsheet.getSheetByName(lastPatientID); //this is the exact same as above, why?
patientSheet.appendRow(last_row); //appendRow is just simpler than getRange(getLastRow).setValues
}
I need some help refining this code. It should copy a specific worksheet in this case the sheet Master Copy based on the rows on the sheet Maxes. Then rename the sheet to the name on the given row in the sheet Maxes. When I try to execute the code all it does is insert a blank page and adds it to the end of the Spreadsheet. Please forgive the poorly written code I am really new at this and trying to make something work. Any suggestions that you could give would be gratefully appreciated. I'm not sure if there is an error within the while loops or what exactly.
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A300");
var nameStartRow = nameSource.getRange("A2");
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("a1:m66");
var nameEndRow = nameSource.getLastRow();
var lifterName;
while (nameStartRow <= nameEndRow)
{
lifterName = nameSource.getCell(nameStartRow, nameColumn);
if (lifterName == null)
{
errors.clear();
ss.getSheetsByName(lifterName) = lifterName;
if(errors.number() > 0)
{
errors.clear();
var newSheet = ss.insertSheet();
ss.renameActiveSheet(lifterName);
ss.getSheetByName(lifterName);
trainingRange.copyValuesToRange(lifterName,1,1,16,66);
lifterName.copyValuesToRange(lifterName,4,1,4,1);
}
} nameStartRow = nameStartRow + 1;
}
}
I modifyed your code because I didn't understood what you wanted exactlly, I hope this will do the trick:
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A").getValues(); // it's a table of table [][]
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("A1:M66").getValues(); // get values give a table of table
for(var i in nameColumn){
if(nameColumn[i][0]!=""){ // if blank we skip
try{ // try to see if already exist who know...
var lifter = ss.getSheetByName(nameColumn[i][0]).activate();
Logger.log("getting lifter sheet "+nameColumn[i][0]);
}
catch(err){ // well it didn't exist so lets create it :D
var lifter = ss.insertSheet(nameColumn[i][0]);
Logger.log("creating lifter sheet "+nameColumn[i][0]);
}
SpreadsheetApp.flush();
lifter.getRange("A1:M66").setValues(trainingRange); // passing the value to the created sheet
}
}
}
I also have a demo sheet here.
Please tell me if this is what you wanted (if not can you give a demo sheet of what you want and what you should get at the end)
EDIT
here the script with formulas copy (it's not nice because you are forced to define in the script where your formulas are, we could have the script to analyse the spreadsheet to search the formulas, but, has it's a copy from template, it's less ressource consuming not to do so.)
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A").getValues(); // it's a table of table [][]
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("A1:H21").getValues(); // get values give a table of table
var trainingFormulasD = trainingSheet.getRange("D2:D21").getFormulas(); // get the formulas to copy
var trainingFormulasH = trainingSheet.getRange("H2:H21").getFormulas(); // get others formulas to copy
for(var i in nameColumn){
if(nameColumn[i][0]!=""){ // if blank we skip
try{ // try to see if already exist who know...
var lifter = ss.getSheetByName(nameColumn[i][0]).activate();
Logger.log("getting lifter sheet "+nameColumn[i][0]);
}
catch(err){ // well it didn't exist so lets create it :D
var lifter = ss.insertSheet(nameColumn[i][0]);
Logger.log("creating lifter sheet "+nameColumn[i][0]);
}
SpreadsheetApp.flush();
lifter.getRange("A1:H21").setValues(trainingRange); // passing the value to the created sheet
lifter.getRange("D2:D21").setFormulas(trainingFormulasD); //passing formulas
lifter.getRange("H2:H21").setFormulas(trainingFormulasH); //passing formulas
}
}
}
I've setup a script to copy and process a spreadsheet that is generated from a form.
I gather the responses like this:
var responses = formResponses.getDataRange().getValues();
Then accessing the individual columns through the array index, for example:
var timestamp = row[0];
var agentName = row[1];
Now, while this works. Any changes to the form could end up screwing the whole thing up and the array indices will change.
Can I instead query by column name?
If accessing it via the onFormSubmit event is not viable for you because you need to access the data post-submission, I have created code that allows you to access via column name.
function getDataFields(workingRow){
//header is row 1 -- not row 0
var headerRow = 1;
var headerRowValues = getRowRange(headerRow).getValues();
var workingRowValues = getRowRange(workingRow).getValues();
var dataFields = [];
for (var colNum in headerRowValues[0]){
dataFields[headerRowValues[0][colNum]] = workingRowValues[0][colNum];
}
dataFields['Working Row'] = workingRow;
return dataFields;
}
function getRowRange(workingRow){
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lastColumn = activeSheet.getLastColumn();
return activeSheet.getRange(workingRow, 1, 1, lastColumn);
}
You can then use dataFields['Column Name'] to access the data of that particular row.
if you use the onFormSubmit event you can access all form values by their named values, this is explained in the documentation on Spreadsheet Form Submit Events so you won't have this problem anymore...