Adding new line to text in Google spreadsheet cell via apps script - google-apps-script

I have an apps script which takes email addresses from one spreadsheet from multiple cells and adds them them to another spreadsheet into 1 cell only.
Currently the email addresses are added to that cell and separated by a ", ".
I would like to add the email addresses into that same cell but add a new line after each address.
I know it is possible to have new lines in a cell when manually adding text, by typing CTRL-Enter.
How can this be achieved in apps script?
I have so far tried to append "\n" or "\r" or "\r\n" to the string, to no avail, so I have reverted my code back to adding ", " instead.
sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.appendRow(["Num Emails", "Emails"]);
var LMEmails = "";
var count = 0;
for (var i = 0; i < reviewers.LMEmails.length; i++) {
if (count) {
LMEmails += ", " + reviewers.LMEmails[i];
} else {
LMEmails += reviewers.LMEmails[i];
}
count++;
}
data = [count, LMEmails];
sheet.appendRow(data);
If anyone could help, I would very much appreciate it
Regards
Crouz

After searching for the same question, this was my solution:
var stringToDisplay = 'FirstBit' + String.fromCharCode(10) + 'SecondBit';
then
workSheet.getRange(1,1).setValue(stringToDisplay);
output will be in a single cell, :
FirstBit
SecondBit

Google Spreadsheets seems to ignore the new line if there are no characters after it.
Using "/n" works fine as long as you add at least one other character after it, this could be a space as shown below.
For example:
var myString = 'First Bit' + "\n " + "Second Bit";

It should be:
data = [[count, LMEmails]];

Related

Skip Empty Cells in Google Sheets for Text Script with Hyperlink

I have a script that I created in Google Apps Script that sends a slack message to a user with certain IDs on a list in a Google Sheet with a hyperlink. The list for each user does not contain the same number of IDs resulting in the hyperlink url for empty cells to appear in the slack message. Is it possible to skip or hide the hyperlink url for cells that are empty for each user. Apologies if this is not clear. Please see payload script below:
// custom slack webhook
var url = "https://hooks.slack.com/services/XXXXXSBGW/XXXXXXU1K/XXXXXXXXn9jfZXAAAAAA";
var payload = {
"channel": "#"+city[2],
"username": "Alerts",
"text": "Hi " + city[0] + "\n"+
"\n Here are your most pending kits for review.\n" +
"\n <https://google.com/maps/'"+"|"+city[5]+">" +
"\n <https://google.com/maps/'"+"|"+city[6]+">" +
"\n <https://google.com/maps/'"+"|"+city[7]+">" +
"\n <https://google.com/maps/'"+"|"+city[8]+">" +
"\n <https://google.com/maps/'"+"|"+city[9]+">" +
"\n Please review these kits as soon as possible.\n"
};
Generic Hyperlinks provided but basically columns 7 through 9 on the City spreadsheet are sometimes blank. Is it possible to skip these cells if blank or at least not make the url appear? When the cells are blank, usually the hyperlink URL is displayed in the slack message. Any guidance would be much appreciated.
You need to check each of those values to see if they're populated and only then add them to the message. Multiple ways you can do this, but maybe the most straightforward is to loop through the values, build an array, and then join the array.
// Example city array
var city = ["name", 1, 2, 3, 4, "city1", "city2", "", "city3"];
// Compile links
var linkStartIndex = 5;
var linkEndIndex = 9;
var links = [];
for (var i = linkStartIndex; i <= linkEndIndex; i++) {
var value = city[i]
if (value != null && value != "") {
links.push("\n <https://google.com/maps/'"+"|"+value+">");
}
}
// Compile full text
var text = [
"Hi " + city[0] + "\n",
"\n Here are your most pending kits for review.\n",
links.join(""),
"\n Please review these kits as soon as possible.\n"
];
var joined = text.join("");
console.log(joined);
You could potentially make that a little cleaner using map(), but it all really depends on how your data is structured. Personally, I don't like having a variable number of columns as they doesn't convert as neatly into arrays as variable rows do. I also prefer to work with objects where possible. Consider how generating this object from your city array might make your code easier to comprehend:
var record = {
name: 'Brian',
slackId: '123',
cities: [
'New York',
'London'
]
};

Google Sheets SHOW the apostrophe before text

