Activate script only if specified columns change - javascript

This thing changes the status of two different columns dependent on each others' values. I want it to only trigger the script when the changes are in these two columns. This spreadsheet will have about 30 people on it and I do not want it activating every time a cell is edited. Please take a look and be aware I'm a complete newbee who pieced this together by Googling.
function onEdit(e) {
var s = e.source.getActiveSheet();
var data = s.getDataRange().getValues();
var data_len = data.length;
var headers = s.getRange(1, 1, 1, s.getLastColumn()).getValues();
var edit_headers = headers[0].indexOf('Edit');
var qc_headers = headers[0].indexOf('QC');
for(var i=0; i<data_len; i++) {
var edit = data[i][edit_headers];
var qc = data[i][qc_headers];
var edit_stat = s.getRange(i+1,edit_headers +1);
var qc_stat = s.getRange(i+1,qc_headers +1);
//Statuses for QC and Edit that change each other
var stat_1 = "Needs QC";
var stat_2 = "Pass";
var stat_3 = "Fail";
var stat_4 = "Fail Fix in Process";
var stat_5 = "Re-QC";
//Switch instead of elseif
switch (edit + qc) //edit + qc stats generate cases below
{
case stat_1: //Needs QC + ""
qc_stat.setValue(stat_1); //qc = Needs QC
break;
case stat_1 + stat_2: //Needs QC + Pass
edit_stat.setValue(stat_2); //edit = Pass
break;
case stat_1 + stat_3: //Needs QC + Fail
edit_stat.setValue(stat_3); //edit = Fail
break;
case stat_4 + stat_3: //Fail Fix in Process + Fail
qc_stat.setValue(stat_4); //qc = Fail Fix in Process
break;
case stat_1 + stat_4: //Needs QC + Fail Fix in Process
qc_stat.setValue(stat_5); //qc = Re-QC
break;
//Below are fail safes
case stat_2 + stat_3: //Pass + Fail; just in case qc Passes a fail
edit_stat.setValue(stat_3); //edit = Fail
break;
case stat_3 + stat_2: //Fail + Pass; just in case qc Fails a Pass
edit_stat.setValue(stat_2); //edit = Pass
break;
}
}
}

