function doGet(e){
Logger.log("--- doGet ---");
var tag = "",
value = "";
try {
// this helps during debuggin
if (e == null){e={}; e.parameters = {tag:"test",value:"-1"};}
tag = e.parameters.tag;
value = e.parameters.value;
// save the data to spreadsheet
save_data(tag, value);
return ContentService.createTextOutput("Wrote:\n tag: " + tag + "\n value: " + value);
} catch(error) {
Logger.log(error);
return ContentService.createTextOutput("oops...." + error.message
+ "\n" + new Date()
+ "\ntag: " + tag +
+ "\nvalue: " + value);
}
}
// Method to save given data to a sheet
function save_data(tag, value){
Logger.log("--- save_data ---");
try {
var dateTime = new Date();
// Paste the URL of the Google Sheets starting from https thru /edit
// For e.g.: https://docs.google.com/..../edit
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1HYJRHfJVgZp16xYt4fipR1bH2BudhuQ4UrDhAf1rBKw/edit");
var dataLoggerSheet = ss.getSheetByName("Datalogger");
// Get last edited row from DataLogger sheet
var row = dataLoggerSheet.getLastRow() + 1;
// Start Populating the data
dataLoggerSheet.getRange("A" + row).setValue(row -1); // ID
dataLoggerSheet.getRange("B" + row).setValue(dateTime); // dateTime
dataLoggerSheet.getRange("C" + row).setValue(tag); // tag
dataLoggerSheet.getRange("D" + row).setValue(value); // value
//dataLoggerSheet.getRange("E" + row).setValue(value); // value
//dataLoggerSheet.getRange("F" + row).setValue(value); // value
// Update summary sheet
summarySheet.getRange("B1").setValue(dateTime); // Last modified date
// summarySheet.getRange("B2").setValue(row - 1); // Count
}
catch(error) {
Logger.log(JSON.stringify(error));
}
Logger.log("--- save_data end---");
}
In the example above, inside the value of "tag" there is data in the format "12345678912 | ABCDEFGHIJ". "Tag" data in column C; I want to print with the first 11 characters in column D. The "tag" data in column C; I want to print it with column E after 12 characters. How can I do that?
To see my overall objective, these two screenshots should show it.
Original Spreadsheet from Form:
enter image description here
Formatted Version of Spreadsheet:
enter image description here
Thank you in advance for your help.
You will have to manipulate the tag string in order to get the values you want.
In order to do this you will have change this:
dataLoggerSheet.getRange("C" + row).setValue(tag); // tag
To this:
dataLoggerSheet.getRange("C" + row).setValue(tag.slice(0,tag.indexOf('|')); //first part of tag
dataLoggerSheet.getRange("D" + row).setValue(tag.slice(tag.indexOf('|') + 2)); // second part of tag
dataLoggerSheet.getRange("E" + row).setValue(value); // value
Explanation
The above snippet makes use of the indexOf and slice methods from JavaScript in order to get the index of the | character in order to be able to split the tag string into two different strings.
Reference
JavaScript Array.prototype.slice();
JavaScript Array.prototype.indexOf().
Related
I'm receiving a gmail from the below code, but NOT the form values that I want to be included. I'm trying have a Google Form (Sheet) send an email to me (a teacher) when a student would type an important or alarming keyword in one of the form's fields (col J).
Picture a Google form with essentially the following fields:
A - Date/time stamp
B - email address collection
C - Name (short answer text)
D - what did you learn or work on yesterday? (long answer text)
E - How are you generally feeling today? (multiple choice)
F - Are you tired today? (multiple choice)
G - Are you stressed out today? (multiple choice)
H - What have you going on today? (bunch of checkboxes)
I - What could be "cool" or "good" about today? (long answer text)
J - (optional) Feel free to tell me anything more (long answer text)
If the student types any alert words, like "die" or "drugs" and so on in the last column (column J), I'd like to get a gmail with a summary of all the info on the row. So far, I've set up a trigger and am only getting a gmail with a subject and message, but the message DOES NOT contain the concatenated vars values.
ALSO, the gmail's subject DOES NOT contain the concatenated studname, which would be helpful. I'm curious how you'd fix this code.
THANK YOU!!
function checkComments(){
var commentsRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2").getRange("J2");
var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet2");
var lastrow = sheet.getLastRow();
var comments = sheet.getRange('J' + lastrow).getValue();
if (comments === '.*drug.*'||'.*die.*'||'.*emotion.*'||'.*suicide.*'||) //many more root key words will be added in here in this |OR| format
{
// Send Alert Email.
var timestamp = sheet.getRange('A' + lastrow).getValue();
var studname = sheet.getRange('C' + lastrow).getValue();
var studemail = sheet.getRange('B' + lastrow).getValue();
var feelings= sheet.getRange('E' + lastrow).getValue();
var tired= sheet.getRange('F' + lastrow).getValue();
var stressed= sheet.getRange('G' + lastrow).getValue();
var studwork = sheet.getRange('H' + lastrow).getValue();
var cool = sheet.getRange('I' + lastrow).getValue();
var results = timestamp + ' \n ' + studname + ' \n ' + studemail + ' \n ' + feelings + ' \n ' + tired + ' \n ' + stressed + ' \n ' + studwork + ' \n ' + cool + ' \n ' + comments;
var emailAddress = 'my email address';
var message = 'Alert from the daily survey!\n' + results;
var subject = 'Daily Survey Alert from ' + studname;
MailApp.sendEmail(emailAddress, subject, message);
}
}```
To match a keyword, replace the
if (comments === '.*drug.*'||'.*die.*'||'.*emotion.*'||'.*suicide.*'||)
with
if(!!comments.match(/drug|die|emotion|suicide/))
I've fixed a bit your code and it seems work for me:
function checkComments() {
var sheet = SpreadsheetApp.getSheetByName('Sheet2');
var lastRow = sheet.getLastRow();
// it works faster when you grab all the row at once
var row = sheet.getRange('A'+lastRow+':J'+lastRow).getValues().flat();
var comments = row[9];
var words = ['drug','die','emotion','suicide'];
if (words.filter(w => comments.includes(w)).length == 0) return;
var emailAddress = 'your#mail.com';
var subject = row[2];
var message = row.join('\n');
MailApp.sendEmail(emailAddress, subject, message);
}
Probably it makes sense to use RegEx to search these words in comments. But I'm not sure if you're ready to dive so deep.
I have a sheet where hyperlink is set in cell, but not through formula. When clicked on the cell, in "fx" bar it only shows the value.
I searched on web but everywhere, the info is to extract hyperlink by using getFormula().
But in my case there is no formula set at all.
I can see hyperlink as you can see in image, but it's not there in "formula/fx" bar.
How to get hyperlink of that cell using Apps Script or any formula?
When a cell has only one URL, you can retrieve the URL from the cell using the following simple script.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var url = sheet.getRange("A2").getRichTextValue().getLinkUrl(); //removed empty parentheses after getRange in line 2
Source: https://gist.github.com/tanaikech/d39b4b5ccc5a1d50f5b8b75febd807a6
When Excel file including the cells with the hyperlinks is converted to Google Spreadsheet, such situation can be also seen. In my case, I retrieve the URLs using Sheets API. A sample script is as follows. I think that there might be several solutions. So please think of this as one of them.
When you use this script, please enable Sheets API at Advanced Google Services and API console. You can see about how to enable Sheets API at here.
Sample script:
var spreadsheetId = "### spreadsheetId ###";
var res = Sheets.Spreadsheets.get(spreadsheetId, {ranges: "Sheet1!A1:A10", fields: "sheets/data/rowData/values/hyperlink"});
var sheets = res.sheets;
for (var i = 0; i < sheets.length; i++) {
var data = sheets[i].data;
for (var j = 0; j < data.length; j++) {
var rowData = data[j].rowData;
for (var k = 0; k < rowData.length; k++) {
var values = rowData[k].values;
for (var l = 0; l < values.length; l++) {
Logger.log(values[l].hyperlink) // You can see the URL here.
}
}
}
}
Note:
Please set spreadsheetId.
Sheet1!A1:A10 is a sample. Please set the range for your situation.
In this case, each element of rowData is corresponding to the index of row. Each element of values is corresponding to the index of column.
References:
Method: spreadsheets.get
If this was not what you want, please tell me. I would like to modify it.
Hey all,
I hope this helps you save some dev time, as it was a rather slippery one to pin down...
This custom function will take all hyperlinks in a Google Sheets cell, and return them as text formatted based on the second parameter as either [JSON|HTML|NAMES_ONLY|URLS_ONLY].
Parameters:
cellRef : You must provide an A1 style cell reference to a cell.
Hint: To do this within a cell without hard-coding
a string reference, you can use the CELL function.
eg: "=linksToTEXT(CELL("address",C3))"
style : Defines the formatting of the output string.
Valid arguments are : [JSON|HTML|NAMES_ONLY|URLS_ONLY].
Sample Script
/**
* Custom Google Sheet Function to convert rich-text
* links into Readable links.
* Author: Isaac Dart ; 2022-01-25
*
* Params
* cellRef : You must provide an A1 style cell reference to a cell.
* Hint: To do this within a cell without hard-coding
* a string reference, you can use the CELL function.
* eg: "=linksToTEXT(CELL("address",C3))"
*
* style : Defines the formatting of the output string.
* Valid arguments are : [JSON|HTML|NAMES_ONLY|URLS_ONLY].
*
*/
function convertCellLinks(cellRef = "H2", style = "JSON") {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getRange(cellRef).getCell(1,1);
var runs = cell.getRichTextValue().getRuns();
var ret = "";
var lf = String.fromCharCode(10);
runs.map(r => {
var _url = r.getLinkUrl();
var _text = r.getText();
if (_url !== null && _text !== null) {
_url = _url.trim(); _text = _text.trim();
if (_url.length > 0 && _text.length > 0) {
switch(style.toUpperCase()) {
case "HTML": ret += '' + _text + '}' + lf; break;
case "TEXT": ret += _text + ' : "' + _url + '"' + lf; break;
case "NAMES_ONLY" : ret += _text + lf; break;
case "URLS_ONLY" : ret += _url + lf; break;
//JSON default : ...
default: ret += (ret.length>0?(','+ lf): '') +'{name : "' + _text + '", url : "' + _url + '"}' ; break;
}
ret += lf;
}
}
});
if (style.toUpperCase() == "JSON") ret = '[' + ret + ']';
//Logger.log(ret);
return ret;
}
Cheers,
Isaac
I tried solution 2:
var urls = sheet.getRange('A1:A10').getRichTextValues().map( r => r[0].getLinkUrl() ) ;
I got some links, but most of them yielded null.
I made a shorter version of solution 1, which yielded all the links.
const id = SpreadsheetApp.getActive().getId() ;
let res = Sheets.Spreadsheets.get(id,
{ranges: "Sheet1!A1:A10", fields: "sheets/data/rowData/values/hyperlink"});
var urls = res.sheets[0].data[0].rowData.map(r => r.values[0].hyperlink) ;
==================================
UPDATE 11 December 2019
My Question is more about Macro Script
The GOAL (in illustration)
to change below raw sheet:
to more readable format:
Basically what i'm doing is split the campaign name with the separator and parse it.
I don't have the problem if the function on only process single cell,for example:
on "Report" Sheet the CELL B2 , is taking data from "Data" B2 ONLY
i got problem when the return data require conditional operator that involve specific condition. So while processing cell B2, it require content from E2, D2, etc
=====================================
i'm taking data from Google Ads/Analytics API to Google Sheet on specific worksheet (i call it 'Raw Data').
Now i'm using pattern for the campaign, so i can easily split/break with separator in order for me to get specific data.
For Example:
With this, by using underscore as separator, i can split campaign name, into various data:
Campaign Objective: Sales
Campaign Title: TBMB
Network: SEM
Branch: All
Targeting: Keywords
..etc
Then i create new sheet called Called CReport which consist the same data from Raw Data sheet, but in much better visualization for marketing people.
Now, after searching on Google, i found the solution for self reference cell.
The script goes like this:
function getSegment(data,index){
temp=data.split("_");
return temp[index-1];
}
function dataParse(input,dataSegment){
return Array.isArray(input) ? input.map(function(e){
return e.map(function(f){
if(f!=""){
return getSegment(f,dataSegment);
}
}
)}
) : "false usage";
}
So if i want to have a column with Network Name, i can place this formula on row 2 (because row 1 is for table header) something like this:
=ArrayFormula(dataParse('RAW DATA'!B2:B;2))
Now my question:
This works for self-reference cell, means if the data taken from B2 in RAW DATA sheet, it will be the only data referenced to cell in Campaign Report sheet.
If the pointer is in B2 on CReport Sheet require data not only from B2 in RAW DATA but also D2 Cell.
What script i need to add in my function ?
i'm expecting the chunk of code will something like this
function dataParse(input,dataSegment){
return Array.isArray(input) ? input.map(function(e){
return e.map(function(f){
if(f!=""){
segmentData=getSegment(f,dataSegment);
if(segmentData=="google"){
returnData=get reference from column D //<---
}else{
returnData=get reference from column E //<---
}
return returnData
}
}
)}
) : "false usage";
}
Hope its clear enough.
Thanks in Advance !
I modified your function in this way:
// range (String): It will be used to get the info in a range
function dataParse(input,dataSegment, range){
var val = "";
return Array.isArray(input) ? input.map(function(e, index){
return e.map(function(f){
if(f!=""){
// If col D has value google then take info from col B
if(f === "google") val = getDesiredRangeValue("B", range, index);
// else take info from col E
else val = getDesiredRangeValue("E", range, index);
// Take segment as needed
return getSegment(val,dataSegment);
}
}
)}
) : "false usage";
}
In order to make it work, I inserted an extra argument to the function. Now you will need to pass as an string the range in A1 notation in your ArrayFormula, this is because the input argument only gives you the values in the cells, and with that extra argument it will be possible to obtain extra info. To make it work fine, always use the same range as the next example shows:
=ArrayFormula(dataParse('RAW DATA'!D2:D5, 2,"D2:D5"))
or
=ArrayFormula(dataParse('RAW DATA'!D2:D, 2,"D2:D"))
Notice I also added a new function called getDesiredRangeValue, which will take the values from the column you need, depending if one of the cells from Col D has the value google. This is how the function looks:
/*
// A1 (String): The col from where you will want the info
// range (String): It will be used to get the info in a range
// index (Integer): It gives the index number from the main array gotten in the input arg
*/
function getDesiredRangeValue(A1, range, index){
var rowNumbers = range.match(/\d+/g);
// It checks if the range will has and end or it will prolong without specifying and end row
if(rowNumbers.length > 1){
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1 + rowNumbers[1]).getValues();
} else {
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1).getValues();
}
// It returns the whole value from each cell in the specified col
return rangeCol[index][0];
}
Code
Now your whole code will look like this:
// Global var
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("RAW DATA");
function getSegment(data,index){
temp=data.split("_");
return temp[index-1];
}
/*
// A1 (String): The col from where you will want the info
// range (String): It will be used to get the info in a range
// index (Integer): It gives the index number from the main array gotten in the input arg
*/
function getDesiredRangeValue(A1, range, index){
var rowNumbers = range.match(/\d+/g);
// It checks if the range will has and end or it will prolong without specifying and end row
if(rowNumbers.length > 1){
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1 + rowNumbers[1]).getValues();
} else {
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1).getValues();
}
// It returns the whole value from each cell in the specified col
return rangeCol[index][0];
}
// range (String): It will be used to get the info in a range
function dataParse(input,dataSegment, range){
var val = "";
return Array.isArray(input) ? input.map(function(e, index){
return e.map(function(f){
if(f!=""){
// If col D has value google then take info from col B
if(f === "google") val = getDesiredRangeValue("B", range, index);
// else take info from col E
else val = getDesiredRangeValue("E", range, index);
// Take segment as needed
return getSegment(val,dataSegment);
}
}
)}
) : "false usage";
}
Docs
These are the docs I used to help you:
Class Sheet
Custom Functions
I am trying to send an email using Google scripts to multiple emails listed in the cells. I would like to send one email and the other emails would be cc. Emails are listed in cells D10:D12, M5:M6, and AL10:AL12
Sheet Link = https://docs.google.com/spreadsheets/d/1xVjEQv6FOnKk-qZgcPV4b7vdeEP3h53on2CA-jJa7iU/edit?usp=sharing
The current script is working great to send an email to me. Just can't figure out how to do the multiple emails and CC's.
function sendEmail() {
var email = sheet.getRange(D10:D12).getValues();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var actualSheet=SpreadsheetApp.getActiveSheet()
var sheet = ss.getActiveSheet() // Enter the name of the sheet here
var subject = "PDF from Water Polo Scoresheet - " + actualSheet.getName();
var body = "\n Attached is a PDF copy of the sheet " + sheet.getName() + " in the " + ss.getName() + " spreadsheet. For the most up to date scoresheet make sure and check www.waterpolodrills.com";
// Base URL
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
/* Specify PDF export parameters
From: https://code.google.com/p/google-apps-script-issues/issues/detail?id=3579
*/
var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=letter' // paper size legal / letter / A4
+ '&portrait=false' // orientation, false for landscape
+ '&fitw=true&source=labnol' // fit to page width, false for actual size
+ '&sheetnames=false&printtitle=false' // hide optional headers and footers
+ '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines
+ '&fzr=false' // do not repeat row headers (frozen rows) on each page
+ '&gid='; // the sheet's Id
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext + sheet.getSheetId(), {
headers : {
'Authorization' : 'Bearer ' + token
}
}).getBlob().setName(sheet.getName() + ".pdf");
// Uncomment the line below to save the PDF to the root of your drive.
// var newFile = DriveApp.createFile(response).setName(sheet.getName() + ".pdf")
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail(email, subject, body, {
htmlBody : body,
attachments : [response],
cc : ccEmail.join(",")
});
}
As described in the doc of sendEmail, you can add options as the 4th parameter (https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object))
In the possible options parameter, there is cc with description "a comma-separated list of email addresses to CC"
So I guess you could use it like this:
ccEmails = //get your ccs here
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail(email, subject, body, {
htmlBody : body,
attachments : [response],
cc : ccEmails.join(",")
});
When i try to make these dynamically made textareas into CEditor fields i get the error:
TypeError: b is undefined
my code:
var input = $("<textarea>").addClass("textAreaClassTest");
//input.setAttribute("id", "como");
//input.setIdAttribute("id", "como");
//input.ID = 'como';
CKEDITOR.replace('como');
item.append(input);
//CKEDITOR.replace('como');
return item;
i cant seem to give the textarea an id - any id's :)
I'm assuming you're using jQuery and only working with 1 or more text areas at a time. So you can get the text areas and assign them ids and use them as below.
//select all text areas
var input = $("textarea");
var list = new Array();
var count = 0;
input.each(function () {
count++;
$this = $(this);
$this.attr("id", "como" + count);
console.log('id is "' + $this.attr("id") + '" and text is "' + $this.text() + '"');
CKEDITOR.replace($this.attr("id"));
list.push($this.attr("id"));
});
//return the list of replaced text area ids
return list;