Is it possible to let onEdit trigger for fontstylechanges? (line-through) - google-apps-script

Got here two scripts that change the font color based on line-through, both are working.
- First one can be custom triggered,
- Second is onEdit.
The onEdit has my preference, as it automates things instantly, however onEdit does not see changes when a cell's value is getting line-through yes or no.
So is it possible to let onEdit trigger for fontstylechanges?
function colorlinethrough() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get spreadsheet
var sheet = ss.getSheets()[0]; // Get first Sheet
var range = sheet.getDataRange(); // Get cells
var data = range.getValues(); // Get the cell values
for (var i in data) {
var editrange = sheet.getRange(parseInt(i)+1,2);
if (editrange.getFontLine() == "line-through") {
editrange.setFontColor("#CCCCCC");
}
else {
editrange.setFontColor("#000000");
}
}
};
function onEdit(e) {
var ss = e.source; // Get spreadsheet
var range = ss.getActiveRange();
if (range.getFontLine() == "line-through") {
range.setFontColor("#CCCCCC");
}
else {
range.setFontColor("#000000");
}
};
also put this question on the g+ community https://plus.google.com/104787958270362345970/posts/GTdBoTZR3YF

Spreadsheets has an onChange event that might do the trick here. onEdit is when the data changes and onChange is when the spreadsheet UI itself changes. Give it a shot.
https://developers.google.com/apps-script/understanding_events

Related

Google Sheets Script - Reference a specific cell in a row

I have a sheet where when I change a specific cell to "YES", I need a template sheet to be copied to a new version and named as per the value of a cell on the current row.
I'm having trouble working out how to get the value of the first cell in the row selected. This is what I have so far (I know this is wrong):
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = sheet.getCurrentCell();
if (currentCell = "YES")
{
SpreadsheetApp.getActiveSpreadsheet().toast("New change control sheet added to workbook.","Change Control",15);
var sourceRow = ss.getActiveRange().getRowIndex();
var tabName = ss.getRange(cell,1).getValues();
ss.getSheetByName("CCTemplate").showSheet()
.activate();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.duplicateActiveSheet();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.getActiveSheet().hideSheet();
ss.setActiveSheet(ss.getSheetByName('Copy of CCTemplate'), true);
ss.getActiveSheet().setName("CC" & tabName);
}
}
Any ideas?
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=='Your Sheet Name' && e.value=="YES") {
e.source.toast="New change control sheet added to workbook.","Change Control",15);
var tabName=sh.getRange(e.range.rowStart,1).getValue();
var tsh=e.source.getSheetByName('CCTemplate');
var csh=tsh.copyTo(e.source);
csh.setName('CC'+tabName);
}
}
You should avoid using activate in your scripts especially in simple triggers where you have to finish in 30 seconds. I think this code does the same thing that you intended for your code. One significant difference is that I use the information that comes in the event object that comes with the trigger. You should add the code Logger.log(JSON.stringify(e)) and then look at the logs you will see that there is a lot of information available to you which removes the need to run extra functions to get things like a spreadsheet.
Use event objects
onEdit offers among others the event objects range and value which are helpful to retrieve the range that has been edited and its value.
Also
When you want to a cell and compare it against a value, like in if (currentCell = "YES") - you need to retrive its value (either currentCell.getValue() or just event.value) and you need to use == instead of = for comparison.
Be careful with getValues() vs getValue(). The former gives you a 2D array and is not necessary if you want to retrieve the value of a single cell.
There is no need to set your sheet to active in order to change its name.
You can rewrite your code as following:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = event.range;
var value = event.value;
if (value == "YES")
{
...
var sourceRow = range.getRowIndex();
var tabName = ss.getRange(sourceRow, 1).getValue();
...
ss.getSheetByName('Copy of CCTemplate').setName("CC" + tabName);
}
}

Undo ability not working after adding Script

