Hide Rows onEdit in Google Sheets - google-apps-script

I need a script triggered by a yes/no field in B2 to hide all rows in Budget_01 sheet wherever 0 is found in column B. For example in table Budget_01:
BUDGET_01 TABLE WITH HIDE ZERO [B2]= "No" All rows unhidden
Budget_01
Hide Zero|No
Expense | Amount | Frequency
Car loan 500.00 1
Gas 0 0
Music 0 1
Supplies 50 20
....
Books 0 0
BUDGET_01 TABLE WITH HIDE ZERO [B2]= "Yes" All rows where column B = $0 hidden
Budget_01
Hide Zero|Yes
Expense | Amount | Frequency
Car loan 500.00 1
Supplies 50 20
This is my attempt that does not work:
function toggleRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Budget 01");
var cellValue = sheet.getRange("B2").getValue();
var sheets = ss.getSheets();
if(cellValue == 'No'){
for(var i = 0, iLen = sheets.length; i < iLen; i++) {
// get sheet
var sh = sheets[i];
// unhide rows
var rRows = sh.getRange("A1:A");
sh.unhideRow(rRows);
}
}
if(cellValue == 'Yes'){
ss.showRows(1, ss.getMaxRows());
ss.getRange('B1:B')
.getValues()
.forEach(function (r, i) {
if (r[0] !== '' && r[0].toString()
.charAt(0) == 0) ss.hideRows(i + 1)
});
}
}

Rather than use the yes/no drop down to launch the script I inserted two graphic buttons (insert > drawing square button) marked with yes and no. I launched these two functions from each button:
function hide01Rows() {
// set up spreadsheet and sheet
var ss = SpreadsheetApp.getActiveSpreadsheet(), sheets = ss.getSheets();
for(var i = 0, iLen = sheets.length; i < iLen; i++) {
// get sheet
var sh = sheets[i];
sh.showRows(1, sh.getMaxRows());
sh.getRange('B:B')
.getValues()
.forEach(function (r, i) {
if (r[0] !== '' && r[0].toString()
.charAt(0) == 0) sh.hideRows(i + 1)
});
}
}
function unhide0Rows() {
// set up spreadsheet and sheet
var ss = SpreadsheetApp.getActiveSpreadsheet(), sheets = ss.getSheets();
for(var i = 0, iLen = sheets.length; i < iLen; i++) {
// get sheet
var sh = sheets[i];
// unhide rows
var rRows = sh.getRange("A:A");
sh.unhideRow(rRows);
}
}
This is not the most graceful solution but it does what I need.

Please change the function name of toggleRows() to onEdit(), and change B1 of "No" to "Yes". By this, when spreadsheet was edited, Budget_01--Unhidden becomes Budget_01--Hidden. If my interpretation was wrong, please tell me it.

Rather than using forEach, I used an else if statement to loop through the Yes condition.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1"); // Change for your sheet
// Check the condition
var cellValue = sheet.getRange("B1").getValue();
// To hide/unhide, you need a range, not the value. Split into to variables.
var range = sheet.getDataRange();
var values = range.getValues();
// Check the data being returned
Logger.log(cellValue);
Logger.log(values);
// If "No," unhide the entire range.
if(cellValue == "No" || "no") {
for(var i = 0; i < values.length; i++) {
Logger.log("Unhide all rows.");
sheet.unhideRow(range);
}
// If "Yes," loop through the data looking for 0's and hide the range.
} else if (cellValue == "Yes" || "yes") {
for(var i=0; i<values.length;i++) {
if(values[i][1] == 0) {
Logger.log("Found 0 at row " + i);
sheet.hideRow(sheet.getRange(i+1,1));
}
}
}
}

Related

Auto Filter based on cell Value in Google App Scripts [duplicate]

