I'm working on a small project in Google Apps Scripts using Google spreadsheet / Google Forms.
I want to help students in large class sizes find people to study with by entering the class into a Google Form. From there they would be automatically emailed a list of people taking the same class as them, who are also looking for people in the same class or lecture to study with. The student inputs their name, school Id number, email, class CRN#, Class Name and instructor. Its put into the Google spreadsheet and I manipulate it like a CSV file.
I want to use the onEdit() trigger so that when information is added or edited, an email will be sent out. I'm not understanding how the onEdit() event trigger works.
This is my code for the class sorting:
function studyBudy2() {
var ss =
SpreadsheetApp.openById("1ZxTdRdhy0iR6HH7jB75KL4g-SCr7nPZEilXrzECe7yg").getActiveSheet();
var numOfStu = ss.getLastRow();
/*var range = ss.getRange(2, 4, numOfStu-1);
var values = range.getValues();
// get emails out of spreadsheet
for (var row in values) {
for (var col in values[row]) {
emails = values[row][col]
Logger.log(emails);
// sends emails
MailApp.sendEmail(emails, "pls work","now");
}
}
*/
var theMass = []
var rAnge = ss.getRange(2,1,numOfStu-1,7);
var vAlues = rAnge.getValues()
for (var row in vAlues) {
var student = [];
var buzznumber = vAlues[row][2];
var classCRN = vAlues[row][4];
var class = vAlues[row][5];
var proffessor = vAlues[row][6];
student.push(buzznumber);
student.push(classCRN);
student.push(class);
student.push(proffessor);
theMass.push(student);
}
for (var i = 0; i < numOfStu-2; i++){
var theStudent = theMass[i]
var theCRN = theStudent[1];
var theClass = theStudent[2];
var theProffessor = theStudent[3];
var theBuzznumber = theStudent[0];
Logger.log(theClass);
for (var j= 1; j < numOfStu-1; j++){
if (i+j <= numOfStu-2 && theMass[i+j][1] == theCRN && (i+j != i)){
Logger.log("Youre in the same Section!")
}
else if (i+j <= numOfStu-2 && theMass[j+i][2] == theClass && theProffessor != theMass[j+i][3] && (i+j != i)){
Logger.log("Youre taking the same Course!");
}
else if(j+i <= numOfStu-2 && theClass == theMass[j+i][2] && theProffessor == theMass[j+i][3] && (i+j != i)){
Logger.log("Youre in the same lecture!");
}
else if (j+i > numOfStu-2){
continue;
}
}
}
}
I'm thinking the onEdit() function should be implemented as another function but does it go in another function or in this studyBudy2 function?
function onEdit(e) {
var activeSheet = SpreadsheetApp.openById("1ZxTdRdhy0iR6HH7jB75KL4g-SCr7nPZEilXrzECe7yg").getActiveSheet();
var row = e.range.getRow();
var studentNum = row+1;
}
onEdit is a reserved function name which purpose is to declare a function to be used as a simple trigger.
function onEdit(e){
//do something
}
Besides creating an onEdit simple trigger, we could create a on-edit installable trigger. Functions to be used for installable triggers could be named as we wish but to avoid confusions it's better to avoid using reserved functions names and spreadsheet build-in functions names.
If studyBudy2() function does what you needs to triggered when a edit is made on the spreadsheet, you could rename it as onEdit, declara an onEdit function that call studyBudy2() or create an installable trigger that calls studyBudy2().
Bear in mind that only edits made by users directly on the spreadsheet will fire a simple/installable on edit trigger. If you want something fire when a form response is submitted then you should use a on form submit installable trigger.
For further details please read https://developers.google.com/apps-script/guides/triggers/
Related
Im having trouble with an script that posts the outcome twice, I have reviewed the script but I cant find the issue.
The script gets the "Timestamp", "Cell address", "Column label" and "Value entered" and post it on the sheet named "Tracker" but it gets posted twice
function onEdit() {
var sheetsToWatch = ['Responses'];
// name of the sheet where the changelog is stored
var changelogSheetName = "Tracker";
var timestamp = new Date();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getActiveCell();
var sheetName = sheet.getName();
// if it is the changelog sheet that is being edited, do not record the change
if (sheetName == changelogSheetName) return;
// if the sheet name does not appear in sheetsToWatch, do not record the change
var matchFound = false;
for (var i = 0; i < sheetsToWatch.length; i++) {
if (sheetName.match(sheetsToWatch[i])) matchFound = true;
}
if (!matchFound) return;
var columnLabel = sheet.getRange(/* row 1 */ 1, cell.getColumn()).getValue();
var rowLabel = sheet.getRange(cell.getRow(), /* column A */ 1).getValue();
var changelogSheet = ss.getSheetByName(changelogSheetName);
if (!changelogSheet) {
// no changelog sheet found, create it as the last sheet in the spreadsheet
changelogSheet = ss.insertSheet(changelogSheetName, ss.getNumSheets());
// Utilities.sleep(2000); // give time for the new sheet to render before going back
// ss.setActiveSheet(sheet);
changelogSheet.appendRow(["Timestamp", "Cell address", "Column label", "Value entered"]);
changelogSheet.setFrozenRows(1);
}
changelogSheet.appendRow([timestamp, cell.getA1Notation(), columnLabel, cell.getValue()]);
}
Google's method documentation makes it seem like you can programmatically check for the existence of some other user's trigger with a function like this:
function triggerLogger() {
// Read installed triggers for the project.
var triggers = ScriptApp.getProjectTriggers();
var installedReport = {};
triggers.forEach(function (t) { installedReport[t.getUniqueId()] = {
event: t.getEventType(),
calledFunction: t.getHandlerFunction(),
source: t.getTriggerSource(),
source_id: t.getTriggerSourceId() || "Time-based triggers have no source id."
}});
// Read "simple" triggers for the project by checking for globals that start with "on".
var simpleReport = {};
for (var thing in this)
if (thing.indexOf("on") === 0 && thing.length > 2)
simpleReport[String(thing)] = {def: this[thing]};
var possibleSimple = Object.keys(simpleReport).length,
message = "Trigger report: " + triggers.length + " installed";
if (possibleSimple) message += ", " + possibleSimple + " possible simple triggers";
message += ".";
// Log to Stackdriver (so the report can be viewed sensibly).
console.log({
message: message,
installed: Object.keys(installedReport).length ?
installedReport : "No detected installed triggers.",
simple: possibleSimple ?
simpleReport : "No simple triggers used",
reportRunAs: Session.getActiveUser().getEmail()
});
}
But the getProjectTriggers() method, despite claiming to get all of the current project's installed triggers, will only obtain your installed triggers for the document, even if you are the owner of the document.
Note that this behavior is accepted as a bug (meaning someone, someday will fix it). If you would like to feel that you have done your part to accelerate that timeline, please star that issue:
I was coding using the google scripts, when I came across a problem I've been struggling with for a couple days now. I am using Code.gs (a default page in creating a web app in google), when I called in data from a google spreadsheet to try and display it on a webpage. I had no problems with calling in the data add storing it into a array but now I am struggling with trying to return it to my javascript code. Can this be done or is there something else I can do to fix it? My code is below.
function getContents()
{
var sheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xum5t4a83CjoU4EfGd50f4ef885F00d0erAvUYX0JAU/edit#gid=0&vpid=A1');
var range = sheet.getDataRange();
var values = range.getValues();
for (var i = 0; i < values.length; i++) {
var education = [];
for (var j = 0; j < values[i].length; j++) {
if (values[i][j]) {
if(j==1){
education[education.length] = values[i][j];
}
}
}
}
Logger.log(education);
return education;
}
From that Code.gs code i want it to return it to a Javascript function that says this:
function onNew(){
var input = google.script.run.getContents();
for(var = 0; i<input.length; i++)
{
$("#main").append("<div id='class'>"+input[i]+"</div>);
}
}
and whenever I try to run it says that it causes an error because it is undefined. Thanks in advance! Anything helps!
You need to use the withSuccessHandler(). Your variable input will not receive the return from google.script.run.getContents()
Separate out the client side code into two functions:
HTML Script
function onNew() {
google.script.run
.withSuccessHandler(appendEducationHTML)
.getContents();
};
function appendEducationHTML(returnedInfo) {
console.log('returnedInfo type is: ' + typeof returnedInfo);
console.log('returnedInfo: ' + returnedInfo);
//If return is a string. Convert it back into an array
//returnedInfo = returnedInfo.split(",");
for (var = 0;i < returnedInfo.length; i++) {
$("#main").append("<div id='class'>"+returnedInfo[i]+"</div>);
};
};
Here's what I'm trying to accomplish:
A project manager fills out a Google Form. It spits the result to a spreadsheet, and I want to manipulate that data.
The first question/cell is what social media the product is using, with a multiple choice checkbox.
If someone checks off Facebook and Twitter, the cell returns "Facebook, Twitter" and I'm having trouble searching the cell for "Twitter" since it's not first.
Here's what I have so far:
function testplan() {
var mainsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var testplan = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TestPlan");
var socialData = mainsheet.getRange(3, 3).getValues();
var socialDataText = socialData.length;
var fbSocial = "Facebook";
var twitSocial = "Twitter";
for (var i = 0; i < socialDataText; i++) {
if (socialData[i][0] == fbSocial) {
testplan.getRange("A15").setValue("User can log into the app with Facebook.");
testplan.getRange("A16").setValue("User can share content from the app with Facebook.");
} {
return 0;
};
};
for (var i = 0; i < socialDataText; i++) {
if (socialData[i][0] == twitSocial) {;
testplan.getRange("A17").setValue("User can log into the app with Twitter.");
testplan.getRange("A18").setValue("User can share content from the app with Twitter.");
} {
return 0;
};
};
The first command to look for "Facebook" works, because it's the first bit of text. But anything after it isn't able to be found. I've searched a lot and have found things that are close, but nothing that works the way I'm expecting it to. It's probably a command or something really obvious that I'm not seeing.
try
function testplan() {
var mainsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var testplan = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TestPlan");
var socialData = mainsheet.getRange(3, 3).getValues();
var socialDataText = socialData.length;
var fbSocial = "Facebook";
var twitSocial = "Twitter";
for (var i = 0; i < socialDataText; i++) {
if (socialData[i][0].indexOf(fbSocial) > -1) {
testplan.getRange("A15").setValue("User can log into the app with Facebook.");
testplan.getRange("A16").setValue("User can share content from the app with Facebook.");
};
if (socialData[i][0].indexOf(twitSocial) > -1) {;
testplan.getRange("A17").setValue("User can log into the app with Twitter.");
testplan.getRange("A18").setValue("User can share content from the app with Twitter.");
};
};
};
for simplicity
I have a page where you can invite teams. Clicking "Invite teams" makes a popup box appear showing a search input. The search-function is AJAX based. When a team is found through your search word(s), you'll have to click on the team whereupon the team will be showed in a "Invited-teams"-box.
It works in a way that when you "add" the team, a hidden input field is generated containing the team's ID as a value. The problem is that with my current code, it is possible to add the same team as many times as you wish. I should be possible to check, if the team can be found in the hidden-input-data. If it already exists, it should not be possible to add the sane team.
My current javascript-code can be found beneath here. Please notice that I have tried to make the code that checks the team, but it doesn't work.
function addTeam(tid) {
// Grab the input value
var teamName = document.getElementById(tid).innerHTML;
var teamID = document.getElementById(tid).id;
// If empty value
if(!teamName || !teamID) {
alert('An error occured.');
} else {
//Tried to do the "team-adlready-added"-test, but it doesn't work
var stored_teams = $t('#store-teams').getElementsByTagName('input');
for (var i = 0; i < stored_teams.length; i++) {
var stored_team = stored_teams[i];
if(stored_team.value == teamID) {
break;
var team_already_added = 1;
}
alert(team_already_added);
}
if((team_already_added) || team_already_added != 1) {
// Store the team's ID in hidden inputs
var store_team = document.createElement('input');
store_team.type = 'hidden';
store_team.value = teamID;
// Append it and attach the event (via onclick)
$t('#store-teams').appendChild(store_team);
// Create the teams with the value as innerHTML
var div = document.createElement('div');
div.className = 'team-to-invite';
div.innerHTML = teamName;
// Append it and attach the event (via onclick)
$t('#teams').appendChild(div);
}
div.onclick = removeTeam;
}
return false;
}
Thanks in advance.
I just want to give you a hint for a possible solution without html elements.
You can create a new functional object for team:
var Team = function (id, name) {
this.name = name;
this.id = id;
}
Create an array which will contain teams:
var TeamList = [];
Add you Teams:
TeamList.push(new Team(1, "Team 1"));
TeamList.push(new Team(2, "Team 2"));
TeamList.push(new Team(3, "Team 3"));
TeamList.push(new Team(4, "Team 4"));
Write a function which loops trough the list of teams and checks with the id if a team already exists:
function containsTeam(id) {
for (var i = 0; i < TeamList.length; i++) {
if (TeamList[i].id == id) {
return true;
}
}
return false;
}
Just check it:
containsTeam(1); //returns true
containsTeam(5); //returns false
Have a look at the jsFiddle DEMO and open the console to see the output.
EDIT: In addition, to remove an element you can write a function which looks pretty much the same as the containsTeam function. Just use array.splice instead of returning true:
function removeTeam(id) {
for (var i = 0; i < TeamList.length; i++) {
if (TeamList[i].id == id) {
TeamList.splice(i, 1);
}
}
}
And remove a team:
removeTeam(3);
Your variable scope is off.
You declare team already added in the wrong spot.
Declare it with team name and team id and it will get you in the right direction
Below is a script I am using for a Google Docs Spreadsheet.
These links show what I am doing:
http://i.stack.imgur.com/uGik7.png
http://i.stack.imgur.com/AbKnQ.png
How can I set up a "flag" so that when I run this script a second time, it doesn't add the perviously added stock items?
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Purchase Orders");
var sheet2 = ss.getSheetByName("Inventory");
var data = sheet1.getDataRange();
var i_data = sheet2.getDataRange();
var lastRow = data.getLastRow();
var iLastRow = i_data.getLastRow();
for (i=1;i<=lastRow;i++) {
if (data.getCell(i, 5).getValue() == "stock"){
for (n=1;n<=iLastRow;n++){
if (data.getCell(i,3).getValue() == i_data.getCell(n,3).getValue()) {
i_data.getCell(n, 1).setValue(i_data.getCell(n,1).getValue() + data.getCell(i,2).getValue());
}
}
}
}
}
I guess I'm trying to do this: Once the item has been added to inventory, the script adds an x to column i of that line. Then when the script is run again, it skips over the lines with an x in column i
Designate a cell to hold the flag value, and have the script check that particular cell for the flag value.
In JavaScript, functions are objects. Objects have properties. So, decorate your function:
function myFunction() {
if (!myFunction.alreadyDoneRunIt) {
alert('bapt uia');
myFunction.alreadyDoneRunIt = true;
}
}
for (var i = 0; i < 10; i++) {
myFunction(); // alerts once
}