I have a script to hide or show Rows with a specific value, it is working well, only I have problem that if I do change the value of any cell in the Spreadsheet even in other sheet like (sheet2) and I want to Undo that change, the Undo ability not working till I repeat it more than 30 times!!! And If I delete the script, it works normally.
Do I have to add, change or delete any code of this script to make Undo Ability working normally as before adding script?
Thank you
I tried to changed this line: var ss = SpreadsheetApp.getActiveSpreadsheet();
to let Undo working normally
or to make it atleast be affecting in specific sheet but I could't.
Here is the full script...
function myShowHide() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("sheet1");
var lastRow = sheet.getLastRow();
for (i = 4; i <= lastRow; i++) {
var status = sheet.getRange("J" + i).getValues();
if (status == "X") {
sheet.showRows(i);
}
}
var sheet = ss.getSheetByName("sheet1");
var lastRow = sheet.getLastRow();
for (i = 4; i <= lastRow; i++) {
var status = sheet.getRange("J" + i).getValues();
if (status != "X") {
sheet.hideRows(i);
}
}
}
Assuming that you are running this with an installable onEdit() trigger then this will solve the problem of interacting with other sheets.
function myShowHide(e) {
var sh=e.range.getSheet();
var rg=sh.getRange(4,10,sh.getLastRow(),1);
var sA=rg.getValues();
for(var i=0;i<sA.length;i++) {
if(sA[i][0]=="X") {
sh.showRows(i+4);
}else{
sh.hideRows(i+4);
}
}
}
I setup an installable onEdit trigger for this function.
function myNewShowHide(e) {
var sh=e.range.getSheet();
if(sh.getName()!="Sheet1")return;
myShowHide(e);
}
But solving the problem on Sheet1 depends upon how you want the sheet to run. If you run it with an edit trigger then anytime your editing anywhere on the sheet it runs. You could limit the edit range but that requires knowing what you want to do with the sheet and I don't know that.
My recommendation is not to run this kind of function with an onEdit() trigger. This one will run much faster because I get all of the data at one time but the rows are still shown or hidden one at a time.

Google Apps Sheets Script .getRange Problems

I just want a "hello world" and after an embarrassing number of hours, its still not working. I'm new to Javascript and Google App script.
Here is the simple script that fails to enter the "Hello" and I would appreciate any tips you have on getting this to work.
As you can see in the commented lines, I've tried many ways to get my "Hello" out there, but none of them work yet. The menu does work. Thanks for your help
Really what I want to do is to be able to move from cell to cell in a spread sheet, get the values there, assign it to a variable. And then to write the var value to a cell after a condition is meet in the script.
function onOpen() {
var ss = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Generate Coin Trades', functionName: 'GCTrades_'}
];
ss.addMenu('CoinTrade', menuItems)
function GCTrades_() {
var ss = SpreadsheetApp.getActive();
SpreadsheetApp.setActiveSheet(ss.getSheetByName('Prices'));
sheet.getRange("$H$1").setValue('Hello');
//settingsSheet.activate();
// One before the last row that has been entered in the spreadsheet
// var LastRow = sheet.spreadsheet.getLastRow() -1;
// var cell1 SpreadsheetApp.getActiveSheet().getRange(LastRow,16);
// var cell = spreadsheet.getRange("$H$1");
// cell.setvalue('Hello')
//var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// var cell = sheet.getRange(1655,16);
// var cell = 'H1655'
// cell.setValue("Hello");
//var count = SpreadsheetApp.getActiveSheet().getRange(2, 3, 6, 4)
// Spreadsheet.getActiveSheet().getRange(LastRow,16).setvalue('Hello')
// SpreadsheetApp.getActiveRange().setValue('hello')
}
There are a couple of typos preventing your script from running. First, your onOpen script isn't closed.
function onOpen() {
var ss = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Generate Coin Trades', functionName: 'GCTrades_'}
];
ss.addMenu('CoinTrade', menuItems)
} // missing closing curly brace.
You used sheet.getRange()... but didn't define sheet anywhere. You also do not need to use setActive to edit the sheet, as you can do that on a cell-by-cell basis. It is enough to define the sheet in the script.
Once your sheet is defined, you can get ranges and set the values. I kept your absolute range ($H$1) for the first cell. We then use a relative reference for the second cell by getting the position using the .getRow() and .getColumn() methods.
function GCTrades_() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1')
var cell1 = sheet.getRange("$H$1").setValue('Hello');
var cell2 = sheet.getRange(cell1.getRow(), cell1.getColumn()+1).setValue('World');
}
Try this:
function onOpen()
{
SpreadsheetApp.getUi().createMenu('CoinTrade')
.addItem('Generate Coin Trades', 'GCTrades_')
.addToUi();
}
//This is a private function so it will not show up in script editors function list. If you want it to show up on the function list then remove the trailing underscore
function GCTrades_()
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Prices').activate();//The activate is not required but it will force this sheet to be on top
sh.getRange("A1").setValue('Hello');//Do not use $s in the range here
}
What I really want:
Really what I want to do is to be able to move from cell to cell in a
spread sheet, get the values there, assign it to a variable. And then
to write the var value to a cell after a condition is meet in the
script.
It's not clear to me what you "really want". Perhaps, you can begin that code yourself and refine the description of what you "really want".