You can build an if-statement that checks the columns being edited and return (exit) the script if that column does not match the columns that are allowed to trigger the script (in which case indexOf will return -1).. E.g: let's say you only want to allow column 3 and 6 to trigger the script then do somehting like this:
function onEdit(e) {
var allowedCols = [3, 6];
if (allowedCols.indexOf(e.range.columnStart) === -1) return;
//rest of your code..
...
}
EDIT: If you also want to exclude certain tabs (see question in comments), you can try:
function onEdit(e) {
var allowedCols = [3, 6];
var disallowedTabs = ['Sheet3', 'Sheet5'];
if (allowedCols.indexOf(e.range.columnStart) === -1 || disallowedTabs.indexOf(e.source.getActiveSheet().getName() > -1) return;
//rest of your code..
...

Related

SyntaxError: missing ) after argument list (line 28, file "Code.gs")

i am working on google apps script and i have come across an error which i cannot resolve.
the error occurs at the end on this line return ContentService.createTextOutput("thankyou...
I can't figure out the error. please assist me.
below is the full code
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1CIdq1anGwzUrfrNNd08NtgTR-QeHUDHgb4HOlnobmkk/edit#gid=0");
var sheet = ss.getSheetByName("Examiners");
function doGet(e){
var action = e.parameter.action;
if(action == "in")
return verified(e);
}
function doPost(e){
var action = e.parameter.action;
if(action == "in")
return verified(e);
}
function verified(e){
var id = e.parameter.id;
var values = sheet.getRange(2,1,sheet.getLastRow(),1).getValues();
for(var i = 0 ; i<values.length ; i++){
if(values[i][0] == id){
i=i+2;
var verified = Utilities.formatDate(new Date(), "EAT", "HH:mm:ss");
sheet.getRange(i,3).setValue(verified);
var fullname = sheet.getRange(i,2).getValue();
return ContentService.createTextOutput("Thank You" (fullname)"is verified at" (verified)).setMimeType(ContentService.MimeType.TEXT);
}
}
}
return ContentService.createTextOutput("Id Not Found").setMimeType(ContentService.MimeType.TEXT);
}
There were a few errors in your styling, one was how you concated strings. You used: "Thank You" (fullname)"is verified at" (verified), however this is a syntax error, as you need a + to conact several variables/strings to a string or use a template string, you got two options:
Using +: "Thank You " + fullname + " is verified at " + verified
Using template strings (Note: those are not done in quotation marks but in backticks): `Thank You ${fullname} is verified at ${verified}`
This is what I think how you mean, but I'm unsure about the last return as it was placed outside any function, I just but it one line up in the last function:
var sheet = ss.getSheetByName("Examiners");
function doGet(e) {
var action = e.parameter.action;
if (action == "in")
return verified(e);
}
function doPost(e) {
var action = e.parameter.action;
if (action == "in")
return verified(e);
}
function verified(e) {
var id = e.parameter.id;
var values = sheet.getRange(2, 1, sheet.getLastRow(), 1).getValues();
for (var i = 0; i < values.length; i++) {
if (values[i][0] == id) {
i = i + 2;
var verified = Utilities.formatDate(new Date(), "EAT", "HH:mm:ss");
sheet.getRange(i, 3).setValue(verified);
var fullname = sheet.getRange(i, 2).getValue();
return ContentService.createTextOutput("Thank You" + fullname + "is verified at" + verified).setMimeType(ContentService.MimeType.TEXT);
}
}
return ContentService.createTextOutput("Id Not Found").setMimeType(ContentService.MimeType.TEXT);
}
Furthermore I suggest you format your code better. Do you use an Editor? Many Editors can auto-format you your code, which makes it much more readable
Replace
return ContentService.createTextOutput("Thank You" (fullname)"is verified at" (verified)).setMimeType(ContentService.MimeType.TEXT);
by
return ContentService.createTextOutput("Thank You" + fullname + "is verified at" + verified ).setMimeType(ContentService.MimeType.TEXT);
Resources
Handling text — strings in JavaScript

"The coordinates of the target range are outside the dimensions of the sheet" error when looping [duplicate]

This question already has an answer here:
Copying data script is not working anymore
(1 answer)
Closed last month.
I have 4 sheets. Form, Raw, URL and USA/Japan/Canada. I get the spreadsheet url value from the URL sheet and use 'IMPORTRANGE' in the Raw sheet to transfer the data table. From there, i loop through the table in Raw sheet to check if the values is match from the values in the Form sheet. If it's matched, i will transfer that row in the USA/Japan/Canada sheet.
So i got this code in my google sheets:
var mainWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form');
var continentWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('USA/Japan/Canada');
var rawWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw');
var urlWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('URLs');
var tourName = mainWS.getRange('C4').getValue();
var depDate = new Date(mainWS.getRange('C5').getValue());
var status = mainWS.getRange('C6').getValue();
//extract table data
var url = urlWS.getRange("B4").getValue();
rawWS.getRange('A1').setValue('=IMPORTRANGE("' + url + '","Main Data!A1:AE")');
var dummyHolder = rawWS.getRange("B1:B").getValues();
var lastRow = dummyHolder.filter(String).length;
Logger.log(lastRow);
//loop through the raw extract
for(var i = 2; i <= lastRow; i++){
var dateHolder = new Date(rawWS.getRange("E" + i).getValue());
if(rawWS.getRange("F" + i).getValue() == tourName && rawWS.getRange("I" + i).getValue() == status && dateHolder.getTime() === depDate.getTime()){
var continentLR = continentWS.getLastRow() + 1;
rawWS.getRange('Raw!' + i + ':' + i + '').copyTo(continentWS.getRange(continentLR, 1), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
}
Then i suddenly get the "The coordinates of the target range are outside the dimensions of the sheet" error message once it enters the loop. Specifically in the first line after the for loop:
var dateHolder = new Date(rawWS.getRange("E" + i).getValue());
To be clear, the rawWS where it is looping has 134 records and it registers 134 as its last row. I don't know why i am getting an error here.
When i remove that line, it still gives me an error on the next line. It all errors inside the for loop.
Any ideas?
I haven't tested this but give it a try:
I think that the problem with filter is that it will remove blanks before the end as well but getValues() won't. So you can end up with the wrong length depending upon the dataset.
function unknown() {
var formWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form');
var continentWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('USA/Japan/Canada');
var rawWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw');
var urlWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('URLs');
var tourName = formWS.getRange('C4').getValue();
var depDate = new Date(formWS.getRange('C5').getValue());
var status = formWS.getRange('C6').getValue();
//extract table data
var url = urlWS.getRange("B4").getValue();
rawWS.getRange('A1').setValue('=IMPORTRANGE("' + url + '","Main Data!A1:AE")');
var dummyHolder = rawWS.getRange(1,2,rawWS.getLastRow(),1).getValues();
for(var i=dummyHolder.length-1;i>=0;i--){
if(!dummyHolder[i][0]){
dummyHolder.splice(i,1);
}else{
break;
}
}
//loop through the raw extract
for(var i=2;i<dummyHolder.length; i++){
var dateHolder = new Date(rawWS.getRange(i,5).getValue());
if(rawWS.getRange(i,6).getValue() == tourName && rawWS.getRange(i,9).getValue() == status && dateHolder.getTime() === depDate.getTime()){
var continentLR = continentWS.getLastRow() + 1;
rawWS.getRange(i,1,).copyTo(continentWS.getRange(continentLR, 1), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
}
}
Array Filter Method
Also your last line included sheet name in the range but rawWS is that sheet. So I rewrote the range parameters. Sorry if this doesn't work.

Making an ajax request with jsonp(no jquery)

I need some help on an assignment that I need to do. Basically the question is a number guessing game. We're assigned a number in the interval [0,1023] based on our student number and we have 11 guesses to get the right number. I know I have to use a binary search to get the number, my only problem is connecting to the server and getting a result.
We're given this:
A sample request looks as follows:
http://142.132.145.50/A3Server/NumberGuess?snum=1234567&callback=processResult&guess=800
And also given that the request returns the following parameters:
1: A code to determine if your guess is equal, less than or greater than the number
2: Message string
3: Number of guesses made by my application
This is what I've tried so far, just as a test to get the server request working. All I get in return is "object HTMLHeadingElement"
window.onload = function() {
newGuess();
}
function newGuess() {
var url = "http://142.132.145.50/A3Server/NumberGuess?snum=3057267&callback=processResult&guess=600";
var newScriptElement = document.createElement("script");
newScriptElement.setAttribute("src", url);
newScriptElement.setAttribute("id", "jsonp");
var oldScriptElement = document.getElementById("jsonp");
var head=document.getElementsByTagName("head")[0];
if (oldScriptElement == null) {
head.appendChild(newScriptElement);
} else {
head.replaceChild(newScriptElement, oldScriptElement);
}
}
function processResult(code,message,guesses) {
var code = document.getElementById("code");
var message = document.getElementById("message");
var guesses = document.getElementById("guesses");
code.innerHTML = code;
message.innerHTML = message;
guesses.innerHTML = guesses;
}
EDIT: Current state of my code.
window.onload = function() {
min = 0;
max = 1023;
mid = 0;
setInterval(newGuess,1000);
};
function newGuess() {
mid = Math.floor((max-min)/2);
var url = "http://142.132.145.50/A3Server/NumberGuess?snum=3057267&callback=processResult&guess="+mid;
var newScriptElement = document.createElement("script");
newScriptElement.setAttribute("src", url);
newScriptElement.setAttribute("id", "jsonp");
var oldScriptElement = document.getElementById("jsonp");
var head=document.getElementsByTagName("head")[0];
if (oldScriptElement == null) {
head.appendChild(newScriptElement);
} else {
head.replaceChild(newScriptElement, oldScriptElement);
}
}
function processResult(codeJ,messageJ,guessesJ) {
code = document.getElementById("code");
message = document.getElementById("message");
guesses = document.getElementById("guesses");
code.innerHTML = codeJ;
message.innerHTML = messageJ;
guesses.innerHTML = guessesJ;
if(codeJ == 0){
return;
}else if(codeJ == -1){
min = mid + 1;
}else if(codeJ == 1){
max = mid -1;
}
console.log(mid);
}
Check your variable-names. You are overwriting the function-patameters.
Something like
code.innerHTML = code;
message.innerHTML = message;
guesses.innerHTML = guesses;
just CAN'T work, you should see the problem yourself...

if condition doesn't work with input variable

I have a problem in slideAC(data) function.
If condition seem to have some problem in the picture condition (data[0] == "picture")
I have already try to alert the data for testing the input value by alert(data[0]);
and the result is "picture" as well I have no idea what is the problem??
since other test condition work correctly.
HERE IS THE INPUT DATA IN THE extractData(data <-- array) FUCNCTION
(It's Already Split from other function by use split("\n"))
slide
,- width 400
,- height 300
,- into #slide1
,- picture
,+[pic/001.png]
,+[pic/002.jpg]
,+[pic/003.jpg]
,+[pic/004.jpg]
,
The purpose of the code is extract the words from the above text and generate some code.
function extractData(data){
alert(data);
var n = 0;
var step1 = "";
var step2 = "";
var step3 = "";
var step4 = "";
var picture =[];
//check '#' command by call the first line data
if(data[0].indexOf("slide") !== -1){
for(var i=1; i<data.length; i++){
// alert(n);
switch (n){
case 0:///////////////////////////////////////
// alert("case1");
//extract from '-'
if(data[i].indexOf('-') !== -1){
step1 = data[i].replace('-','');
step2 = step1.split(' ');
step3 = step2.slice(1,step2.length);
//slide Attribute Compiler
n = slideAC(step3);
}else{
alert("out");
}//end of if condition
break;
case 1:///////////////////////////////////////
// alert("case2");
//extract from '+'
if(data[i].indexOf('+') !== -1){
step1 = data[i].replace('+','');
step2 = step1.replace("[","");
step3 = step2.replace("]","");
picture.push(step3);
alert(step3);
}else if(data[i].indexOf('-') !== -1){
step1 = data[i].replace('-','');
step2 = step1.split(' ');
step3 = step2.slice(1,step2.length);
//slide Attribute Compiler
n = slideAC(step3);
}else{
//Error
// alert("wrong pic syntax");
// javascript_abort();
}//end of if condition
break;
}//end of iswitch case
}//end of item for loop
}else if(data[0].indexOf("menu") !== -1){
//Provision
}else if(data[0].indexOf("form") !== -1){
//Provision
}else{
javascript_abort();
}//end of if condition
}//end of syntaxCompiler
//slide Attribute Compiler
function slideAC(data){
// alert(data[0]);
var a = 0
if(data[0] == "width"){
var propWidth = data[1];
// alert(data[0] + " : " + propWidth);
// alert(typeof data);
a = 0;
}else if(data[0] == "height"){
var propHeight = data[1];
// alert(data[0] + " : " + propHeight);
// alert(typeof data);
a = 0;
}else if(data[0] == "into"){
var propInto = data[1];
// alert(data[0] + " : " + propInto);
// alert(typeof data);
a = 0;
}else if(data[0] == "picture"){
a = 1;
}else{
alert("why");
// javascript_abort();
}//end of if condition
return a;
}//end of slide attribute compiler
Do you have some advise ?? Please help
I just want the if condition work correctly
Thanks in advance
PS. Sorry If my wording make you confuse.
I'm guessing there may be space characters around the words. Hard to tell because you haven't shown a good picture of the result of the split, or shown the original input, and how you're splitting it.
If this is the case, you could trim it. I used a switch statement instead of your if/else if/else.
// trim the string-------v
switch(data[0].trim()) {
case "width":
var propWidth = data[1];
// alert(data[0] + " : " + propWidth);
// alert(typeof data);
a = 0;
break;
case "height":
var propHeight = data[1];
// alert(data[0] + " : " + propHeight);
// alert(typeof data);
a = 0;
break;
case "into":
var propInto = data[1];
// alert(data[0] + " : " + propInto);
// alert(typeof data);
a = 0;
break;
case "picture":
a = 1;
break;
default:
alert("why");
// javascript_abort();
}
You'll need a patch for the .trim() method if you support old browsers.
If js says it's false, then it is! You should eval your vars in a debugger to see what is happening. If using Chrome, just place a call to debugger to break and inspect vars values.
http://msdn.microsoft.com/en-us/library/ie/0bwt76sk(v=vs.94).aspx

IE bug with global variables. How to bypass this bug?

As title says i have some problems with IE8 and Javascript. It's known about its bug in interpretation of global variables: simply it does not get them if you don't declare as:
var variable1 = something;
The problem it's i'm trying to make a script that change the body background clicking on a button and i need a global variable wrapping the actual status (what bg-x.png i'm loading). This script work on FF, Safari and Chrome but not, obviously, on IE. Help? (the problem is on the variable "status")
$('#change').click(function() {
var numStates = 2;
var name = $(this).text();
if(!(status)) {
status = parseInt(1,10);
}
if(status<numStates) {
status = parseInt(status,10) + 1;
}
else {
status = parseInt(1,10);
}
alert(status);
var bgvar = null;
switch(parseInt(status,10)) {
case 1: var bgvar = ' #7097ab url(./img/bg-' + status + '.png) top center repeat';
var name = 'Pattern';
break;
case 2: var bgvar = ' #7097ab url(./img/bg-' + status + '.png) top center repeat-x';
var name = 'Sfumato';
break;
default: alert('Default');
}
$('body').css({
background:bgvar,
});
$(this).text(name);
}
);
Working code even with IE (Thanks to Zeta):
$('#change').click(function() {
var numStates = 2;
var name = $(this).text();
// If data-status isn't defined set it to the initial value
if($('body').data('status') === undefined)
$('body').data('status',1);
// Extract the status
var status = parseInt($('body').data('status'),10);
// Handle the status
if(status < numStates)
status++;
else
status = 1;
// Save the status
$('body').data('status',status);
switch(status) {
case 1: bgvar = ' #7097ab url(./img/bg-' + status + '.png) top center repeat';
name = 'Pattern';
break;
case 2: bgvar = ' #7097ab url(./img/bg-' + status + '.png) top center repeat-x';
name = 'Sfumato';
break;
default: alert('Default');
}
$('body').css({
background:bgvar,
});
$(this).text(name);
}
);
status is a predefined member of the window-object and points to the content of the statusbar. Use another variable-name
Since you're already using jQuery you could use .data() instead of global variables:
$('#change').click(function() {
var numStates = 2;
var name = $(this).text();
// If data-status isn't defined set it to the initial value
if($('body').data('status') === undefined)
$('body').data('status',1);
// Extract the status
var status = parseInt($('body').data('status'),10);
// Handle the status
if(status < numStates)
status++;
else
status = 1;
// Save the status
$('body').data('status',status);
/* ... Rest of your code ... */
Note that this won't work in XML documents in IE (according to the jQuery doc).
Do you know when to use »var«?
I just cleaned your code in the follwing ways:
Add "var status;" to make it a local variable
Delete "var" for already defined variables in your switch statement
Delete the unnecessary comma behind "background: bgvar" which will cause errors in IE
$('#change').click(function () {
var numStates = 2;
var name = $(this).text();
var status;
if (!(status)) {
status = parseInt(1, 10);
}
if (status < numStates) {
status = parseInt(status, 10) + 1;
} else {
status = parseInt(1, 10);
}
alert(status);
var bgvar = null;
switch (parseInt(status, 10)) {
case 1:
bgvar = ' #7097ab url(./img/bg-' + status + '.png) top center repeat';
name = 'Pattern';
break;
case 2:
bgvar = ' #7097ab url(./img/bg-' + status + '.png) top center repeat-x';
name = 'Sfumato';
break;
default:
alert('Default');
}
$('body').css({
background: bgvar
});
$(this).text(name);
});
Does it work now?
P.S. Use http://www.jshint.com/ to prevent those kind of errors.

Categories