In this example, I have a set of data from a Google Sheet (4Cat) feeding into another sheet (ImportFeeder) where I am running my Google Script.
At the end of the script below, how can I insert a filter script to sort the data by Row K? (only showing iPad products)
function myFunction() {
var sss = SpreadsheetApp.openById('1kL96dRm3Z8XBtMXnSzUARxR1b34-njlkZQ1sU0c3g1s'); //replace with source ID
var ss = sss.getSheetByName('4cat'); //replace with source Sheet tab name
var range = ss.getRange('A:I'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('1u7547KaniKHLUJn2v-ezN4l8ZcxE4viCFcoxsA904MI'); //replace with destination ID
var ts = tss.getSheetByName('Sheet1'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
var range = ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length)
var rawData = range.getValues() // get value from spreadsheet 2
var data = [] // Filtered Data will be stored in this array
for (var i = 0; i< rawData.length ; i++){
if(rawData[i][10] == "iPad") // Check to see if column K says ipad if not skip it
{
data.push(rawData[i])
}
}
}
(Cannot read property length from undefined)
4Cat Sample Data https://docs.google.com/spreadsheets/d/1kL96dRm3Z8XBtMXnSzUARxR1b34-njlkZQ1sU0c3g1s/edit?usp=sharing */
feeding into
ImportFeeder https://docs.google.com/spreadsheets/d/1u7547KaniKHLUJn2v-ezN4l8ZcxE4viCFcoxsA904MI/edit?usp=sharing
Required - Successful sheet to sheet import, filter data by Row K within Google Scripts. Add a clear() sheet function to the top of the script, as this will be running daily and the sheet needing clearing before daily import.
Why not using a custom filter function?
Added a .toLowerCase() to match "ipad" case insensitive.
function myFunction() {
var sss = SpreadsheetApp.openById('1kL96dRm3Z8XBtMXnSzUARxR1b34-njlkZQ1sU0c3g1s'); //replace with source ID
var ss = sss.getSheetByName('4cat'); //replace with source Sheet tab name
var range = ss.getRange('A:V'); //assign the range you want to copy
var rawData = range.getValues() // get value from spreadsheet 1
var data = rawData.filter(isColKiPad); // Filtered Data will be stored in this array
var tss = SpreadsheetApp.openById('1u7547KaniKHLUJn2v-ezN4l8ZcxE4viCFcoxsA904MI'); //replace with destination ID
var ts = tss.getSheetByName('Sheet1'); //replace with destination Sheet tab name
ts.getRange(2,1,ts.getLastRow() - 1,ts.getLastColumn()).clear(); // Assuming header is in the first row, clears sheet but header
ts.getRange(2, 1, data.length, data[0].length).setValues(data);
};
// Change both to ts.getRange(1,1,[...] if there's no header row
function isColKiPad(arr) {
return arr[10].toLowerCase() == "ipad";
};
Did you consider using a Spreadsheet formula? You could try a combination of =IMPORTRANGE(spreadsheet_key, string_range) and QUERY(data, query, [header]) to import your range already filtered :
=QUERY(IMPORTRANGE("1kL96dRm3Z8XBtMXnSzUARxR1b34-njlkZQ1sU0c3g1s";"4cat!A:V");"SELECT * WHERE Col11 = 'iPad'")
You won't even need to clear your sheet this way.
you can add this to your original code:
filterByText(rawData, 10, iPad);
It will work as long as you add this function after your myFunction function:
function filterByText(data, columnIndex, values) {
var value = values;
if (data.length > 0) {
if (typeof columnIndex != "number" || columnIndex > data[0].length) {
throw "Please, can you choose a valid column index?";
}
var r = [];
if (typeof value == "string") {
var reg = new RegExp(escape(value).toUpperCase());
for (var i = 0; i < data.length; i++) {
if (columnIndex < 0 && escape(data[i].toString()).toUpperCase().search(reg) != -1 || columnIndex >= 0 && escape(data[i][columnIndex].toString()).toUpperCase().search(reg) != -1) {
r.push(data[i]);
}
}
return r;
} else {
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < value.length; j++) {
var reg = new RegExp(escape(value[j]).toUpperCase());
if (columnIndex < 0 && escape(data[i].toString()).toUpperCase().search(reg) != -1 || columnIndex >= 0 && escape(data[i][columnIndex].toString()).toUpperCase().search(reg) != -1) {
r.push(data[i]);
j = value.length;
}
}
}
return r;
}
} else {
return data;
}
}
Above is the code used by Google Apps Script's ArrayLib library filterByText method. I literally just copied it and made the throw friendlier.
Your full code could look something like this:
function myFunction() {
var sss = SpreadsheetApp.openById('1kL96dRm3Z8XBtMXnSzUARxR1b34-njlkZQ1sU0c3g1s'); //replace with source ID
var ss = sss.getSheetByName('4cat'); //replace with source Sheet tab name
var range = ss.getRange('A:I'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('1u7547KaniKHLUJn2v-ezN4l8ZcxE4viCFcoxsA904MI'); //replace with destination ID
var ts = tss.getSheetByName('Sheet1'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
var range = ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length)
var rawData = range.getValues() // get value from spreadsheet 2
var data = filterByText(rawData, 10, iPad); // rawData is now sorted.
range.clear();
var powerRange = ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length);
powerRange.setValues(data);
}
function filterByText(data, columnIndex, values) {
var value = values;
if (data.length > 0) {
if (typeof columnIndex != "number" || columnIndex > data[0].length) {
throw "Please, can you choose a valid column index?";
}
var r = [];
if (typeof value == "string") {
var reg = new RegExp(escape(value).toUpperCase());
for (var i = 0; i < data.length; i++) {
if (columnIndex < 0 && escape(data[i].toString()).toUpperCase().search(reg) != -1 || columnIndex >= 0 && escape(data[i][columnIndex].toString()).toUpperCase().search(reg) != -1) {
r.push(data[i]);
}
}
return r;
} else {
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < value.length; j++) {
var reg = new RegExp(escape(value[j]).toUpperCase());
if (columnIndex < 0 && escape(data[i].toString()).toUpperCase().search(reg) != -1 || columnIndex >= 0 && escape(data[i][columnIndex].toString()).toUpperCase().search(reg) != -1) {
r.push(data[i]);
j = value.length;
}
}
}
return r;
}
} else {
return data;
}
}
You can find the documentation on sorting in a range here. To sort select a range using getRange and then sort function like so
var range = ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length)
// Use the below line instead, if you want to sort whole sheet, not just the newly entered data!
// var range = ts.getDataRange()
range.sort(11) // sort based on column number 11
Edit 1:
To filter only values based on the column to copy into the new sheet you will do need to trim the data you get from a sheet of all values you don't need.
var rawData = range.getValues() // get value from spreadsheet1
var data = [] // Filtered Data will be stored in this array
for (var i = 0; i< rawData.length ; i++){
if(rawData[i][10] == "iPAD") // Check to see if column K says ipad if not skip it
{
data.push(rawData[i])
}
}
// Now you can paste array data to your new spreadsheet like before.
Edit 2: This how the final code should look like,
function myFunction() {
var sss = SpreadsheetApp.openById('1kL96dRm3Z8XBtMXnSzUARxR1b34-njlkZQ1sU0c3g1s'); //replace with source ID
var ss = sss.getSheetByName('4cat'); //replace with source Sheet tab name
var range = ss.getRange('A:V'); //assign the range you want to copy
var rawData = range.getValues() // get value from spreadsheet 1
var data = [] // Filtered Data will be stored in this array
for (var i = 0; i< rawData.length ; i++){
if(rawData[i][10] == "iPad") // Check to see if column K says ipad if not skip it
{
data.push(rawData[i])
}
}
var tss = SpreadsheetApp.openById('1u7547KaniKHLUJn2v-ezN4l8ZcxE4viCFcoxsA904MI'); //replace with destination ID
var ts = tss.getSheetByName('Sheet1'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
}

Collecting a Gmail Username when a Button is Pressed In Google Sheets

I am creating a bathroom sign out sheet for my middle school students. I have created a Google App Script that Collects students names from a dropdown box and then logs the date and time. Everything seems to work great except when 500 students have access to the sheet at the same time. If a student selects their name it can possibly change before the script can be run. I would like to replace the dropdown box with a script that will automatically grab their Google User Name. Is there anyway this can be done? I am a novice programmer and tend to get things to work by tinkering around with it, but this seems to be above my head. Here is the Google Sheet and the Script is attached as well. Thanks in advance
https://docs.google.com/spreadsheets/d/e/2PACX-1vR36FnMTbJV4Nl8X8x_VyG107Y8Q-oCSgfG3ITEvaMjSraMv-bUH2u4FuWSE74Qg1gCrO5bg12pvawe/pubhtml
function clockIn()
{
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
for (var j = 5; j <= lastRow; j++)
{
// CHECK CLOCK IN
if(mainSheet.getRange('B1:B1').getValue() == mainSheet.getRange(j, 1).getValue() && mainSheet.getRange(j,3).getValue() == '')
{
Browser.msgBox("⚠️ You are Already Signed Out","Please Click the Returning to Classroom Button and then Try Again!",Browser.Buttons.OK);
return;
}
}
//_________________________________________________________________________________________________________________________________________________//
// ADD CLOCK IN RECORD
mainSheet.getRange(lastRow+1,1).setValue(mainSheet.getRange('B1:B1').getValue()).setFontSize(12);
mainSheet.getRange(lastRow+1,2).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss A/P").setHorizontalAlignment("left").setFontSize(12);
//CLEARCONTENTS
{
var sheet = ss.getSheetByName("MAIN");
sheet.getRange('B1:B2').clearContent();
}
if (mainSheet.getRange('B1:B1').getValue() == mainSheet.getRange('B1:B1').getValue() && mainSheet.getRange(j,3).getValue() == '')
{
SpreadsheetApp.getUi().alert("⏰ Please Hurry Back! ⏰","Your Teacher is Waiting",SpreadsheetApp.getUi().ButtonSet.OK);
}
}
//_________________________________________________________________________________________________________________________________________________//
function clockOut() {
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
var foundRecord = false;
for (var j = 5; j <= lastRow; j++)
{
// FIND CLOCK IN RECORD
if(mainSheet.getRange('B1:B1').getValue() == mainSheet.getRange(j, 1).getValue() && mainSheet.getRange(j,3).getValue() == '')
{
SpreadsheetApp.getUi().alert("🙏 Thank You! 🙏"," " ,SpreadsheetApp.getUi().ButtonSet.OK);
// UPDATE CLOCK IN RECORD
mainSheet.getRange(j,3).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss A/P").setHorizontalAlignment("left").setFontSize(12);
var totalTime = (mainSheet.getRange(j,3).getValue() - mainSheet.getRange(j,2).getValue()) /(60*100*1000);
mainSheet.getRange(j,4).setValue(totalTime.toFixed(2)).setNumberFormat("#0.00").setHorizontalAlignment("left").setFontSize(12);
foundRecord = true;
}
}
//CLEARCONTENTS
{
var sheet = ss.getSheetByName("MAIN");
sheet.getRange('B1:B2').clearContent();
}
// IF NO CLOCK IN RECORD
if(foundRecord == false)
{
SpreadsheetApp.getUi().alert("⚠️ No Record ⚠️","You Might Have Forget to Sign Out?" ,SpreadsheetApp.getUi(). ButtonSet.OK);
}
}
//_________________________________________________________________________________________________________________________________________________//
// CALL TOTAL HOURS
TotalHours();
function TotalHours()
{
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
//DEFINE ARRAY
var totals = [];
//LOOP THROUGH ALL RATES
for (var j = 5; j <= lastRow; j++)
{
var rate = mainSheet.getRange(j, 4).getValue();
var name = mainSheet.getRange(j, 1).getValue();
var foundRecord = false;
for(var i = 0; i < totals.length; i++)
{
//FOUND RECORD ADD TO TOTAL
if(name == totals[i][0] && rate != '')
{
totals[i][1] = totals[i][1] + rate;
foundRecord = true;
}
}
//ADD NEW RECORD, EXISTING RECORD NOT FOUND
if(foundRecord == false && rate != '')
{
totals.push([name, rate]);
}
}
//CLEAR DATA
mainSheet.getRange("F5:G1000").clear();
//DISPLAY TOTALS
for(var i = 0; i < totals.length; i++)
{
mainSheet.getRange(5+i,6).setValue(totals[i][0]).setFontSize(12);
mainSheet.getRange(5+i,7).setValue(totals[i][1]).setFontSize(12);
}
}
//_________________________________________________________________________________________________________________________________________________//
function ClearCells()
{
var sheet = SpreadsheetApp.getActive().getSheetByName('DATASHEET');
sheet.getRange('A5:G1000').clearContent();
}
//_________________________________________________________________________________________________________________________________________________//
function clearRange()
{
// replace 'Sheet1' with your actual sheet name
// replace 'dhrhrejYOURSHETIDerhe5j54j5j' with your actual sheet ID
var sheetActive = SpreadsheetApp.openById("1sjx0UAv73wiW-Jo1e8QWZuanjKK2tsjveVXjB1y_IHw").getSheetByName("DATASHEET");
sheetActive.getRange('A5:G1000').clearContent();
}
//_________________________________________________________________________________________________________________________________________________//
``
This works for me:
function getUserEmail() {
SpreadsheetApp.getActive().toast(Session.getActiveUser().getEmail());
}
But it may not work all of the time because of a complex set of security protocols which I know nothing about.
Since you are pertaining to the email address of the user, you can use Session.getActiveUser() which will give you the current user, then use getEmail() to get the current user's email address. Similar to what #Cooper suggested
You just need to use them in your clockIn() and clockOut():
function clockIn()
{
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
for (var j = 5; j <= lastRow; j++)
{
// CHECK CLOCK IN
if(Session.getActiveUser().getEmail() == mainSheet.getRange(j, 1).getValue() && mainSheet.getRange(j,3).getValue() == '')
{
Browser.msgBox("⚠️ You are Already Signed Out","Please Click the Returning to Classroom Button and then Try Again!",Browser.Buttons.OK);
return;
}
}
//_________________________________________________________________________________________________________________________________________________//
// ADD CLOCK IN RECORD
mainSheet.getRange(lastRow+1,1).setValue(Session.getActiveUser().getEmail()).setFontSize(12);
mainSheet.getRange(lastRow+1,2).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss A/P").setHorizontalAlignment("left").setFontSize(12);
//CLEARCONTENTS
{
var sheet = ss.getSheetByName("MAIN");
sheet.getRange('B1:B2').clearContent();
}
if (Session.getActiveUser().getEmail() == Session.getActiveUser().getEmail() && mainSheet.getRange(j,3).getValue() == '')
{
SpreadsheetApp.getUi().alert("⏰ Please Hurry Back! ⏰","Your Teacher is Waiting",SpreadsheetApp.getUi().ButtonSet.OK);
}
}
//_________________________________________________________________________________________________________________________________________________//
function clockOut() {
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
var foundRecord = false;
for (var j = 5; j <= lastRow; j++)
{
// FIND CLOCK IN RECORD
if(Session.getActiveUser().getEmail() == mainSheet.getRange(j, 1).getValue() && mainSheet.getRange(j,3).getValue() == '')
{
SpreadsheetApp.getUi().alert("🙏 Thank You! 🙏"," " ,SpreadsheetApp.getUi().ButtonSet.OK);
// UPDATE CLOCK IN RECORD
mainSheet.getRange(j,3).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss A/P").setHorizontalAlignment("left").setFontSize(12);
var totalTime = (mainSheet.getRange(j,3).getValue() - mainSheet.getRange(j,2).getValue()) /(60*100*1000);
mainSheet.getRange(j,4).setValue(totalTime.toFixed(2)).setNumberFormat("#0.00").setHorizontalAlignment("left").setFontSize(12);
foundRecord = true;
}
}
//CLEARCONTENTS
{
var sheet = ss.getSheetByName("MAIN");
sheet.getRange('B1:B2').clearContent();
}
// IF NO CLOCK IN RECORD
if(foundRecord == false)
{
SpreadsheetApp.getUi().alert("⚠️ No Record ⚠️","You Might Have Forget to Sign Out?" ,SpreadsheetApp.getUi(). ButtonSet.OK);
}
}
//_____
Another option is to use promt dialog to ask user to input their name when clockIn() or clockOut() was called. Then change the inputted name to capital letters.
Your Code:
function clockIn()
{
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Enter your name:',ui.ButtonSet.OK_CANCEL);
var studentName;
// Process the user's response.
if (response.getSelectedButton() == ui.Button.OK) {
Logger.log('The user\'s name is %s.', response.getResponseText());
studentName = studentName.toUpperCase();
studentName = response.getResponseText();
} else {
Logger.log('Request was cancelled.');
return;
}
for (var j = 5; j <= lastRow; j++)
{
// CHECK CLOCK IN
if(studentName == mainSheet.getRange(j, 1).getValue() && mainSheet.getRange(j,3).getValue() == '')
{
Browser.msgBox("⚠️ You are Already Signed Out","Please Click the Returning to Classroom Button and then Try Again!",Browser.Buttons.OK);
return;
}
}
//_________________________________________________________________________________________________________________________________________________//
// ADD CLOCK IN RECORD
mainSheet.getRange(lastRow+1,1).setValue(studentName).setFontSize(12);
mainSheet.getRange(lastRow+1,2).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss A/P").setHorizontalAlignment("left").setFontSize(12);
//CLEARCONTENTS
{
var sheet = ss.getSheetByName("MAIN");
sheet.getRange('B1:B2').clearContent();
}
if (studentName == studentName && mainSheet.getRange(j,3).getValue() == '')
{
SpreadsheetApp.getUi().alert("⏰ Please Hurry Back! ⏰","Your Teacher is Waiting",SpreadsheetApp.getUi().ButtonSet.OK);
}
}
//_________________________________________________________________________________________________________________________________________________//
function clockOut() {
//DEFINE ALL ACTIVE SHEETS
var ss = SpreadsheetApp.getActiveSpreadsheet();
//DEFINE MAIN SHEET
var mainSheet = ss.getSheetByName("DATASHEET");
//LAST ROW ON MAIN SHEET
var lastRow = mainSheet.getLastRow();
var foundRecord = false;
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Enter your name:',ui.ButtonSet.OK_CANCEL);
var studentName;
// Process the user's response.
if (response.getSelectedButton() == ui.Button.OK) {
Logger.log('The user\'s name is %s.', response.getResponseText());
studentName = response.getResponseText();
studentName = studentName.toUpperCase();
} else {
Logger.log('Request was cancelled.');
return;
}
for (var j = 5; j <= lastRow; j++)
{
// FIND CLOCK IN RECORD
if(studentName == mainSheet.getRange(j, 1).getValue() && mainSheet.getRange(j,3).getValue() == '')
{
SpreadsheetApp.getUi().alert("🙏 Thank You! 🙏"," " ,SpreadsheetApp.getUi().ButtonSet.OK);
// UPDATE CLOCK IN RECORD
mainSheet.getRange(j,3).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss A/P").setHorizontalAlignment("left").setFontSize(12);
var totalTime = (mainSheet.getRange(j,3).getValue() - mainSheet.getRange(j,2).getValue()) /(60*100*1000);
mainSheet.getRange(j,4).setValue(totalTime.toFixed(2)).setNumberFormat("#0.00").setHorizontalAlignment("left").setFontSize(12);
foundRecord = true;
}
}
//CLEARCONTENTS
{
var sheet = ss.getSheetByName("MAIN");
sheet.getRange('B1:B2').clearContent();
}
// IF NO CLOCK IN RECORD
if(foundRecord == false)
{
SpreadsheetApp.getUi().alert("⚠️ No Record ⚠️","You Might Have Forget to Sign Out?" ,SpreadsheetApp.getUi(). ButtonSet.OK);
}
}
//_____

Googlesheet adding unwanted rows

I have two sheets (Sheet1 and Mirror) in a single google spreadsheet. I have some columns in the Mirror sheet which are being mirrored from Sheet1 using an array formula (={"Firstname";ARRAYFORMULA(INDIRECT("Sheet1!B2:B"))}).
I have rows being copied automatically from a google form into Sheet1. For some reason, periodically, about 500 empty rows are entered into the Mirror sheet and I have to manually delete them.
I have these googlesheet functions below that trigger on change. I have only deployed the function ReadRows and it works like a charm. Rather than deploying the second function (DeleteBlankRows) which might slow down my spreadsheet, I do like to know how I can figure out what is causing the extra periodic 500 blank rows to appear and stop it or I'd like any professional advice you can give.
Please see the sample scripts below. Thanks in advance.
function readRows() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if ((row[1] == 0 || row[1] == '') && (row[2] == 0 || row[2] == '')){
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
}
};
function DeleteBlankRows() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Mirror');
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if ((row[1] == 0 || row[1] == '')){
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
}
};
Updated answer:
The issue is that you need to delete the rows backwards for Sheet1 and then you don't need to use DeleteBlankRows for Mirror anymore. Replace your code with this one:
function readRows() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var rows = sheet.getDataRange();
var values = rows.getValues();
for (var i = values.length - 1; i>=0; i--) {
var row = values[i];
if ((row[1] == 0 || row[1] == '') && (row[2] == 0 || row[2] == '')){
sheet.deleteRow(i+1);
}
}
};
To get rid of empty rows, you can simply filter them out before you copy them to the target sheet.
Change:
var values = rows.getValues();
to:
var values = rows.getValues().filter(r=>r[0]!='');
Assuming for every empty row, the cell in column A is also empty.
You can now remove the DeleteBlankRows unless you want to delete also the rows.

