Getting the last non-empty cell in a column - javascript

I have a script that is adding or substracting a value (picked up in M2 cell) in each cell of a selected range (I mean a range that I can select with the mouse) :
function moreLess() {
var ss = SpreadsheetApp.getActive();
var sel = ss.getSelection().getActiveRangeList().getRanges();
for (var i=0; i<sel.length; i++) {
var range = sel[i];
var values = range.getValues();
var number = SpreadsheetApp.getActive().getSheetByName("sommaire_redac").getRange('M2').getValue();
for (var j=0; j<values.length; j++) {
for (var k=0; k<values[0].length; k++) {
values[j][k] += number;
}
}
range.setValues(values);
}
}
This works. But instead of selecting all the cells in which I want add or substract a value, I would like to select only one cell, and have a script that would select a range from this selected cell to the last non-empty cell of the column.
For example, instead of selecting cells T30:T36 like this…
with the code I have today
… I would like to select only T30, like this…
with the code I'd like to have
… and then I would like the script to get the last non-empty cell of the column (T36) and select the range T30:T36.
I mean I would like to get exactly the same result by selecting only T30 cell, that I today obtain by selecting T30:T36.
Thanks !

Using your own script, you could add a second line between var ss and var sel like this:
var ss = SpreadsheetApp.getActive();
ss.getSelection().getNextDataRange(SpreadsheetApp.Direction.DOWN).activate()
var sel = ss.getSelection().getActiveRangeList().getRanges();
It will select the remaining rows of that column ;)

This script helps you to find the last empty row of a column.
function lastEmpty(col) {
const sss = SpreadsheetApp.getActiveSpreadsheet();
const ss = sss.getActiveSheet();
const getlastEmptyRow = (colValues) => {
return colValues.length - colValues.reverse().findIndex(row => !!row[0]);
}
const colValues = ss.getRange(col+":"+col).getValues();
const lastEmptyRow = getlastEmptyRow(colValues);
return lastEmptyRow;
}
console.log(`last empty row in column T is ${lastEmpty('T')}`)

Related

How to loop through each column in a given row and then have the loop go automatically to the next column

I need to extract a data from this other sheet where the header will repeat itself by the number of items under it. So far I can only do this with the first column from the data source and I can’t seem to get the right code where the loop will go through the next column once it detects the first empty cell of the previous column.
Here’s where I am getting stuck
function filter(){
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var data = sheet.getSheetByName("data")
var filter = sheet.getSheetByName("filter")
var dataRange = data.getDataRange().getValues();
var dataLr = data.getLastRow();
var dataLc = data.getLastColumn();
var row = 1
var col = 1
for(var i=1; i < dataRange.length; i++){
let targetAppName = filter.getRange(i+1,1)
let targetQname = filter.getRange(i+1,2)
targetQname.setValue(dataRange[i])
targetAppName.setValue(dataRange[0][0])
}
}
I’m trying to get these results in another sheet tab:
|Names | Subjects |
|:—————|:———————-:|
|Michael Lowry| Trigonometry|
|Michael Lowry| Biology|
And so on, until it reads all columns and rows of the data range
Loop throught each column of each row
function loopthroughteachcolumnofarow() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const vs = sh.getDataRange().getValues();
vs.forEach((r,i) => {
r.forEach((c,j) => {
//c is the value for vs[i][j];
})
})
}

Copy Selected Columns in One Sheet and Add Them To Selected Columns in Another Sheet

