Copy range in google docs to another sheet - google-app-engine

I have Google form that gets filled in by a few users. Works great but has it's limitations.
I'd like to copy the data entered from the active sheet to a new sheet called "work", all information except the first row that is. In the first row I have a few array formulas that populate some cells as new data is entered on the active sheet.
The second sheet (work) has a header row with all the formatting, data validation, some formulas etc (row 1). This information can not be applied when a new record is added via the form.. so I am told..
Thus, once the data has been copied from the active sheet (called active) I'd like the new data to be formatted as per the heading row (row 1) of the "work" sheet with all the formatting, validation, formulas etc being applied to the new data.
Is this doable? I am a noob when it comes to scripting so a complete solution would be highly appreciated.
here is a sample form you can play with
https://docs.google.com/spreadsheet/ccc?key=0AplugTacg-08dFNRUHROSW82bDhESkxBdjVTV0NOLUE
First thing i noticed one can not just copy/paste as the array formulas will bong things up so it has to be a paste special - values only
Any help greatly appreciated.

I'm struggling a bit with the logic behind what you're doing, but I've attempted a solution in sheet 'work2' in this copy of your spreadsheet. Perhaps have a play and report back what's not right or missing.
The script is this:
function onFormSubmit(e) {
var sheet = SpreadsheetApp.getActive().getSheetByName('work2');
var nextRow = sheet.getRange(sheet.getLastRow() + 1, 1, 1, 9);
sheet.getRange(2, 1, 1, 9).copyTo(nextRow);
var sLength = e.values[2].length;
var huuh = e.values[3] * sLength;
var pending = e.values[3] * e.values[3] / huuh;
var nextMonth = e.values[3] + pending;
nextRow.setValues([[e.values[0], e.values[1], huuh, e.values[2], sLength, e.values[3], 'Please select action', pending, nextMonth]]);
}
and has an "on form submit" trigger attached to it.

Related

Remove and add protection within onEdit script

CURRENT SITUATION
As an owner I've created a spreadsheet that makes an editor of everyone who has received the link. However there are some partially protected sheets with a few unprotected columns, making it possible for these editors to change values. I have an onEdit function that automatically sorts the entire range of a sheet when a cell has been edited by user.
PROBLEM
Unfortunately, since these sheets are partially protected, the AUTOSORT does not work. I need to add something to the script so that when the onEdit is triggered, the activesheet becomes unprotected and the AUTOSORT can do its job. After that the protection is added again (with a few columns as an exception). I don't want everyone to lose their editors rights after this. So it needs to go back to normal.
Script that I tried so far but not working:
function onEdit() {
if (e.range.columnStart == 3 && e.range.getValue() != '') {
var sheets = ["FASHION NL", "FASHION BE","KIDS & UNDERWEAR BNL" ,"NEW BUSINESS BNL" ,"SPORTS & SHOES BNL", "HD&E BNL"]; // Please set your expected sheet names.
var sheet = e.range.getSheet();
if (sheets.includes(sheet.getSheetName())) {
var range = sheet.getRange("A5:bY600");
var spreadsheet = SpreadsheetApp.getActive();
var allProtections =
spreadsheet.getActiveSheet().getProtections(SpreadsheetApp.ProtectionType.SHEET);
var protection = allProtections[0];
protection.remove();
range.sort({ column: 11, ascending: true });
e.source.toast('Sort complete.');
}
}
var protection = spreadsheet.getActiveSheet().protect();
protection.setUnprotectedRanges([spreadsheet.getRange('AK:AK'),
spreadsheet.getRange('BN:BN')])
var editors = SpreadSheet.getEditors();
for (var i = 0; i < editors.length; i++) {
SpreadSheet.removeEditor(editors[i])
}
}
CLARIFICATION PROBLEM
It does not give me an error, but script fails to sort the data range.
SAMPLE SHEET STRUCTURE
Trigger is on column C (3)
Script is created in a way that it reflects whether the Activesheet where the edit takes place is one of the predetermined range of sheets.
You should keep all your permissions as they're and set the function as if it's run by yourself (delete all the parts that have to do with removing and adding permissions). Call it other way than onEdit, for example autoSort(), and set an installable trigger run by event. You can read about it here
The sorting then would be run as it was done by you but triggered by other users' changes. Give it a try and let me know!

