So I have a spreadsheet up for the purpose of documenting descriptions of functions found in some python files. TLDR these descriptions are hard to read due to the clutter left over from the files.
So my solution to solve this was:
function onEdit(e) {
const desFix = ['"', '
'];
let activeSheet = e.source.getActiveSheet();
let range = e.range;
const desc = range.getValue();
const rdesc = desc.toString();
for (let i=0; i<desFix.length; i++){
const rep = rdesc.replace(desFix[i]," ");
range.setValue(rep);
}
}
But it only works on the first occurrence when I need it to happen multiple times. Everything I've found and tried to implement/translate over to spreadsheet api breaks. Any idea of what I need to do to make it run multiple times?
I believe your goal as follows.
You want to convert the values of " and
to " " in the active range in the Google Spreadsheet.
You want to run the script using the OnEdit trigger.
Modification points:
In your script, the same rdesc is used by rdesc.replace(desFix[i]," ") in the for loop. By this, only the 1st
at 2nd loop is replaced. I think that this is the reason of your issue.
And, I think that setValue is used in the for loop, the process cost will be high.
In your case, I thought that TextFinder might be suitable.
So in this answer, I would like to suggest to modify your script using TextFinder. When your script is modified using TextFinder it becomes as follows.
Modified script:
function onEdit(e) {
const desFix = ['"', '
'];
desFix.forEach(f => e.range.createTextFinder(f).matchCase(true).replaceAllWith(" "));
}
When you use this, for example, please edit a cell. By this, the script is run by OnEdit trigger and " and
in the value in the cell are replaced to " ".
Note:
When you want to run the script with the script editor, you can also use the following script. When you use the following script, please run myFunction() at the script editor. By this, all cell values in the active sheet are checked.
function myFunction() {
const desFix = ['"', '
'];
const sheet = SpreadsheetApp.getActiveSheet();
desFix.forEach(f => sheet.createTextFinder(f).matchCase(true).replaceAllWith(" "));
}
References:
Class TextFinder
google-apps-scropt
I thought that these links might be useful.
Related
I've got a script that's doing some onEdit formatting on a sheet of mine. All the rest is working well, and I wanted to include a line that deletes spaces from number values I'm importing. That last line is not working.
Any ideas what I'm missing here?
function onEdit(e) {
var cell = e.range;
var sh = e.source.getActiveSheet();
if(sh.getName() === "Trading Journal") {
cell.setBackground('#fff');
cell.setFontSize(10)
cell.setFontFamily()
cell.replace(/\s/g, "")
}
}
https://docs.google.com/spreadsheets/d/1rkjO-ITeLdIHq-LLHfHcp6-1j1R0-giS6HGbwYdJ5Ek/edit?usp=sharing
Did a bit of research regarding this, and it seems that .replace() is a string method and therefore may not work with numbers. Reference
But if you only need to remove whitespaces from numbers, here is a simple solution:
function rSpaces() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell();
cell.trimWhitespace();
}
You can assign this on an onEdit trigger and check this documentation for any font modifications you want to add.
I'm trying to make a script that, whenever triggered, runs through each row checking if the checkboxes in column F are checked. If so, the content of column A in that row is replaced with a 0. Upon running the code, nothing happens. I am not sure where the script gets caught up, but I would assume it's in the for() loop. I have also included a picture of the spreadsheet itself for easier understanding. Any help is appreciated.
My code:
function onEditButAgain(event){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var editedCell = sheet.getActiveCell();
var columnToSortBy = 6;
if(editedCell.getColumn() == columnToSortBy)
{
for(var x = 2; x<=100; x++)
{
var checked = sheet.getRange(x, 6);
if(checked.isChecked == true)
{
var date = sheet.getRange(x, 1);
date.setValue("0");
}
}
}
}
The image of the spreadsheet itself:
Explanation:
Your goal is to manually execute a script that will change the value in column A whenever the cell in the same row in column F is checked.
The obvious issue in the code is isChecked which should be isChecked(). You use parenthesis when you want to execute a function and in this case you want to execute isChecked.
In this case, an onEdit script will be redundant. If you want to use an onEdit trigger with the name onEditButAgain you have to create an installable trigger. But you don't need an installable trigger for this purpose.
Although you can wrap up the following code in this answer in a simple onEdit() function, the event object is not used and the code won't be 100% efficient. But if you want to run it manually, you don't need a trigger anyway.
When you use a loop, it is not a good practice to use methods like getRange or isChecked or setValue because these methods are computationally expensive and your script will very slow. Work with arrays instead and getValues/setValues.
Solution:
function myFunction(){
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1'); // change it to your sheet name
const valA = sh.getRange('A2:A'+sh.getLastRow()).getValues().flat();
const cb = sh.getRange('F2:F'+sh.getLastRow()).getValues().flat();
const new_valA = cb.map((c,i)=> [c ? "0" : valA[i]]);
sh.getRange(2,1,new_valA.length,new_valA[0].length).setValues(new_valA);
}
Having a lot of trouble finding this and as a very beginner programmer, I can't quite troubleshoot my way through this.
What I want to do:
Automatically log the word count of a google doc in a google sheets cell.
The code I've been playing with to try and make it happen that is probably super wrong:
function countWords() {
var doc = DocumentApp.openByURL().getBody().getText();
var punctuationless = doc.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()"?“”]/g," ");
var finalString = punctuationless.replace(/\s{2,}/g," ");
var count = finalString.trim().split(/\s+/).length;
return count;
Ideally, what I'd like to do is, in sheets, set it up so there's a column with links to google docs and be able to just put in a function that will return the wordcount from that doc.
Answer:
You can not create a custom function to do this, as reading another document requires authentication. You can however do this with an in-sheet button which runs the script.
More Information:
As per the documentation on custom functions, it is not possible to run methods which require authentication such as DocumentApp:
Unlike most other types of Apps Scripts, custom functions never ask users to authorize access to personal data. Consequently, they can only call services that do not have access to personal data
As a result, you will instead have to manually run the script - but this can be done from a button in the Sheet.
Code:
Assuming that you have the Document links in column A and wish for the word count to be in column B (starting in row 2):
function countWords() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var linkRange = ss.getRange("A2:A");
try {
linkRange.getValues().forEach(function(cell, index) {
if (cell[0] == "") {
throw "Cell A" + (index + 2) + " is empty"
}
let doc = DocumentApp.openByUrl(cell[0]).getBody().getText();
let count = (doc.match(/\b\S+\b/g) || []).length;
ss.getRange(index + 2, 2).setValue(count);
});
}
catch (err) {
console.log(err);
return;
}
}
Rundown of this function:
Open the sheet containing the document links (remember to change the sheet name!)
Get the range of links down column A
Loop through each link and obtain the Document's text
Obtain all instances of word-boundary/non-whitespace/word-boundary in the document, puts them all into an array, and gets the length of the array.
In this step, if the document is empty, then an empty array is given
Sets the cell in column B adjacent to the link to the result of the count.
This is all wrapped inside a try/catch so that the script stops execution when it reaches an empty cell in column A.
Assigning to a Button:
Now, you can create an in-sheet button which will run the script whenever you click it.
Go to the Insert > Drawing menu item and create a shape; any shape will do, this will act as your button.
Press Save and Close to add this to your sheet.
Move the newly-added drawing to where you would like. In the top-right of the drawing, you will see the vertical ellipsis menu (⋮). Click this, and then click Assign script.
In the new window, type countWords and press OK.
Now, each time you click the button, the script will run.
Visual Example:
References:
Custom Functions in Google Sheets | Apps Script | Google Developers
I am working on a project where I take multiple column/row inventory sheets and turn them into a multi-row/2-column format for order picking.
I have a switch for selecting the appropriate inventory sheet and a map() function that copies the imported information from the inventory DataRange().
However, not all the data is in consistent columns. What I would like to do is find an expression that maps the next column in if the column it was mapping has a zero or "" value.
I won't give you the full body of code unless you need it, but hopefully just the important parts.
This is what I have:
var source = SpreadsheetApp.openById("1xixIOWw2yGd1aX_2HeguZnt8G_UfiFOfG-W6Fk8OSTs"); //This sheet
var srcSht = SpreadsheetApp.getActive();
var sourceMenu = srcSht.getRange('A1');//This is the cell cotaining the dropdown
var menuTest = sourceMenu.getValue();
// Variable for the vars sheet. If it doesn't exist, create it
var varsTest = source.getSheetByName('vars');
if (!varsTest){source.insertSheet('vars');}
var importedA1 = varsTest.getDataRange().getA1Notation();
varsTest.clearContents();
var t1Imp = '=ImportRange("test1_Id", "Stock!A1:F11")';
var varsData = varsTest.getRange('A1');// This is the cell we fill with the importRange formula
varsData.setValue(t1Imp);
var imported = varsTest.getDataRange().getValues();
var newOrder = imported.map(function(item) {
if (item[4] !== NaN){return [[item[0]],[item[4]]];};
if (item[4] === NaN){return [[item[0]],[item[3]]];};}
var orderRange = source.getSheetByName('Sheet1').getRange(10,1,newOrder.length, newOrder[0].length);
orderRange.setValues(newOrder);
Logger.log("\t" + newOrder);
Logger.log(newOrder):
[(timestamp omitted)] items1,order,caramel,6,c&c,2,mint,3,PB,0,,,items2,,caramel,,strawberry,,mint,,PB,
It seems to be skipping the if statements, or I told it that I mean to test the index as NaN, which will obviously never be true.
I also tried replacing 'NaN' with 'undefined'. Same result. I tried finding the item[4].Values, but it gave me an error. I also tried the same logic using filter() instead of map() but it copied the entire data set.
I pull these values onto a new 'vars' sheet in the workbook (to minimize calls to the web service):
test1
reduce them to the first and last columns, then output:
test
The cells in the 'order' column for the second set of items in the 'test' sheet are blank. The values for that order column should be in item[3] of that array, but I can't get the script to identify that that the blank cells are blank.
I am new to Google Apps Script and JS, but I am watching a lot of tuts and learning by doing. If I find a solution, I will post it.
Thank you StackOverflow, I could not have learned as much as I have without this community!
I have a working function that does what I want. In short:
I had to create a duplicate of the order column in a new column, so that all the values would line up. It's not technically a JS answer, but was the simplest and follows good spreadsheet rules.
function rmZeroOrderPS(item){
var source = SpreadsheetApp.openById("<sheetId>"); //This sheet
var varsTest = source.getSheetByName('vars');
var imported = varsTest.getDataRange().getValues();
var i=-1;
while (i <= imported.length){
if(item[8]!= 0) {return [item[0],item[8]]};
i+=1;
};
I have this code that I found online and it works as needed, but it works for all my sheets or the tabs at the bottom if you want to call them. I want it to work
function onEdit(event)
{
var sheet = event.source.getActiveSheet();
var eventRange = event.source.getActiveRange();
var eventColumn = eventRange.getLastColumn();
if (eventColumn == 1)
{
var stampRange = eventRange.offset(0,10);
stampRange.setValue(new Date());
}
}
This is the original code, I tried adding in line 4 the following but i can't get it to work. I'm not experienced with javascript but I need your help as i'm trying my best. Thank you.
if(sheet.match(/*.13/)){
This is the line I added. Based on my reading online, the script should works only if the sheet name ends with 13. But it's not working.
You've got the right idea, but sheet is a Sheet Object, while .match() is a String method. Use the Sheet.getSheetName() method to get the name of the sheet (the words on the tab).
In an onEdit(), you usually want to bail out without investing much processing time, so you should put the test for the sheet name as early as possible.
If you want to match "Sheet13" exactly, you should test for just that - because your regex will also match "Apollo13" and "a13a", for example.
function onEdit(event)
{
var sheetName = event.source.getActiveSheet().getSheetName();
if (sheetName.match(/.13/) == null)
// These aren't the droids you're looking for...
return;
var eventRange = event.source.getActiveRange();
var eventColumn = eventRange.getLastColumn();
if (eventColumn == 1)
{
var stampRange = eventRange.offset(0,10);
stampRange.setValue(new Date());
}
}