I have a column in Google Sheets with strings.
Some of the rows start with an apostrophe ', some don't. But Google assumed that the apostrophe is because it's a text instead of letting it be part of the text.
How do I make it show these apostrophes?
You mentioned:
Some of the rows start with an apostrophe ', some don't...
How do I make it show these apostrophes?
By adding an extra apostrophe ' in the beginning of the cells.
EDIT
Following the comments by OP
That's inviable for 10000 rows.
and Liron
You can do that with "Find and replace" - search for ^' (caret and apostrophe) and replace it with '' (two apostrophes), and select "Search using regular expressions" and "Also search within formulas".
That would change every apostrophe at the beginning of a cell to two apostrophes.
I wrote the following script as an answer. I assume that you have a column with a mix of strings, some being enclosed in ' and some don't, like this example:
As shown on the picture, Sheets automatically hides the first '. To prevent this you have to add another ' at the start of the string. You can do it with this code:
function myFunction() {
var dataSheet = SpreadsheetApp.openById(
"{SPREADSHEET IDENTIFICATOR}").getSheets()[0];
var dataColumn = 2;
var dataRange = dataSheet.getRange(1, dataColumn, dataSheet.getLastRow());
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].length; j++) {
if (data[i][j].substr(-1, 1) == "'") {
data[i][j] = "''" + data[i][j];
}
}
}
dataRange.setValues(data);
}
The former code will first use a combination of .openById(), .getSheets(), .getRange() and .getValues() to open the spreadsheet, open the sheet, get the data range and read its values respectively. Then, the code will iterate over every value to check if it ends in a ', and if it does, the script will add an extra ' at the start of the string. The end result looks like this:
Please, ask me any question for additional help.

Google Script - Insert indents to appended texts

I'm trying to pass information from a google spreadsheet to a google doc.
This is the view of the table:
The first column only shows once and when it's list of items for that category will be shown.
I managed to present this information in a table inside the doc but it's required to show it as text since the minimum height of each table row is still too much.
This information will travel as an array with two columns and I'll iterate thru it. This is what I've tried:
//servicios_numrows_Q -> number of rows for the data
//value_tabla_servicios -> variable that contains the information
for(var t = 0; t < servicios_numrows_Q - 1; t++){
if(body.appendParagraph(value_tabla_servicios[t+1][0]) == ''){ //Am I in a row that hasn't a Category Title?
"\t" + body.appendParagraph(value_tabla_servicios[t+1][1]);
}else
{
body.appendParagraph(value_tabla_servicios[t+1][0]) + "\t"
+ body.appendParagraph(value_tabla_servicios[t+1][1]);
}
}
However, adding a tab only results in each element being shown in a separate line.
Is there a way to show the first and second column in the same line? Adding spaces instead of tab?
You want to convert the top image (Spreadsheet) of your question as the paragraphs of Google Document using Google Apps Script.
If my understanding is correct, how about this answer?
Modification points:
When you add \t to the top of text using appendParagraph, please use as follows.
"\t" + body.appendParagraph(value_tabla_servicios[t+1][1]); is modified to body.appendParagraph("\t" + value_tabla_servicios[t+1][1]);.
body.appendParagraph(value_tabla_servicios[t+1][0]) + "\t" + body.appendParagraph(value_tabla_servicios[t+1][1]); is modified to body.appendParagraph(value_tabla_servicios[t+1][0] + "\t" + value_tabla_servicios[t+1][1]);
In your script, when value_tabla_servicios[t+1] is declared as a variable, the readability of script can be increased.
If you want to align the column "B", "\t\t" might be suitable instead of "\t".
When above points are reflected to your script, it becomes as follows. Please think of this as just one of several answers.
Modified script:
for(var t = 0; t < servicios_numrows_Q - 1; t++){
var row = value_tabla_servicios[t+1]; // Added
if (row[0] == ''){ // Modified
body.appendParagraph("\t\t" + row[1]); // Modified
} else {
body.appendParagraph(row[0] + "\t" + row[1]); // Modified
}
}
By the length of value of row[0], "\t\t\t" of body.appendParagraph("\t\t" + row[1]) might be suitable. About this, please check your actual situation.
Reference:
appendParagraph()
If I misunderstood your question and this was not the direction you want, I apologize. If the error occurs, can you provide a sample Spreadsheet, output you want and your whole script? By this, I would like to confirm it. Of course, please remove your personal information.