I would like to create a simple google apps script to copy specific column into another sheets.
Previously I tried using getLastRow but I get stuck to modify it.
var destinationSheetLastRow = destinationSheet.getDataRange().getLastRow();
Here is my spreadsheet: https://docs.google.com/spreadsheets/d/1rGvmlKCmbjDSCLCC2Kujft5e4ngbSLzJd2NYu0sxISs/edit?usp=sharing
And here is the modified script so far:
function pasteMultiCol(sourceSheet, destinationSheet,sourceColumns,destinationColumns, doneColumn){
var sourceDataRange = sourceSheet.getDataRange();
var sourceDataValues = sourceDataRange.getValues();
var sourcesheetFirstRow = 0;
var sourceSheetLastRow = sourceDataRange.getLastRow();
var destinationSheetLastRow = destinationSheet.getDataRange().getLastRow();
var pendingCount = 0;
//Find the row start for copying
for(i = 0; i < sourceDataValues.length; i++){
if(sourceDataValues[i][doneColumn-1] === "Copied"){
sourcesheetFirstRow++;
};
if(sourceDataValues[i][doneColumn-1] === ""){
pendingCount++;
};
};
//Update Source sheet first row to take into account the header
var header = sourceSheetLastRow-(sourcesheetFirstRow + pendingCount);
sourcesheetFirstRow = sourcesheetFirstRow+header;
// if the first row equals the last row then there is no data to paste.
if(sourcesheetFirstRow === sourceSheetLastRow){return};
var sourceSheetRowLength = sourceSheetLastRow - sourcesheetFirstRow;
//Iterate through each column
for(i = 0; i < destinationColumns.length; i++){
var destinationRange = destinationSheet.getRange(destinationSheetLastRow+1,
destinationColumns[i],
sourceSheetRowLength,
1);
var sourceValues = sourceDataValues.slice(sourcesheetFirstRow-1,sourceSheetLastRow);
var columnValues =[]
for(j = header; j < sourceValues.length; j++){
columnValues.push([sourceValues[j][sourceColumns[i]-1]]);
};
destinationRange.setValues(columnValues);
};
//Change Source Sheet to Copied.
var copiedArray =[];
for(i=0; i<sourceSheetRowLength; i++){copiedArray.push(["Copied"])};
var copiedRange = sourceSheet.getRange(sourcesheetFirstRow+1,doneColumn,sourceSheetRowLength,1)
copiedRange.setValues(copiedArray);
};
function runsies(){
var ss = SpreadsheetApp.openById("1snMyf8YZZ0cGlbMIvZY-fAXrI_dJpPbl7rKcYCkPDpk");
var source = ss.getSheetByName("Source");
var destination = ss.getSheetByName("Destination");
var sourceCols = [4,5,6,7,8,9,10];
var destinationCols = [7,8,9,10,11,12,13];
var doneCol = 12
//Run our copy and append function
pasteMultiCol(source,destination, sourceCols, destinationCols, doneCol);
};
Your code is taken from my tutorial in my blog article Copy Selected Columns in One Sheet and Add Them To The Bottom of Different Selected Columns in Another Sheet and it just needs a tweak.
I think the issue might be that you have a bunch of formulas in other columns in your "Destination" Sheet tab. So getting the last row of the sheet will result in getting the last row considering all the data including your other formulas.
You might find this explanation in a follow up blog article I wrote helpful: Google Apps Script: Get the last row of a data range when other columns have content like hidden formulas and check boxes
In short, you can change the destinationSheetLastRow variable to something simple like this.
var destinationSheetLastRow = (()=>{
let destinationSheetFirstRow = 7; // The first row of data after your header.
//Get a sample range to find the last value in the paste columns.
let sampleRange = destinationSheet.getRange(destinationSheetFirstRow,
destinationColumns[0],
destinationSheet.getLastRow())
.getValues();
let sampleLastRow = 0;
while(sampleLastRow < sampleRange.length){
if (sampleRange[sampleLastRow][0] == ""){
break;
}
sampleLastRow++;
};
return sampleLastRow;
})()

How to hide columns with less than one input in Google sheets script?

