I am a wanna-be developer who is trying to figure out how to hide a set of columns based off a checkbox being clicked.
Would anyone want to help with this code?
I have 12 different sheets(one for each month) and I would like to hide columns A-H with the checkbox in I being clicked.
Ideally I can implement on each individual sheet.
Link to spreadsheet
There are few ways one can do it.
Easiest and most recommended among all is to group those column and it will have pretty much same use which you're looking for.
If you're willing to use appscript for it. Here how it should be done:-
Open Script Editor from your spreadsheet.
Declare the onEdit simple trigger which will run every time when sheet will be edited.
So whenever you'll click on tickbox on I1 this function will trigger.
When a trigger fires, Apps Script passes the function an event object as an argument, typically called e.
For this object, we're gonna have the information we need to do our task, and also to restrict our operation to only to those months sheet and range belongs to it.
Here is the code, I tried my best to explain what happening in the code:-
function onEdit(e)
{
var rangeEdited = e.range; // This will us range which is edited
var sheetEdited = rangeEdited.getSheet().getName() // from range we can get the sheetName which is edited
var mySheets = ["Jan List","Feb List"] // Put all the month sheet name in this array where you want to have this functionality
var rowEdited = rangeEdited.getRow() // From Range we can get Row which is edited
var columnEdited = rangeEdited.getColumn() // From Range we can get Column which is edited
if(mySheets.indexOf(sheetEdited) > -1) // Now we want to only restrict the operation on those sheets,so if other sheet is edited, we shouldn't run our hide function
{
if(rowEdited === 1 && columnEdited === 9) // we're further restricting the range of operation to run this function when only I1 is edited that is Row:- 1 and Col:- 9
{
hideUnhide(sheetEdited) // calling our hide function within OnEdit and passing sheetName as an argument in it
}
}
}
function hideUnhide(sheetEdited) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssname = ss.getSheetByName(sheetEdited) // accessing the sheet which is edited
var isItHidden = ssname.isColumnHiddenByUser(1) // checking if range is already hidden
if(isItHidden === false) // if No, hide that range
{
ssname.hideColumns(1, 6)
}
else // if Yes, unhide that range
{
var hideThisRange = ssname.getRange('A:H')
ssname.unhideColumn(hideThisRange)
}
}
Documentation:-
AppScript Events
Related
I know this question has been asked before but the answers given are not valid for my case because it's slightly different.
I've created a formula that looks for sheets with a pattern in the name and then uses it's content to generate the output. For example
function sampleFormula(searchTerm) {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheets = spreadsheet.getSheets()
.filter(function(sheet) {
// If sheet name starts with DATA_SHEET_...
return sheet.getSheetName().indexOf('DATA_SHEET_') === 0;
});
const result = [];
sheets.forEach(function(sheet) {
// We get all the rows in the sheet
const rows = sheet.getDataRange().getValues();
rows.forEach(function(row) => {
// If the row it's what we are looking for we pick the columns A and C
if (row[1] === searchTerm) {
result.push([ row[0], row[2] ])
}
});
});
// If we found values we return them, otherwise we return emptry string
return result.length ? result : '';
}
The thing is I need this formula to be re-calculated when a cell in a sheet with a name starting with DATA_SHEET_ changes.
I see most answers (and what I usually do) is to pass the range we want to watch as a parameter for the formula even if it's not used. But in this case it will not work because we don't know how many ranges are we watching and we don't even know the whole sheet name (it's injected by a web service using Google Spreadsheet API).
I was expecting Google Script to have something like range.watch(formula) or range.onChange(this) but I can't found anything like that.
I also tried to create a simple function that changes the value of cell B2 which every formula depends on but I need to restore it immediately so it's not considered a change (If I actually change it all formulas will break):
// This does NOT work
function forceUpdate() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getActiveSheet();
const range = sheet.getRange(1, 1);
const content = range.getValue();
range.setValue('POTATO');
range.setValue(content);
}
So I don't know what else can I do, I have like a hundred formulas on multiple sheets doing this and they are not updating when I modify the DATA_SHEET_... sheets.
To force that a custom function be recalculated we could use a "triggering argument" that it's only taks will be to trigger the custom function recalculation. This triggering argument could be a cell reference that will be updated by a simple edit trigger or we could use an edit installable trigger to update all the formulas.
Example of using a cell reference as triggering argument
=sampleFormula("searchTerm",Triggers!A1)
Example of using an edit installable trigger to update all the formulas
Let say that formulas has the following form and the cell that holds the formula is Test!A1 and Test!F5
=sampleFormula("searchTerm",0)
where 0 just will be ignored by sampleFormula but will make it to be recalculated.
Set a edit installable trigger to fire the following function
function forceRecalculation(){
updateFormula(['Test!A1','Test!F5']);
}
The function that will make the update could be something like the following:
function updateFormula(references){
var rL = SpreadsheetApp.getActive().getRangeList(references);
rL.getRanges().forEach(function(r){
var formula = r.getFormula();
var x = formula.match(/,(\d+)\)/)[1];
var y = parseInt(x)+1;
var newFormula = formula.replace(x,y.toString());
r.setFormula(newFormula);
});
}
As you can imagine the above example will be slower that using a cell reference as the triggering argument but in some scenarios could be convenient.
I know this question has been asked before but the answers given are not valid for my case because it's slightly different.
I've created a formula that looks for sheets with a pattern in the name and then uses it's content to generate the output. For example
function sampleFormula(searchTerm) {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheets = spreadsheet.getSheets()
.filter(function(sheet) {
// If sheet name starts with DATA_SHEET_...
return sheet.getSheetName().indexOf('DATA_SHEET_') === 0;
});
const result = [];
sheets.forEach(function(sheet) {
// We get all the rows in the sheet
const rows = sheet.getDataRange().getValues();
rows.forEach(function(row) => {
// If the row it's what we are looking for we pick the columns A and C
if (row[1] === searchTerm) {
result.push([ row[0], row[2] ])
}
});
});
// If we found values we return them, otherwise we return emptry string
return result.length ? result : '';
}
The thing is I need this formula to be re-calculated when a cell in a sheet with a name starting with DATA_SHEET_ changes.
I see most answers (and what I usually do) is to pass the range we want to watch as a parameter for the formula even if it's not used. But in this case it will not work because we don't know how many ranges are we watching and we don't even know the whole sheet name (it's injected by a web service using Google Spreadsheet API).
I was expecting Google Script to have something like range.watch(formula) or range.onChange(this) but I can't found anything like that.
I also tried to create a simple function that changes the value of cell B2 which every formula depends on but I need to restore it immediately so it's not considered a change (If I actually change it all formulas will break):
// This does NOT work
function forceUpdate() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getActiveSheet();
const range = sheet.getRange(1, 1);
const content = range.getValue();
range.setValue('POTATO');
range.setValue(content);
}
So I don't know what else can I do, I have like a hundred formulas on multiple sheets doing this and they are not updating when I modify the DATA_SHEET_... sheets.
To force that a custom function be recalculated we could use a "triggering argument" that it's only taks will be to trigger the custom function recalculation. This triggering argument could be a cell reference that will be updated by a simple edit trigger or we could use an edit installable trigger to update all the formulas.
Example of using a cell reference as triggering argument
=sampleFormula("searchTerm",Triggers!A1)
Example of using an edit installable trigger to update all the formulas
Let say that formulas has the following form and the cell that holds the formula is Test!A1 and Test!F5
=sampleFormula("searchTerm",0)
where 0 just will be ignored by sampleFormula but will make it to be recalculated.
Set a edit installable trigger to fire the following function
function forceRecalculation(){
updateFormula(['Test!A1','Test!F5']);
}
The function that will make the update could be something like the following:
function updateFormula(references){
var rL = SpreadsheetApp.getActive().getRangeList(references);
rL.getRanges().forEach(function(r){
var formula = r.getFormula();
var x = formula.match(/,(\d+)\)/)[1];
var y = parseInt(x)+1;
var newFormula = formula.replace(x,y.toString());
r.setFormula(newFormula);
});
}
As you can imagine the above example will be slower that using a cell reference as the triggering argument but in some scenarios could be convenient.
Currently building a function where when a certain selection is selected from a drop-down data validation menu, the user is redirected to a different sheet within the workbook. What I currently have does not return an error but also does not do what is intended. Any help would be greatly appreciated.
function gotoselectsheetnosheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange(4,3);
var data = range.getValue();
if (data == "Answers")
{
var dinner = ss.getSheetByName('Answers');
dinner.activate();
}
}
please see this image for further clarification
Try this solution.
function onEdit(e) {
if(e.source.getActiveSheet().getName() === "Menu" && e.range.getRow() === 4 && e.range.getColumn() === 3) {
e.source.getSheetByName(e.value).activate();
}
}
This works if you setup an onEdit() trigger.
function gotosheet(e)
{
e.source.getSheetByName(e.value).activate();
}
e.source is the event event objects resource for the spreadsheet object. Look here to learn more about it.
So then the next is getSheetByName(e.value) and e.value is the new value in the cell being edited.
Then the next is activate. And that makes it move to the named sheet. So presumably you have selected the appropriate sheet names in your validation setup.
Validation setup:
When you select one of the two possible selections in the validation drop down that triggers the onEdit trigger and the function takes you to the tab with that name.
Named Range Used in Validation Setup:
OnEdit Trigger Setup:
I'm working on creating a system for other teachers to easily track their students' progress. I've got a spreadsheet with individual sheets for each student and then a sheet for an overview of all students. The spreadsheet has the following script attached to it:
function SheetNames() {
try {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets()
var out = new Array( sheets.length+1) ;
for (var i = 1 ; i < sheets.length ; i++ ) {
out[i] = [sheets[i-1].getName()];
}
return out
}
catch( err ) {
return "#ERROR!"
}
}
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Student List')
.addItem('Update Student List', 'SheetNames')
.addToUi();
}
In the "Overview" sheet, I have a cell that just contains =SheetNames(). When I first enter the custom function, the list populates. When I open the spreadsheet, the menu is added as it should be. However, when I click the menu item, the list of students on the "Overview" sheet is not updated. Is there anyway to make this function automatically update?
It will not update because all that function does is return an array. When you use the =SheetNames() notation, you are giving it a range to write to (the cell where you put the formula).
When you run the function via menu click, it doesn't know anything about the target range in the spreadsheet. It simply creates a variable ('out'), stores it in memory, then destroys it when the function finishes executing.
If you'd like to write to specific range, you should reference it in your function. Here's a quick example of the function that writes a random number from 0 to 100 to cell A1 of the first sheet
function populateCell() {
var number = Math.random() * 100;
var cell = SpreadsheetApp.getActiveSpreadsheet()
.getSheets()[0]
.getRange("A1");
cell.setValue(number);
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('menu')
.addItem('run', 'populateCell')
.addToUi();
}
It will not work as a custom function though. As per GAS documentation, if a function is being called from a cell (is custom), that function is read-only and can't set values https://developers.google.com/apps-script/guides/sheets/functions
Also, there's no need to use custom function because you seem to only need this code for specific range. If you intend to write to whatever cell the cursor is currently in, you should remove the reference to specific cell and use sheet.getActiveCell() instead. Only use custom functions for general functionality not tied to specific range.
I am pretty new to google sheets script development and am wondering how to trigger a clearAll script with cell value i.e. A1=100.
My clearAll script works (see below), though I don't know what to add to it to trigger it using a specific cell value.
function clearAll() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formresponses1 = ss.getSheetByName("formresponses1");
formresponses1.clearContents();}
Thanks
If you are trying to make it so that whenever somebody puts in the value of "100", it clears the content of the entire sheet, then you can do this:
function onEdit(e) {
var ss = SpreadsheetApp.getActive() //gets the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet() //gets the active sheet
var cell = ss.getActiveRange() //gets the active cell
var cellContent = cell.getValue() //gets the value of the active cell
if(cellContent === 100) {
sheet.clearContents() //clears the values of the entire active sheet
}
}
If you want to make it so that whenever somebody edits the cell and makes its value "100", the code clears only that cell, then do this:
function onEdit(e) {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = ss.getActiveRange()
var cellContent = cell.getValue()
if(cellContent === 100) {
cell.setValue("") //clears the value of the active cell
}
}
Of course, in the latter, due to the slight lag in Google scripts, if somebody rapidly puts in 100 in every cell they can, then some of the cells with a value of "100" will stay there, but if the person is putting the values in like a normal person rather than a spammer, then this code will work.
Also, if you are trying to make it so that if the value of a certain cell (ie: A1) is equal to "100," the script clears the entire sheet, do this:
function onEdit(e) {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = sheet.getRange('A1')
var cellContent = cell.getValue()
if(cellContent === 100) {
sheet.clearContents()
}
}
Hope I could help!
The onEdit trigger runs when any cell in the spreadsheet is edited.
Google Documentation - Spreadsheet On Edit
There is also a change trigger. It is an installable trigger, not a simple trigger.
Available types of triggers
Quote from documentation:
An installable change trigger runs when a user modifies the structure
of a spreadsheet itself — for example, by adding a new sheet or
removing a column.
I think the only thing that will work for you is the On Edit trigger. The trigger gets set from the Resources menu in the Apps Script Code editor.
I don't think you can restrict the code from running only to a certain cell, or a certain value within a cell. The code will run every time you edit ANY cell.
I think that the only other alternative would be to run a time based trigger, and have the script get the value of that cell, and check the value. The shortest time interval you can use is to run a script every minute. So if you edited the cell on second 1, it would take 59 more seconds before anything happened.
If you had some type of user interface, and the value in that cell was written to when the user entered a value in an input field, you could detect that change immediately, and make something happen.