How do I read numbers with appscript from a google sheet and want to use the number as formatted on another sheet"

I am doing a dependant dropdown list in google sheets using a script.
The source sheet data is read into an array, The destination sheet pulls the dropdown options from the aray.
The numbers from the source sheet are formatted as degrees; 0°, 45°, 90°, 180°.
When the are displayed in the dropdown on the destination sheet the degree symbol is removed and the 0 option doesn't show as an option at all. so I get 45, 90, 180. If I format the destination cell as percent, the the chosen option doesn't match the validation. and I still can't get the 0°.
How can I pass the formatting with the numbers so everything works correctly?
I was thinking I need to do something with setNumberFormat('##0"°"'), but I don't know how.
This is how I am creating the data from the array:
var ws = SpreadsheetApp.getActiveSpreadsheet() .getSheetByName(mainWsName) ;
var wsOptions = SpreadsheetApp.getActiveSpreadsheet() .getSheetByName(optionsWsName) ;
var options = wsOptions.getRange(3, 2,wsOptions.getLastRow()-2, 5).getValues();
var optionsFormat = wsOptions.getRange(3, 2,wsOptions.getLastRow()-2, 5).getNumberFormat()
This is how the data is being retrieved from the array:
var filteredOptions = options.filter(function(o){ return o[0] === firstLevelColValue && o[1] === val });
var listToApply = filteredOptions.map(function(o){ return o[2] });
var cell = ws.getRange(r, thirdLevelColumn) ;
applyValidationToCell(listToApply,cell);
This is my first time asking a question here, I hope I have given the information necessary to solve my problem. Let me know if there is additional information needed.
Thanks
Use getDisplayValues() instead of getValues()
This will allows you to retrieve the values in exactly the same way as they are displayed in the spreadsheet.

Google Sheets - Allow only one checkbox to be checked when the boxes are placed in specific cells across a wide range

I need a simple script for Google Sheets to allow only one of 6 checkboxes to be checked at a time. The end user will check a checkbox and should see the one they checked before turn unchecked or FALSE when they check the new one. The "problem" for a newbie like is me that the checkboxes will be asymmetrically located. They are in cells D14, D30, J14, J32, P14 and P30. I also need to duplicate this sheet a number of times, so preferably the script should work on any of the duplicates I make the same way. The cells will always be these six cells in every sheet.
I've seen many posts about this subject and tried to use the example scripts to my problem without success, so I want to ask specifically about my spreadsheet.
Here is a link to a draft version of my sheet with the locations of the checkboxes:
https://docs.google.com/spreadsheets/d/1PtxetS-Gyv7LyMD19yF3NuWZ24RvqUjyK42SmQTttiU/edit?usp=sharing
Thank you,
Lassi
You can set up an onEdit() trigger that will:
Check whether the cell edited is a checkbox (by verifying its range).
Check that the new value for the cell is TRUE (the checkbox has been enabled).
In case both of 1 and 2 apply, unset the rest of the defined checkboxes in the same sheet.
Note that the execution of the script may be a bit slow (due to Google Apps Script limitations) and that the script will work independently for each of the Sheets in your workbook.
Code
var CHECKBOX_CELLS = ["D14", "J14", "P14", "D30", "J32", "P30"];
function onEdit(e) {
var range = e.range;
var checkboxIndex = CHECKBOX_CELLS.indexOf(range.getA1Notation());
if (checkboxIndex > -1 && range.getValue() == true) {
var sheet = range.getSheet();
for (var i=0; i<CHECKBOX_CELLS.length; i++) {
if (i==checkboxIndex) continue;
sheet.getRange(CHECKBOX_CELLS[i]).setValue(false);
}
}
}