Google Scripts functions refreshing rate

I have a simple function to get some cell value
function getValue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[4];
var range = sheet.getRange("C2:C4");
var cell = range.getCell(1, 1); // "C2"
if (cell.isBlank()) {
return 'error'
} else {
return cell.getValue()
}
}
But when I change data in C2, cell, which contains =getValue() function does not refresh itself instantly. Only if I run script again and get back to sheet. Is it possible to speed this process up? Any code for this? Thanks.
If you have to use the custom functions for this situation, how about this workaround? I don't know whether this is the best way for you. Please think of this as one of several answers.
The flow of script is as follows.
Flow :
Retrieve all values and formulas on the sheet.
Remove values of cells which have formulas.
Reflect values to the sheet using SpreadsheetApp.flush().
Import formulas to the removed cells.
By onEdit(), when you edit the cell, this sample script is launched.
Sample script :
function onEdit(e) {
var range = e.source.getDataRange();
var data = range.getValues();
var formulas = range.getFormulas();
var values = data.map(function(e){return e.slice()});
for (var i in formulas) {
for (var j in formulas[i]) {
if (formulas[i][j]) {
data[i][j] = formulas[i][j];
values[i][j] = "";
}
}
}
range.setValues(values);
SpreadsheetApp.flush();
range.setValues(data);
}
Note :
In this situation which imports a value at "C2" to the cell at =getValue(), the refresh speed is slower than that of #random-parts's method.
To use onEdit() is also proposed from #Cooper.
If this was not useful for you, I'm sorry.

Delete a row in Google Spreadsheets if color of cell is a certain color

So I've be racking my brain about this one for a while now, not 100% sure why this code isn't working.
I got the code from a previous SO post, from there I changed the script to do what I needed.
function onOpen() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// create menu
var menu = [{name: "Evaluate Column J/Call Duration", functionName: "deleteRow"}];
// add to menu
ss.addMenu("Delete Calls Under 1 Minute", menu);
}
function deleteRow() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get active/selected row
var activeRow = ss.getActiveRange().getRowIndex();
// get content column J
var columnJ = ss.getRange("J"+activeRow).getFontColor();
// evaluate whether cell has white text or not
if (columnJ == 'white' || columnJ == '#FFFFFF') {
ss.deleteRow(parseInt(activeRow));
}
}
Basically I have a spreadsheet that's exported from a super archaic call tracking software. Our main issue is that we need to take out any call that's under 1 minute and any duplicates. So, we added conditional formatting for both. This is for getting rid of any 1 minute calls, which in turn should delete the whole row.
Anyone have any idea about this? Thanks guys.
Column j is 10. Colors are in '#ffffff' format. Red is '#ff0000'. This function will delete the row that has the selected color in the selected column.
function jakeDeleteRow(column,color) {
var column = (typeof(column)!='undefined')?column:10;
var color = (typeof(color)!='undefined')?color:'#ff0000;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sht = ss.getActiveSheet();
var rng = ss.getDataRange();
var rngA = rng.getBackgrounds()
for(var i=rngA.length-1;i>-1;i--)
{
if(rngA[i][column-1]==color)
{
sht.deleteRow(i+1);
}
}
}