I have a very large data set with clients and prices but not all clients get charged every price. When I filter out a client, I need to be able to run a macro to hide all of the columns that do not have a price associated with the header. I had the macro in Excel working fine but cannot transfer it into google sheets.
Excel VBA that worked perfectly:
Sub KolumnHider()
Dim wf As WorksheetFunction
Dim i As Long, r As Range
Set wf = Application.WorksheetFunction
For i = 1 To 1000
Set r = Cells(1, i).EntireColumn
If wf.Subtotal(3, r) < 2 Then r.Hidden = True
Next i
End Sub
This formula below is almost what I need. My issue is that I need it to hide the columns based on what is showing. When I filter out the data, I then want to run the macro and hide the columns with empty cells. It works when I filter to the certain row that 'ss.GetRange(3,1,1)' implies. For this example, If I filter to row 3 it works, but I have to change the code to say 6,1,1 for it to hide the correct info on row 6. I need it to hide only the row showing. Please help!
function hideEmptyHeaders() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var headers = ss.getRange(3, 1, 1, ss.getMaxColumns()).getValues()[0];
var columnIndex = 0, numColumns = 0;
headers.forEach(function(header, index) {
if (!header) {
if (!columnIndex)
columnIndex = index + 1;
numColumns++;
} else if (columnIndex > 0) {
ss.hideColumns(columnIndex, numColumns);
columnIndex = numColumns = 0;
}
});
if (columnIndex > 0) ss.hideColumns(columnIndex, numColumns);
}
Try this:
function hideBlankColumns() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var width=rg.getWidth();//could also be sh.getMaxColumns()
for(var c=1;c<=width;c++) {
if(getColHeight(c,sh,ss)==0) {
sh.hideColumns(c);
}
}
}
function getColHeight(col,sh,ss){
var ss=ss || SpreadsheetApp.getActive();
var sh=sh || ss.getActiveSheet();
var col=col || sh.getActiveCell().getColumn();
var rg=sh.getRange(1,col,sh.getLastRow(),1);
var vA=rg.getValues();
if(vA) {
while(vA.length && vA[vA.length-1][0].length==0){
vA.splice(vA.length-1,1);
}
return vA.length;
}
return 0;
}
Try this,
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var i;
var j;
for(i=1;i<=1000;i++)
{
var count = 0;
var r = sheet.getLastRow();
for(j=1;j<r;j++)
{
if(!sheet.getRange(j,i).isBlank())
{
count++;
}
}
if(count < 2)
{
sheet.hideColumns(i);
}
}
}
Problem
You have rows hidden by a filter
You want to hide all columns, which do not have contents in the non-hidden cells
Solution
You need a function that returns you the hidden rows
You loop through all columns
For each column you loop through all rows and check if the row is not hidden
For all non-hidden rows, you check if the cell in given column has contents
If non of the non-hidden cells in a column has contents, you hide this column
If I understood right that this is what you want to do - here is a script that allows you to do so.
function getIndexesOfFilteredRows(ssId, sheetId) {
var hiddenRows = [];
// get row metadata to find the hidden rows
var fields = "sheets(data(rowMetadata(hiddenByFilter)),properties/sheetId)";
var sheets = Sheets.Spreadsheets.get(ssId, {fields: fields}).sheets;
//Find the right sheet
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].properties.sheetId == sheetId) {
var data = sheets[i].data;
var rows = data[0].rowMetadata;
for (var j = 0; j < rows.length; j++) {
//push the indexes of all hodden rows into an array
if (rows[j].hiddenByFilter) hiddenRows.push(j);
}
}
}
//return indexes of hidden rows
return hiddenRows;
}
function hideEmptyHeaders() {
var ssId='XXXXX';
var sheetId=0;// adjust if necessary
//get the rows that are hidden by a filter
var hidden=getIndexesOfFilteredRows(ssId, sheetId);
var sheet=SpreadsheetApp.openById(ssId).getSheets()[sheetId];
//get all sheet contents
var rangeValues=sheet.getDataRange().getValues();
//check for every column either the not hidden part of the column is empty
for(var j=0;j<rangeValues[0].length;j++) {
// loop through all data rows
for(var i=0;i<rangeValues.length;i++) {
//check if the row is not hidden
if((hidden.indexOf(i)+1)==false) {
// if the row is not hidden, check if the cell in column j has content
if(rangeValues[i][j]!=""||rangeValues[i][j]!="") {
//if the cell has content, jump to the next column, otherwise check first all the other rows
break;
}
}
// if no content has been found in column j after ite5rating through all non-hidden rows, hide column j
if(i==(rangeValues.length-1)) {
sheet.hideColumns(j+1)
}
}
}
}

Loop through range and set values

I would like to create a loop that goes through the range A1:A150 and sets the cell value to =readmessage(Sheet2!A1) with A1 changing dynamically with each cell. So with A2 it reads, Sheet2! A1.
function storeValue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("A1:A150");
for (var i = 1; i < range.length; i++) {
range.setValue("=readMessage(Sheet2!"+range+")");
}
}
This doesn't work, nothing is written into the cells in the range.
I'm guessing it's something to do with range.setValue.
Don't confuse values with formulas. For values there is setValue(value) and for formulas there is setFormula(formula).
By the other hand var range = sheet.getRange("A1:A150"); assigns a Range object to the range variable. To get get it address use getA1Notation()
This should work if I understood you correctly:
function storeValue(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
for (var i = 1; i < 150; i++) {
range = sheet.getRange("A"+i);
range.setValue("=readMessage(Sheet2! A"+i+")");
} }
Otherwise comment below.

Google Apps Script Taking one random cell from each row

So I have a sheet as seen here.
https://docs.google.com/spreadsheets/d/1r2ogg1ldR0CFjOJ6mVObY-WRVipJx_X3pQ0yM2HYEog/edit?usp=sharing.
I am trying to write a script that goes through every row in range A1:D and chooses one random cell to put in the F column of the same row.
I am new to GAP so Im not sure how to write the exact script for that. This is what I got so far
function random() {
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ss = sss.getSheetByName('Sheet1'); //the sheet that has the data
var range = ss.getRange('A1:D'); //the range I need
var data = range.getValues();
for(var i = ; i < data1.length; i++) { //at this point im just guessing based on online codes
= Math.floor(Math.random()*(j+1)); //method of randomization
ss.getRange('the i row of F column').setValue(data[i][1]); //choosing the row that is being used, selecting the first item of the shuffled array
};
}
You've been pretty close to the solution:
function random() {
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ss = sss.getSheetByName('Sheet1'); //the sheet that has the data
var range = ss.getRange(1,1,ss.getLastRow(), 4); //the range you need: 4 columns on all row which are available
var data = range.getValues();
for(var i = 0; i < data.length; i++)
{
var j = Math.floor(Math.random()*(data[i].length)); //method of randomization
var element = data[i][j]; // The element which is randomizely choose
ss.getRange(i+1, 6).setValue(element);
}
}
I've made some modification on your orignal code:
getLastRow() get the position of the last row which is use. Otherwise, you collect a array the size of your entire sheet.
The Math.random() function is multiply by the size of a row, so you can have as much column as you want.

Categories

Resources