How do I add my timer formula back into Google spreadsheet for column of cells?

We had originally gotten help from a Google developer a year or so back on how to add a timer to field when a certain cell is changed, etc.
Somehow, it was deleted or defaulted, but I was lucky enough to find the equation on one of our saved discussion boards. Can someone possibly help integrate code
if (sheetName == "Driver Status" && [4, 9, 14, 19, 24].indexOf(column) > -1 && row > 3)
into our spread sheet again?
You can put out your JS code to be executed when the sheet is edited then you analyze the event object.
Here's an example from GoogleApps Script API documentation
function onEdit(e){
// Set a comment on the edited cell to indicate when it was changed.
var range = e.range;
range.setNote('Last modified: ' + new Date());
}
You can then check if that certain cell was changed or not in if it was you can trigger your timer.

Google Forms as Multiple Choice Quiz - How to Provide Results

I've built a google form for a multiple choice quiz, with a linked spreadsheet for results, which works very well. I have a specific problem, which is that I'd like to present the user's results to them (i.e. how many answers they got right/wrong). The approach I've taken so far is:
create an extra sheet on the spreadsheet with a formula to calculate the number of correct answers for each response. This gives me two columns "Full Name" and "Scores"
embed the form into a google site
create a google apps script to read the results sheet and display output
embed the above into the same site below the form as an Apps Script Gadget
Currently I am able to display all of the results recorded so far. See here:
https://sites.google.com/site/mcqtest123/home
The script looks like:
// Script-as-app template.
function doGet() {
var app = UiApp.createApplication();
var title = app.createLabel("Survey Results").setStyleAttribute("fontSize","16px");
app.add(title);
//readRows(app);
calculateScores(app);
return app;
};
function calculateScores(app) {
var sheet = SpreadsheetApp.openById("0AlNR-ou0QtandFFzX1JCU1VRdTl0NVBRNTFjOUFhd1E");
var responseSheet = sheet.getSheetByName("Form Responses");
var allData = responseSheet.getDataRange().getValues();
var correct = allData[1];
var responses = allData.slice(2);
//Logger.log("Timestamp, name, score");
Logger.log("Name, Score");
for (var i = 0; i < responses.length; i++) {
var timestamp = responses[i][0];
var name = responses[i][1];
var score = 0;
for (var j = 2; j < correct.length; j++) {
if(responses[i][j] == correct[j]) {
score += 1;
}
}
//var output = timestamp + ", " + name + ", " + score + "/" + correct.length
var output = name + ", " + score + "/" + correct.length
print(app, output);
}
};
function print(app, line) {
Logger.log(line);
app.add(app.createLabel(line));
};
So this leaves two problems:
When the page loads, it loads the scores for all the respondents. I'd like to be able to present only the score for the person who filled out the form.
The scores don't get updated when the form is completed - only when the page is refreshed.
For problem 1), I wondered if there was some way to access the data in the form iframe (e.g. using document.getElementById('targetFrame'), except that google scripts don't seem to have access to the document model) to only display results of the person whose full name matches the name in the form (of course you could then view someone else's results if you know what they'd put as their full name, but without using the timestamp I don't see away round this).
For problem 2), I wondered if there was some way to trigger the script when the responses sheet was updated. However when I go to the spreadsheet and Tools->Script Manager I get the message "No scripts found", so I don't know how to add this trigger.
If you make your own form using HtmlService or UiApp and then that POSTing to your script to populate the spreadsheet, then you can generate a UID in a hidden field and use this to determine the results someone needs to see.
This will be the results as instant feedback to their answers to the quiz. To see these at a later date, you could then also add a bookmarkable link that also included that UID as a parameter. So your doGet() would look for a e.parameters.uid for example.
From Google Forms as they stand I am not so sure. you could potentially, with the new form styles, offer a pre-filled field with such a UID, but the route from form submission to your webapp is again unclear.

Resources