Drop down to hide rows based on a dropdown

In Google Sheets I want to hide rows 5 to 31 when my drop down in R4 says BLS, and show those cells if R4 is blank or says ALS.
Here is my most recent attempt:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Shee1");
var rg = sh.getDataRange();
var vA = rg.getValues();
var R4 = sh.getRange("R4").getValue();
for (var i = 0; i < vA.length; i++) {
var row = i + 1;
switch (R4) {
case "BLS":
if (row >= 5 && row <= 31) {
sh.hideRows(row);
}
break;
case "ALS":
if (row >= 4 && row <= 32) {
sh.showRows(row);
}
break;
default:
}
}
}
I have also tried this, which points to 2 different macros that I recorded but it makes the screen go crazy and jumps around whenever something else is edited:
function onEdit(){
if(SpreadsheetApp.getActiveSheet().getRange('R4').getValue() == "BLS") BLS(); // Launches the script
if(SpreadsheetApp.getActiveSheet().getRange('R4').getValue() == "ALS") ALS(); // Launches the script
}
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sheet1"); // Enter sheet name
var row = s.getRange('R:R').getValues();
// Enter column letter that has the text "hide" and "unhide"
s.showRows(1, s.getMaxRows());
for(var i=0; i< row.length; i++){ if(row[i] == 'hide') { s.hideRows(i+1, 27); }
else if(row[i] == 'unhide'){ s.unhideRow(ss.getDataRange()); }
}
}