Copy Paste Script Google Sheets

I work for a major Motor Manufacturer and I need some help with a google sheets script that I need to write (I assume a script is the way forward?)
I have a google sheets file that is used to monitor issues and planned improvements for multiple departments. The workbook has multiple tabs that I need to somehow copy and paste data around within it.
I have included a sample file to try and help explain it, it's quite a complicated file to try and explain...I will do my best. It sounds like I need to use a script but I am new to using scripts.
Link to Sheet
Explanation of file:
On a weekly basis I update the sheet with latest data into the "Master data" sheet, this sheet feeds the "electrical" sheet using a query.The dept owner for electrical updates updates the "electricalinput" sheet with his actions and timing and this feeds into the "electrical" sheet also. The "electrical" sheet in turn feeds the "improvement data" sheet which feeds the chart.
It is arranged like this so what when new issues are added and the order changes the comments follow on the "electrical" sheet, and the owner only needs to update the "electricalinput" sheet with comments that he hasn't already done.
What I would like try and do:
I would like to be able to run a script that filters or extracts anything in the electrical sheet with #N/A against it (which means the 3 cell combination hasn't been found in the input sheet) and copy and paste just those items into the "electricalinput" sheet at the next available line that isn't populated. In the actual file there are multiple depts so variations of the script will have to run to cover the different depts.
I've updated the spreadsheet that you shared with relevant code.
You can run the script via Add Ons->Master Data Utils->Clean Up Keys menu. The menu was created in the OnOpen function from this script.
Note that there are a couple of requirements as below for the script to work.(already taken care of in the shared ss)
Departments lists and details helpful for processing all the data as shown below.
There should be a NamedRange called Department_List which would be top left cell of the table shown above.
Column to Clean -> Action Summary
is the column we would be using to search of #N/A
Display Sheet Name -> Electrical
is where the #N/A would be.
Input Sheet Name -> Electricalinput
is the sheet name that would be updated.
Copy Cols From(Disp) -> B:D
the columns that would be copied over
Similar to d but this is where sata would be copied to
But at the moment the code doesn't use this and just pastes into first available cell in col B
Here's the code I attempted, let me know of any suggestions or alterations that would make it easier to use.
function cleanComponentList(curSS) {
Logger.log("Init script cleanComponentList 'Department_List'")
curSS = curSS || SpreadsheetApp.getActiveSpreadsheet()
var deptListStart = curSS.getRangeByName("Department_List")
if(deptListStart==null){
Logger.log("This script cannot be used without the named range 'Department_List'")
return
}
var dept = deptListStart.offset(1,0)
while( ! dept.isBlank() ){
Logger.log("Started processing " + dept.getDisplayValue() + " Dept.")
//Get Department Sheet
var deptSht = curSS.getSheetByName(dept.offset(0,1).getValue())
//Get Column that has Action Summary in department sheet
var actSummCol=deptSht.getRange(2, 1)
//Get Department Input Sheet (Target Sheet where we need to copy the final values to
var deptInputSht = curSS.getSheetByName(dept.offset(0,2).getValue())
//Find column with the "Column Header"/"Summary" in which we search #N/A
while( ! (actSummCol.getDisplayValue() === dept.offset(0,3).getDisplayValue())){
var tmp = actSummCol.getDisplayValue()
var actColRng = actSummCol.getA1Notation()
actSummCol=actSummCol.offset(0,1)
}
var actSummColAddress = actSummCol.getA1Notation();
Logger.log("Found key \"" + dept.offset(0,3).getDisplayValue() + "\" for " + dept.getDisplayValue() + " # " + actSummColAddress)
var errRows = []
//Get all rows that have error Action Summary
var lastRow = deptSht.getLastRow()
for(nRow=1;nRow<lastRow;nRow++){
//There should be a better of checking #N/A
if(actSummCol.offset(nRow,0).getDisplayValue().equals("#N/A")){
errRows.push(nRow+actSummCol.getRow())
}
}
Logger.log("Got " + errRows.length + " error rows for " + dept.getDisplayValue() + " Dept.")
//Get Cell where data append should start from.
var deptInputLastAvailableRow = deptInputSht.getRange("B1")
while(!deptInputLastAvailableRow.isBlank() || deptInputLastAvailableRow.isPartOfMerge()){
deptInputLastAvailableRow=deptInputLastAvailableRow.offset(1,0)
}
Logger.log(dept.getDisplayValue() + " Dept." + " Input will be updated from " + deptInputLastAvailableRow.getA1Notation())
//Copy CDE from the filtered rows to Department Input Sheet
var srcCols=deptSht.getRange(dept.offset(0,4).getDisplayValue())
//There should be a better way of iterating. for-of throws syntax error!!!
for(idx in errRows){
var row = errRows[idx];
var lc = srcCols.getLastColumn()
var fc = srcCols.getColumn()
var errKeyRangeAddress=srcCols.getCell(row,1).getA1Notation() + ":" + srcCols.getCell(row,lc-fc + 1).getA1Notation()
var errKeyRange=deptSht.getRange(errKeyRangeAddress)
errKeyRange.copyTo(deptInputLastAvailableRow)
deptInputLastAvailableRow=deptInputLastAvailableRow.offset(1,0)
}
Logger.log("Copied " + errRows.length + " entries to Sheet \"" + deptInputSht.getName() + "\"")
Logger.log("Finished Processing " + dept.getDisplayValue() + " Dept.")
dept=dept.offset(1,0)
}
}
function onOpen(){
//Choose which way you want your menu to appear.
//SpreadsheetApp.getActiveSpreadsheet().addMenu("Monitor", [{name:"Clean Up Keys",functionName:"cleanComponentList"}])
SpreadsheetApp.getUi().createAddonMenu().addItem("Clean Up Keys", "cleanComponentList").addToUi()
}
This is a simple copy script to help you get started. copyTo is documented here. The rest of the commands can be found in the same documentation.
After you've done a few of your own scripts you'll find it a lot easier to make up your own rather than spending all of your time copying scripts.
function copyPasteSelectedRows()
{
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('Sheet2');
var sh0=ss.getSheetByName('Sheet1');
var rg0=sh0.getDataRange();
var vA=rg0.getValues();
for(var i=1;i<vA.length;i++)
{
if(vA[i][10]==1)//condition to meet to copy
{
var src=sh0.getRange(i+1,1,1,vA[i].length);//source range
var tar=sh1.getRange(sh1.getLastRow() + 1,1,1,vA[i].length);//target range
src.copyTo(tar);
}
}
}
This is Sheet1:
This is Sheet2 after the copy:

