I have tons of Google Forms for a project and each one has the same sections and questions, just different choices. Every time I want to update a question, I have to change each form individually which takes a lot of time. I was wondering if there's a way to link a Form to a Sheet so I can change the question in the spreadsheet and it'll update in every single form connected.
One option I could suggest is to create a container-bound script in your Google Sheets to update the questions for multiple Google Forms using Apps Script.
Example Sheet:
We have a Google Sheet with 2 Sheets named "Questions" and "Forms" respectively.
Sheet:Questions contains the list of questions available in your Google Forms. To Update column can be used as a flag to determine which questions you want to update in the Google Forms.
Sheet:Forms contains the list of Google Forms Ids' where you want the questions to be updated.
Example Apps Script Code:
function updateFormsQuestions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formsSheet = ss.getSheetByName("Forms");
var questionsSheet = ss.getSheetByName("Questions");
//Get the list of forms to update
var formsList = formsSheet.getRange(2,1,formsSheet.getLastRow()-1).getValues();
Logger.log(formsList);
//Get the list of questions to update
var questionIndex = [];
var qCheckbox = questionsSheet.getRange(2,2,questionsSheet.getLastRow()-1,1).getValues();
Logger.log(qCheckbox);
qCheckbox.forEach(function(currentValue, index){
if(currentValue[0] == true)questionIndex.push(index);
});
Logger.log(questionIndex);
//Open Form and get all items
for( var i = 0; i < formsList.length; i++){
var forms = FormApp.openById(formsList[i][0]);
var items = forms.getItems();
//Update question
questionIndex.forEach(function(index){
Logger.log(index);
Logger.log(questionsSheet.getRange(index + 2, 1).getValue());
items[index].setTitle(questionsSheet.getRange(index + 2, 1).getValue());
});
}
}
What it Does?
Get the list of Google Forms Ids' under Sheet:Forms
Get all checkbox values under Sheet:Questions starting from Cell B2.
Check each checkbox values if set to true, then push the current index to the questionIndex array. (Note that in javascript array index starts from zero).
Open each forms listed in step 1, one-by-one using for-loop using FormApp.openById(). Then get all items of the current forms using .getItems(). It will give you an array of items available in your form (this may represent your questions in your form).
Forms items can be accessed as an array. Hence it should start from zero. (Question 1 = index 0, Question 2 = index 1 ... so on)
Update the questions in the current item using .setTitle(). The new title will be based on the cell value under Sheet:Questions column A. You can get the value of the cell using .getValue() assuming you already selected the correct cell range using .getRange().
Notice that we increment the row index by 2 when getting the cell value questionsSheet.getRange(index + 2, 1).getValue(). Cell rows and columns starts from 1 in sheets, if we want to access Cell A3, row = 3; col = 1. The index that we saved earlier in Step 3 starts from zero (since we used an array). If you are curious why we increment 2 instead of 1. The reason is because we also adjusted the indexing when we start getting the checkbox values from row 2 instead of row 1 in Step 2.
Sheet:Questions Column C will show you the indexing of the qCheckbox array, while Column D will show you the indexing of sheets when accessing rows.
Output:
BEFORE:
AFTER:
Additional References:
Forms Service - allows scripts to create, access and modify Google Forms
Spreadsheet Service - allows scripts to create, access, modify Google Sheets
Related
I will try to be as clear as possible. Here is the example piece: link
What I want to happen is that the Filter formula will search for any Sheet containing “Form Responses” and then display the results. You can see on the Current sheet how I’ve been doing, but this is more tedious and leads to issues of the first formula begins to overwrite the next one, etc. On the Wanted tab, I’ve laid out how I imagine it and put a note in A7. Any help offered is greatly appreciated!
You can get started with this script:
function getSheetResponses(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Wanted");
var getCellValue = sheet.getRange("A7").getValue(); //Gets the name of your designated sheet on "Wanted Sheet" cell "A7"
var getName = ss.getSheetByName(getCellValue);
var getNameValue = getName.getRange(2,5,getName.getLastRow(),1).getValues(); //Gets all the values of Column E on any defined sheet names based on getCellValue
var datalength = getNameValue.length;
Logger.log(datalength);
sheet.getRange(8,6,datalength,1).setValues(getNameValue); //Puts the data on Wanted Sheet Column F
}
What this does is it gets the sheet name on cell A7, and populates the data on Column F row 8 on the "Wanted" sheet like so:
Now, the data it populates on the "Wanted" sheet came from Form Responses 1 based on the sample piece you have provided:
If ever you would want to relocate which specific row or column the data would be pasted on "Wanted" Sheet. You can refer to this documentation on how to modify the rows and columns on sheet.getRange()
Reference:
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getrangerow,-column,-numrows,-numcolumns
Situation:
1 company, 3 different points of sale.
I have to make 3 different stacks of invoices.
Invoice numbers are 1/1/1, 1/1/2, 1/1/3, where the first number is incremental, second number is always 1 & third number is the point of sale identifier.
First sheet is data input.
Second is the is invoice generator.
Sheet 3, 4 & 5 are point of sale invoice archive.
I managed to get next invoice number generated depending on the point of sale using the index and left functions in separate cells but i get the error message along with the result that i actually wanted.
Is there a simple way to get generated IDs from POS1, POS2, POS3 sheets into a drop-down list data validation without any error?
Sheet Racun ->Click on the invoice number, choose point of sale (eg. POS1).
Go to sheet POS1 and click save.
https://docs.google.com/spreadsheets/d/1RD_rkbtmhC-OKh2dAtc32Qo1p42RdgKaiZsnI8uRKyg/edit?usp=sharing
I am sorry if i didnt explain myself correctly. English is not my mother language.
Suggestion
You can try adding this onOpen() function below on your Apps Script to automatically get the generated IDs from POS1,POS2,POS3 sheets & build a new data validation drop-down on cell C11 of the Racun sheet.
Script
function CopyRow(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var data = sh.getRange('A3:F3').getDisplayValues();
var lastRow = sh.getLastRow()+1
sh.getRange('A'+lastRow+':F'+lastRow).setNumberFormat("#").setValues(data);
}
function onOpen(){
var sh = SpreadsheetApp.getActive();
var cell = SpreadsheetApp.getActive().getSheetByName("Racun").getRange('C11');
var values = [sh.getSheetByName("POS1").getRange("K2").getValue()+" (POS1)",
sh.getSheetByName("POS2").getRange("K2").getValue()+" (POS2)",
sh.getSheetByName("POS3").getRange("K2").getValue()+" (POS3)"];
var rule = SpreadsheetApp.newDataValidation().requireValueInList(values).build();
cell.setDataValidation(rule);
}
Sample Demonstration
After saving & running the script or re-opening of your sheet, you will see the new drop-down:
NOTE:
On your POS1,POS2,POS3 sheets, just change the formula on cell A3 with =LEFT(Racun!C11, LEN(Racun!C11)-6) to get the generated IDs, as seen below:
I'm new to this,
I have 2 google spreadsheets:
Spreadsheet A: The active sheet Containing multiple tabs with information to be Pushed to B.
Spreadsheet B: A spreadsheet with a single tab. The same headers and structure as spreadsheet A.
Based on the user selecting the answer "Yes" in the first column of any of the 1 tabs in Spreadsheet A, I would like that entire row to move over to Spreadsheet B.
I have modified a script that works on a single spreadsheet (ie moving rows from tab to tab) to attempt to get it to work between spreadsheets:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tss = SpreadsheetApp.openById('B').getSheetByName('Sheet 1');
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(r.getColumn() == 1 && r.getValue() == "Yes") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var target = tss.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
}
}
Probably needless to say, this yields no result. Having searched through a number of posts and forums I only see individuals posting about how to move rows between tabs but not between entirely separate spreadsheets. Is it even possible to do this? If so, what am I doing wrong in the script?
Thank you so much for anyone who takes the time to assist.
Anthony
Following a dialogue with the OP in the comments section, it was indicated that the original spreadsheet did not to be kept secret.
Consequently, the desired functionality can be provided by using a combination of IMPORTRANGE() and QUERY() in the spreadsheet with no need to use Google App Script. For instance,
=QUERY(IMPORTRANGE(url,range),"select A where B matches 'Yes'") or similar
This imports data from a second spreadsheet and then the QUERY() function acts as a way of filtering the imported range by certain criteria.
Once the imported range is authorised, the editors of the spreadsheet can access it by, e.g. removing or modifying the query. You could prevent this by protecting that particular cell, if needed.
I have spreadsheet similar to this:
I'd like to remove all duplicates of row based on the first column data.
So from this screenshot row, 1 and 2 would be kept, and row 2 would be removed. Any help would be greatly appreciated.
P.S. In my case I have columns from A to AU and rows from 2 to 9500.
Thank you.
Maya's answer and the solution AJPerez linked both work.
You can also use Filter View, which doesn't require deleting rows or creating new rows/sheets.
First create a helper column, say to the left of all your data. If your data starts on row 1, then create a blank row above all your data; if not, you are fine. Afterwards, on the first row where you have data, say row 2, write in the formula
=iserror(match(B2,B$1:B1,0))
Replace "2" with the row number of the first row of your data and "1" with that number minus 1. Also populate the rest of the column with the formula. (Unfortunately, arrayformula doesn't work here.) The formula outputs TRUE when the entry in B# has not occurred in cells above.
Note that this assumes your data now starts with column B and column B is where you want the filter to base. If that's not the case, just edit the column index too accordingly.
Select this new helper column. Go to Data -> Filter Views... -> Create a new Filter. Select filter by value and check TRUE only.
Caveat: this filter can only work if there are actually rows with TRUE value. This will always be the case as some entries are always unique.
If you want to avoid the caveat in your future applications, you can use filter by conditions with custom formula. The formula b2 should work.
But to begin with, even without the helper column, the above formula should work. Why doesn't it? That would be a good question for Google Support should it exist.
You can also use a google apps script to do this. To open the script editor from google sheets:
Choose the menu Tools > Script Editor.
Copy and paste the following script:
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var newData = [];
var ids = [];
for (var i in data) {
var row = data[i];
var duplicate = false;
if (ids.indexOf(row[0]) > -1) {
duplicate = true;
} else {
duplicate = false;
ids.push(row[0]);
}
if (!duplicate) {
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
This assumes that you want to dedupe based on the contents of the first row of you sheet. If not you can adjust the row references from the 0 index to any other index you wish.
I would...
Create a new sheet
For column A, do =Unique(Sheet1!A:A)
Simply use VLOOKUP to populate the other columns. This will deliver the first value associated with the duplicates.
I am trying to index my google sheet, based on an if condition. So, if the 3 column data is not empty, I want the first column of the sheet to get indexed. In the code below, the if statement is working fine, but I am unable to set the value of index in the first column.
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("production");
var data = sheetFrom.getDataRange().getValues();
var count = 0;
var farmerCount = 0;
for(n=3;n<data.length;++n){ // iterate in the array, row by row
if (data[n][2]!=""){
farmerCount++;
data[n][0].setValue(farmerCount);
//sheetFrom.getRange(n, 0).setValue(farmerCount);
}
Thanks in advance.
Range indexing in Google Apps Script is 1 based so you want to use
sheetFrom.getRange(n, 1).setValue(farmerCount);
Possibly n+1 depending on how many header rows you have.