How do I determine if a column is hidden in Google Spreadsheet using scripts?

I'm trying to write a function for Google Spreadsheet that locates the first and last column of a group. It then hides the group, or shows it if it's already hidden.
However, I haven't been able to find a way to determine whether a column is hidden or not. I haven't been able to find anything anything on Google's Class Sheet page https://developers.google.com/apps-script/reference/spreadsheet/sheet, and I haven't found an equivalent to Excel's .hidden
getColumnWidth(column) returns the unhidden column width even when it's hidden.
Here's my code:
function hideShowColumns(startCol, endCol) {
//endCol is one column past the last data set that should be hidden
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Transposed Data");
//import the data from the Column Headers
var colHeaderData = sheet.getRange(1, 1, 2, sheet.getMaxColumns()).getValues();
var startColNum = 0;
var endColNum = 0;
// This section searches for the column names in the header rows and returns their column number
for (var i =0; i < 2; ++i) {
for (var j = 0; j < colHeaderData[0].length; ++j) {
if (colHeaderData[i][j] == startCol)
startColNum = j;
if (colHeaderData[i][j] == endCol)
endColNum = j;
}
}
//This is the wrong command getColumnWidth doesn't change if column is hidden
if (sheet.getColumnWidth(startColNum + 1) != 0) {
sheet.hideColumns(startColNum + 2, endColNum - startColNum - 1);
Logger.log(sheet.getColumnWidth(startColNum + 2));
return;
}
//This is the wrong command getColumnWidth doesn't change if column is hidden
if (sheet.getColumnWidth(startColNum + 1) == 0) {
for (var j = startColNum + 1; j < endColNum - 1; ++j) {
sheet.unhideColumn(j);
Logger.log(sheet.getColumnWidth(startColNum + 2));
}
return;
}
}
Thanks for the help!
The new (as of 2018) api for this is: isColumnHiddenByUser(columnPosition)
Returns whether the given column is hidden by the user.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// Columns start at 1
Logger.log(sheet.isColumnHiddenByUser(1));
Unfortunately there is no Google Apps Script method that will return whether a column or row is hidden or not. You might like to star the issue opened for it, as a way of a. receiving updates about the issue, and b. "signing the petition", so to speak.
https://code.google.com/p/google-apps-script-issues/issues/detail?id=195&q=hidden%20column&colspec=Stars%20Opened%20ID%20Type%20Status%20Summary%20Component%20Owner
A workaround. Create 2 rows. The first must always have a value and the second has a set of formulas. These 2 rows look like this:
| A | B | C |
---------------------------------------------------------------------------------
1 | 1 | 1 | 1 |
2 | =NOT(SUBTOTAL(103, A1)) | =NOT(SUBTOTAL(103, B1)) | =NOT(SUBTOTAL(103, C1)) |
SUBTOTAL returns a subtotal using a specified aggregation function. The first argument 103 defines the type of function used for aggregation. The second argument is the range to apply the function to.
3 means COUNTA and counts the number of values in the range
+100 means ignore hidden cells in the range.
The result of SUBTOTAL with a range of 1 cell will be 0 when the cell is hidden and 1 when the cell is shown. NOT inverts it.
Now your can read the second row with your script to know if a column is hidden.
Here's the transposed question and answer: https://stackoverflow.com/a/27846202/1385429
Sorry, I also could not find a way and stumbled upon this stack overflow.
But I might as well share this script somewhere.
I use the first column as a place holder for a -- or || value to tell if its hidden or shown. (Not the best but its all I could seem to find)
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name: "Toggle Rows",
functionName: "toggleRows"
},{
name: "Hide Rows",
functionName: "hideRows"
},{
name: "Show Rows",
functionName: "showRows"
}];
sheet.addMenu("Script", entries);
};
function toggleRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var maxRows = sheet.getMaxRows();
var r = sheet.getRange(1, 1, maxRows+1);
var values = r.getValues();
var hideRanges = [];
var showRanges = [];
var toggleValue = null;
var startRow = null;
var tmp;
var len = values.length;
var i;
for (i = 0; i < len; i++) {
tmp = values[i][0];
if (startRow === null && (tmp === '--' || tmp === '||')) {
startRow = i + 1;
toggleValue = tmp;
} else if (startRow !== null && tmp !== toggleValue) {
if (toggleValue === '--') {
hideRanges.push([startRow, (i + 1) - startRow]);
} else {
showRanges.push([startRow, (i + 1) - startRow])
}
if (tmp === '--' || tmp === '||') {
startRow = i + 1;
toggleValue = tmp;
} else {
startRow = null;
}
}
}
var customRange = null;
var range = null;
i = hideRanges.length;
while (i--) {
customRange = hideRanges[i];
range = sheet.getRange(customRange[0], 1, customRange[1]);
range.setValue('||');
sheet.hideRows(customRange[0], customRange[1]);
}
i = showRanges.length;
while (i--) {
customRange = showRanges[i];
range = sheet.getRange(customRange[0], 1, customRange[1]);
range.setValue('--');
sheet.showRows(customRange[0], customRange[1]);
}
};
function hideRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var maxRows = sheet.getMaxRows();
var r = sheet.getRange(1, 1, maxRows+1);
var values = r.getValues();
var startRow = null;
var tmp;
var len = values.length;
var i;
for (i = 0; i < len; i++) {
tmp = values[i][0];
if (startRow === null && (tmp === '--' || tmp === '||')) {
startRow = i + 1;
} else if (startRow !== null && (tmp !== '--' && tmp !== '||')) {
var numRows = (i + 1) - startRow;
sheet.getRange(startRow, 1, numRows).setValue('||');
sheet.hideRows(startRow, numRows);
startRow = null;
}
}
};
function showRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var maxRows = sheet.getMaxRows();
var r = sheet.getRange(1, 1, maxRows+1);
var values = r.getValues();
var startRow = null;
var tmp;
var len = values.length;
var i;
for (i = 0; i < len; i++) {
tmp = values[i][0];
if (startRow === null && (tmp === '--' || tmp === '||')) {
startRow = i + 1;
} else if (startRow !== null && (tmp !== '--' && tmp !== '||')) {
var numRows = (i + 1) - startRow;
sheet.getRange(startRow, 1, numRows).setValue('--');
sheet.showRows(startRow, numRows);
startRow = null;
}
}
};
See here for any updates: https://gist.github.com/LiamKarlMitchell/81cef19a530261c4af93
As of 2018, Google hasn't added row/col visibility methods to the Sheets API yet. Now, late 2018, they created an API for this.
That's sad but I found another way:
When a row is the last one visible, you cannot hide it (same with columns). Google Spreadsheet throws an error and shows you a message. So, when a script function hides every row except the one we want to check, if it fails, our row was hidden. If the run is successful, it means that our row was visible.
Please be advised that this work-around is too hackerish to be used in a performance sensitive script.
Usage examples:
var sheet = SpreadsheetApp.getActive().getActiveSheet()
// Is the tenth row hidden?
isRowHidden(sheet.getRange('B10'))
// Is column B hidden?
isColumnHidden(sheet.getRange('B10'))
// Is cell B10 visible? (not in a hidden row and/or column)
!(isCellHidden(sheet.getRange('B10')))
Code
/**
* Takes the first row of a range and checks whether is hidden or not.
* Second parameter is an optional sheet. Defaults to the active sheet.
* #param {range} row
* #param {sheet} [sheet]
* #returns {boolean} True if row is hidden, false if it is visible.
*/
function isRowHidden (row, optionalSheet) {
var ss = SpreadsheetApp.getActive()
var sheet = optionalSheet || ss.getActiveSheet()
SpreadsheetApp.setActiveSheet(sheet)
var dup = ss.duplicateActiveSheet()
SpreadsheetApp.setActiveSheet(sheet)
var isHidden = false
var rowIndex = row.getRow()
var numRows = dup.getMaxRows()
if (numRows === 1) {
ss.deleteSheet(dup)
return false
}
try {
if (rowIndex === numRows ) {
dup.hideRows(1, numRows - 1)
} else if (rowIndex === 1) {
dup.hideRows(rowIndex + 1, numRows - 1)
} else {
dup.hideRows(1, rowIndex - 1)
dup.hideRows(rowIndex + 1, numRows - rowIndex)
}
isHidden = false
} catch (e) {
isHidden = true
} finally {
ss.deleteSheet(dup)
}
return isHidden
}
/**
* Takes the first column of a range and checks whether is hidden or not.
* Second parameter is an optional sheet. Defaults to the active sheet.
* #param {range} column
* #param {sheet} [sheet]
* #returns {boolean} True if column is hidden, false if it is visible.
*/
function isColumnHidden (col, optionalSheet) {
var ss = SpreadsheetApp.getActive()
var sheet = optionalSheet || ss.getActiveSheet()
SpreadsheetApp.setActiveSheet(sheet)
var dup = ss.duplicateActiveSheet()
SpreadsheetApp.setActiveSheet(sheet)
var isHidden = false
var colIndex = col.getColumn()
var numCols = dup.getMaxColumns()
if (numCols === 1) {
ss.deleteSheet(dup)
return false
}
try {
if (colIndex === numCols ) {
dup.hideColumns(1, numCols - 1)
} else if (colIndex === 1) {
dup.hideColumns(colIndex + 1, numCols - 1)
} else {
dup.hideColumns(1, colIndex - 1)
dup.hideColumns(colIndex + 1, numCols - colIndex)
}
isHidden = false
} catch (e) {
isHidden = true
} finally {
ss.deleteSheet(dup)
}
return isHidden
}
/**
* Takes the first cell of a range and checks whether is hidden or not.
* Second parameter is an optional sheet. Defaults to the active sheet.
* #param {range} cell
* #param {sheet} [sheet]
* #returns {boolean} True if cell is hidden, false if it is visible.
*/
function isCellHidden (cell, optionalSheet) {
var isHidden = isColumnHidden(cell, optionalSheet) || isRowHidden(cell, optionalSheet)
return isHidden
}
PS: Code follows JS Standard Style.