Google Script insertSheet not accepting string object?

So I am taking data from a spreadsheet, putting the relevant parts into an array and writing it back to a new spreadsheet. The data is coming from a google form and not everyone had an input for every question so I am taking only the questions that are not null. Which causes the length of my array to be variable
So I have taken it down to its most barest steps and I am stuck at the part where you insert the sheet, it works fine on a iteration of 1, but when I do it on a loop there is an error.
for (j=2; j <= 3 ; j++)// I have 23 iterations, but I stopped at 2 for now
{
var cellLocation = new String ("B" + j + ":AC" + j);
Logger.log("J is " + j + "Cell location " + cellLocation);
var workingRange = buySheet.getRange(cellLocation);
var customer = workingRange.getValues(); //this produces a range of the row
Logger.log("Range is " + workingRange.getA1Notation() + " data is " + customer[0][0]);
//At first I thought it was the range- so I broke everything out into the tiniest step
var nameCustomer = new String(customer[0][0]);
Logger.log("nameCustomer is " + nameCustomer);
//this correctly prints out the names as strings- through 23 iterations
var create = buySheet.insertSheet(nameCustomer);
//this is a sheet object with the customers name- fails after the first iteration, and creates sheets with blank names -
}
This is the reference I am using: https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#insertSheet(String)
I have commented out everything after this to solve this one sticking point. I have tried instantiating the string outside the loop. I can post the logs, I am using real data I have so I would have to blur out peoples names.
It works for the first round, and it works if I manually type a string.
I figured it out! When I created a new sheet it moved the active sheet to the new sheet. So at the end of the loop I have to reset the active sheet to the first sheet where the data I want it is.
Seems so obvious in retrospect.