I have this code that I copied/pasted/modified from the Google Scripts help files:
function DHGreen() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("D3:P43");
var rule = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("DH")
.setBackground("#00ff00")
.setRanges([range])
.build();
var rule2 = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("Mazie")
.setBackground("#0000ff")
.setRanges([range])
.build();
var rule3 = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("Herald")
.setBackground("#9900ff")
.setRanges([range])
.build();
var rules = sheet.getConditionalFormatRules();
rules.push(rule);
rules.push(rule2);
rules.push(rule3);
sheet.setConditionalFormatRules(rules);
}
I feel like there should be a way to do this more efficiently, but since I'm still at the copy/paste, change things and hope it still works phase of learning Google Scripts (much more familiar with VBA), I'm just not sure where to start. Any help is appreciated.
You can use a function to create the rule rather than reapeating that code.
function makeRule(range, whenTextEqualTo, setBackground) {
return SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo(whenTextEqualTo)
.setBackground(setBackground)
.setRanges([range])
.build();
}
function DHGreen() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("D3:P43");
var rules = sheet.getConditionalFormatRules();
rules.push(makeRule(range, "DH", "#00ff00"));
rules.push(makeRule(range, "Mazie", "#0000ff"));
rules.push(makeRule(range, "Herald", "#9900ff"));
sheet.setConditionalFormatRules(rules);
}
Related
I am trying to build a function that formats certain columns of a tab (a sheet within the main sheet) that is titled "Responses - DO NOT EDIT." However, every time I run the script from the menu, I receive the error message: "Script function not found: FormatCWR."
Here's the code, that I've frankensteined...
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{name:"FormatCWR", functionName:"FormatCWR"}];
ss.addMenu("Scripts", entries);
FormatCRW()
}
function FormatCRW() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetCWR = ss.getSheetByName("Responses - DO NOT EDIT");
var data = sheetCWR.getDataRange().getValues();
var newData = new Array();
for(i in data){
sheetCWR.getRange('H2:H').setNumberFormat("mm/dd/yyyy");
sheetCWR.getRange('J2:J').setNumberFormat('$0.00');
sheetCWR.getRange('K2:K').setNumberFormat('$0.00');
sheetCWR.getRange('R2:R').setNumberFormat('$0.00');
sheetCWR.getRange('BD2:BD').setNumberFormat('$0.00');
sheetCWR.getRange('BG2:BG').setNumberFormat('$0.00');
sheetCWR.getRange('BJ2:BJ').setNumberFormat('$0.00');
sheetCWR.getRange('S2:S').setNumberFormat('[h]:[m]:[s]');
sheetCWR.getRange('T2:T').setNumberFormat('[h]:[m]:[s]');
sheetCWR.getRange('BO2:BO').setNumberFormat('[h]:[m]:[s]');
break;
}
};
I assume the function is in a ".gs" file and that it really is there. So it's possible that something is wrong somewhere else. I know a lot people make their menus in a manner that is similar to what you're doing. However, I like doing it this way.
SpreadsheetApp.getUi().createMenu('Scripts')
.addItem('Format','FormatCRW')
.addToUi();
Maybe this will help...Maybe not.
I'm probably missing something here but this function makes no sense to me.
function FormatCRW() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetCWR = ss.getSheetByName("Responses - DO NOT EDIT");
var data = sheetCWR.getDataRange().getValues();
var newData = new Array();//Not used at all
for(i in data){//Why are you looping on every row in the data range when all of the ranges cover all of the rows?
sheetCWR.getRange('H2:H').setNumberFormat("mm/dd/yyyy");
sheetCWR.getRange('J2:J').setNumberFormat('$0.00');
sheetCWR.getRange('K2:K').setNumberFormat('$0.00');
sheetCWR.getRange('R2:R').setNumberFormat('$0.00');
sheetCWR.getRange('BD2:BD').setNumberFormat('$0.00');
sheetCWR.getRange('BG2:BG').setNumberFormat('$0.00');
sheetCWR.getRange('BJ2:BJ').setNumberFormat('$0.00');
sheetCWR.getRange('S2:S').setNumberFormat('[h]:[m]:[s]');
sheetCWR.getRange('T2:T').setNumberFormat('[h]:[m]:[s]');
sheetCWR.getRange('BO2:BO').setNumberFormat('[h]:[m]:[s]');
break;//Why have a loop if your going to break out the very first time?
}
};
It would make a little more sense this way
function FormatCRW() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetCWR = ss.getSheetByName("Responses - DO NOT EDIT");
sheetCWR.getRange('H2:H').setNumberFormat("mm/dd/yyyy");
sheetCWR.getRange('J2:J').setNumberFormat('$0.00');
sheetCWR.getRange('K2:K').setNumberFormat('$0.00');
sheetCWR.getRange('R2:R').setNumberFormat('$0.00');
sheetCWR.getRange('BD2:BD').setNumberFormat('$0.00');
sheetCWR.getRange('BG2:BG').setNumberFormat('$0.00');
sheetCWR.getRange('BJ2:BJ').setNumberFormat('$0.00');
sheetCWR.getRange('S2:S').setNumberFormat('[h]:[m]:[s]');
sheetCWR.getRange('T2:T').setNumberFormat('[h]:[m]:[s]');
sheetCWR.getRange('BO2:BO').setNumberFormat('[h]:[m]:[s]');
}
I'm trying to write a little script to make my coworkers and mine lives easier. I am trying to append lines to a spreadsheet based on information entered into a custom form. The code posted below just the doPost block which should be appending the google spreadsheet.
function doPost(form) {
var PN = form.PartNumber;
var REV = form.Revision;
var DATE = form.RevisionDate;
var DESC = form.Description;
var NOTE = form.PartNotes;
var URL = form.myFile.getURL();
var ss = SpreadsheetApp.openById("ID HERE"); // removed ID for sake of safety (let me be paranoid)
var sheet = ss.getSheetName('Uploads');
sheet.appendRow([PN,REV,DATE,DESC,NOTE,URL]);
}
I am unsure why it isn't writing to the spreadsheet but it isn't throwing me any errors. If you can offer any insight as to what is wrong I would greatly appreciate it; there are many guides online but most seem to be based on deprecated functions/code/etc.
Thanks for your time.
Instead of using doPost, set up a "On form submit" trigger.
You need to get the namedValues to be able to pull specific values and take the first output.
Also, it should be "getSheetByName('Uploads')" .
As pointed out in the previous answer, it is unclear what you are trying to achieve by "form.myFile.getURL();" If you want to get the form url you might as well create it as a string, as it always stays the same.
Here is a working example of your code:
function doPost(form) {
var formResponses = form.namedValues;
var PN = formResponses.PartNumber[0];
var REV = formResponses.Revision[0];
var DATE = formResponses.RevisionDate[0];
var DESC = formResponses.Description[0];
var NOTE = formResponses.PartNotes[0];
//var URL = form.myFile.getURL(); //Not sure what you are tyring to get here as form URL will always be the same.
var URL = "Your form's url"; //You can put the form url in here so it will be pushed in to every row.
var ss = SpreadsheetApp.openById("ID HERE"); // removed ID for sake of safety (let me be paranoid)
var sheet = ss.getSheetByName('Uploads');
sheet.appendRow([PN,REV,DATE,DESC,NOTE,URL]);
}
The form fields are nested in a "parameter" property in the doPost parameter.
So, you should access them using:
function doPost(form) {
var actualForm = form.parameter;
var PN = actualForm.PartNumber;
//etc
To double check all parameters your receiving and their names, you could append to your sheet everything stringfied, like this:
sheet.appendRow([JSON.stringify(form)]);
--edit
This form.myFile.getURL() also looks odd. I guess another good debugging trick you could do is to wrap everything in a try-catch and email yourself any errors you get. For example:
function doPost(form) {
try {
//all your code
} catch(err) {
MailApp.sendMail('yourself#etc', 'doPost error', err+'\n\n'+JSON.stringify(form));
}
}
On form submit
onFormSubmit works. "doPost" looks wrong.
Simple example:
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for(var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("SendGoogleForm")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
}
function SendGoogleForm(e)
{
try
{
Full example - Scroll down to the code http://www.labnol.org/internet/google-docs-email-form/20884/ (Note: example sends email)
Trigger docs: https://developers.google.com/apps-script/guides/triggers/events
Notes: I think the problem is doPost, Does it work with google Forms? Never seen it used with google forms.
First and foremost, thank you everyone who has responded with information thus far. None of the solutions posted here worked for my particular implementation (my implementation is probably to blame, it is very crude), but they definitely set me down the path to a working version of my form which we now lightly use. I have posted some of the code below:
function sheetFill(form, link) {
try {
var formResponses = form.namedValues;
var toForm = [0,0,0,0,0,0,0];
for (i=0;i < form.PartNumber.length;i++){
toForm[0] = toForm[0]+form.PartNumber[i];
}
... (several for loops later)
var d = new Date();
var ss = SpreadsheetApp.openById("IDHERE");
var sheet = ss.getCurrentSheet;
ss.appendRow([toForm[0], toForm[1], toForm[2], toForm[3], toForm[4], toForm[5], toForm[6], link, d]);
} catch(err) {
MailApp.sendEmail('EMAIL', 'doPost error', err+'\n\n'+JSON.stringify(form));
}
}
It is not very versatile or robust and isn't elegant, but it is a starting point.
sorry if this is an elementary question, but I just can't get this to work the way I need.
I have a script that essentially consists of 3 parts:
1). Removes all protection in a sheet
2). Executes some copying functions (since ranges are protected I need to remove the protection first #1)
3). Sets the protection back up after #2 is finished.
Here's my code:
First clears protection
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
Second clears data in cells
var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'COST REPORT');
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
Third sets protection
var ss = SpreadsheetApp.getActive().getSheetByName('COST REPORT');
var costReportCOGS = ss.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
var costReportPurchaseEnding = ss.getRange('D11:E16');
var protection = costReportPurchaseEnding.protect().setDescription(
'costReportPurchaseEnding');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
I've cut some of the script down for ease of debugging, but basically I need the script to Execute & Finish in this order, one by one. If you just try running the script the way it is, the protection doesn't get removed and I get the error "trying to edit protected range...."
If I run each block by itself then it works perfect, but that consists of 3 different scripts the user has to run and I need it all in one.
Thanks in advance!
Sean.
Something like this?
function removeProtection() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
};
function clearRangeData() {
var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'COST REPORT');
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
};
function weeklyFileRangeProtection() {
//COST REPORT
var ss = SpreadsheetApp.getActive().getSheetByName('COST REPORT');
var costReportCOGS = ss.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
};
You are having issues because for each function you are calling SpreadsheetApp.getActiveSpreadsheet . Each time you make this call you create a virtual "copy" of the spreadhseet, and the changes you make to this copy are only passed to the version in Google's servers once the whole script is finished. Hence, if you manually run each of the 3 function that the workflow:
Run function 1 -> script finished -> update the spreadsheet in the server -> run function 2 (which now gets the updated spreadsheet) -> script finished -> update the spreadsheet in the server -> run function 3 (which now gets the re-updated spreadsheet) -> script finished -> update the spreadsheet in the server
Now, if you run the three functions, the way the script is here is what happens:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT'); this creates a virtual copy of the spreadsheet -> your code removes the protection from this copy and the server spreadsheet is not modified -> you call again var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT'); which create a new copy of the server spreadsheet, which hadn't its protections removed yet -> your code tries to clear the data on this copy, which triggers the error.
As #Cameron Roberts suggested in his answer Spreadsheet.flush() between the calls will solve the issue, because if forces the changes to be synced to the spreadsheet in the server. But you will have another "problem", which is the amount of copies you are calling, the .getActiveSpreadsheet() is very time consuming! It is better if you make only one call, store in a variable (you already do that, it is your variable ss) and make all the edits to that.
Your code will end up looking like this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var costReport = ss.getSheetByName('COST REPORT');
//First clear protection
var protections = costReport.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
};
};
//Second clears data in cells
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
//Third sets protection
var costReportCOGS = costReport.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
};
var costReportPurchaseEnding = costReport.getRange('D11:E16');
var protection = costReportPurchaseEnding.protect().setDescription(
'costReportPurchaseEnding');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
};
This method also applies to Google Docs, which does NOT have a similar .flush() method for updating the server version.
I believe you have misdiagnosed the issue slightly. The code is already running in the correct order, but the protection is simply not being removed before the write calls are executed, due to the nature of Google's underlying architecture.
The comments steering you towards asynchronous behaviour are not helpful in this case, they do make sense from a Javascript perspective but are not the issue here, this is an Apps Script / Google Sheets issue, none of the functions you are calling are asynchronous.
I have two suggestions, one is to try calling SpreadsheetApp.flush() after the protections are removed. The other is to use Utilities.sleep() to artificially pause the script for a brief period after executing the remove() calls.
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush()
https://developers.google.com/apps-script/reference/utilities/utilities#sleep(Integer)
This script works fine, but it keeps creating a new process in the task manager 'process' section. Not the Applications, just the Processes. I thought I was using the write 'quit' options but clearly not! This is the code:
<script>
function gbid(s) {
return document.getElementById(s);
}
function GetData(cell,row){
var excel = new ActiveXObject("Excel.Application");
var excel_file = excel.Workbooks.Open("44227.xls");
var excel_sheet = excel.Worksheets("sheet1");
gbid('span1').innerText = excel_sheet.Cells(93,1).Value;
gbid('span2').innerText = excel_sheet.Cells(95,3).Value;
gbid('span3').innerText = excel_sheet.Cells(94,4).Value;
gbid('span4').innerText = excel_sheet.Cells(95,4).Value;
gbid('span5').innerText = excel_sheet.Cells(95,5).Value;
gbid('span6').innerText = excel_sheet.Cells(97,1).Value;
gbid('span7').innerText = excel_sheet.Cells(99,3).Value;
gbid('span8').innerText = excel_sheet.Cells(98,4).Value;
gbid('span9').innerText = excel_sheet.Cells(99,4).Value;
gbid('span10').innerText = excel_sheet.Cells(99,5).Value;
excel_file.Close();
excel.Application.Quit();
excel.Close();
}
</script>
<body onload="GetData();" />
The rest is just tables and such so no biggie. No significant code or anything. As you can see I've tried three different types of lines, and I've even tried them by themselves. NADA! I've even tried them without the ';' at the end! I've searched this site and used those examples but IT JUST WONT WORK! It'll keep creating new processes! Is it because I used:
new ActiveXObject("Excel.Application"); ?
Starting using a rule and a simple javascript in Alfresco is quite easy but i'm stuck on trying to start a workflow through javascript adding a resource.
My goal is to add the document (or documents) used to start the flow, so i can obtain a reference in the "OW_ATTACHMENTS" of the Alfresco BPM of the Alfresco WorkDesk.
I've tried many times with the bpm:workflowpagckage or bpm:package with no luck....help!
Edit:
function startWorkflow(name,docNode)
{
var workflow = actions.create("start-workflow");
workflow.parameters["bpm:workflowPackage"] = docNode;
workflow.parameters.workflowName = "activiti$AdHocactivitiTimer";
workflow.parameters["bpm:assignee"] = people.getPerson("admin");
workflow.parameters["bpm:workflowDescription"] = "test";
workflow.parameters["bpm:workflowPriority"] = "2";
workflow.parameters["bpm:sendEMailNotifications"] = true;
workflow.parameters["initiator"] = people.getPerson("admin");
var today = new Date();
var duedate = today.getDate() + 1;
workflow.parameters["bpm:workflowDueDate"] = duedate;
workflow.execute(document);
}
function main()
{
var docNode = search.findNode(document.nodeRef);
var name = document.name;
startWorkflow(name,docNode);
}
main();
thanks!
The bpm:package or bpm_package is not available before start.
So what happens you're document is added to bpm_package.
And in your workflow you can access bpm_package as a variable. And with bpm_package.addNode(doc); you can add nodes.
These nodes can be found through search/childbynamepath/xpath etc.
If you don't use the action the other way is:
var workflowAction = workflow.getDefinitionByName('activiti$AdHocactivitiTimer');
var package= workflow.createPackage();
package.addNode(document);
workflowAction.startWorkflow(package, parameters);