I would like to do this in G column : If Cell 'G8' is Blank Then (=K8) for example. My difficulty is to make reference of same row in K of empty cell in G.
I've tryed to adapt this script but I get a shift at some point and I don't know why.
function updatewithformula() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1');
var range = sheet.getDataRange()
var source = sheet.getRange('G1:G13').getDisplayValues()
var index = []
for (var i = 1; i<source.length; i++){
if (source[i][0] == ""){
index.push(i+1)
}
}
index.push(range.getLastRow()+1)
Logger.log(index)
for(var i = 0;i<index.length-1;i++){
var rangetomodify = sheet.getRange(index[i],7,1,1)
var l = index[i+1]-index[i]-1
rangetomodify.setFormulaR1C1("=R["+l+"]C[4]")
}
}
As another approach, how about the following modification?
Modification points:
About I've tryed to adapt this script but I get a shift at some point and I don't know why., in your script, "=R[" + l + "]C[4]" is used with var l = index[i + 1] - index[i] - 1. In this case, when l is not 0, the other row is used. I thought that this might be the reason for your issue. In your script, I think that it is not required to use var l = index[i + 1] - index[i] - 1. When your script is simply modified, it becomes as follows.
function updatewithformula() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1');
var range = sheet.getDataRange();
var source = sheet.getRange('G1:G13').getDisplayValues();
var index = [];
for (var i = 1; i < source.length; i++) {
if (source[i][0] == "") {
index.push(i + 1);
}
}
index.push(range.getLastRow() + 1);
for (var i = 0; i < index.length - 1; i++) {
var rangetomodify = sheet.getRange(index[i], 7, 1, 1);
rangetomodify.setFormulaR1C1("=R[0]C[4]");
}
}
But, in this case, getRange and setFormulaR1C1 are used in a loop. In this case, the process cost becomes high.
When your script is modified by reducing the process cost, how about the following modification?
Modified script:
function updatewithformula() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1');
var source = sheet.getRange('G2:G13').getDisplayValues();
var ranges = source.reduce((ar, [g], i) => {
if (!g) ar.push(`G${i + 2}`);
return ar;
}, []);
sheet.getRangeList(ranges).setFormulaR1C1("=R[0]C[4]");
}
By RangeList, the process cost can be reduced a little.
References:
reduce()
getRangeList(a1Notations)
setFormulaR1C1(formula) of Class RangeList
There are better, easy and short methods to do it, I have used offset here.
The below works for me
function updatewithformula(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1');
var range = sheet.getDataRange()
var source = sheet.getRange('G1:G13').getValues();
Logger.log(source);
var index = [];
for (var i in source){
if(source[i][0] == ""){
var j = +i;
index.push(("G"+(j+1)));
}
}
for (var i in index){
var TEMP = sheet.getRange(index[i]);
var TEMP1 = TEMP.offset(0,4).getA1Notation();
const formula = `=${TEMP1}`;
TEMP.setFormula(formula);
}
}
References - OFFSET
I need to copy data from a selected range (Y5:Z198) to cell (Y206) but somehow I can only make it to appendRow and paste only on column A. Can someone help me, please?
function CopyData(CopyData) {
var ss = SpreadsheetApp.getActive();
var sh1 = ss.getSheetByName("CAPA");
var sh2 = ss.getSheetByName("CAPA");
var rg1 = sh1.getRange("Y5:Z198");
var vA = rg1.getValues();
for (var i = 0; i < vA.length; i++) {
if (vA[i][1]) {
sh2.appendRow(vA[i]);
}
}
}
Try this code to copy the data
function CopyData(CopyData) {
const dstRow = 206;
let ss = SpreadsheetApp.getActive(),
sheet = ss.getSheetByName('CAPA'),
srcRange = sheet.getRange('Y5:Z198'),
srcValues = srcRange.getValues(),
filtered = srcValues.filter(item => item[1]); // filter the data being copied
// Define the range to insert
// 'Y'+dstRow -> Y206
// filtered.length -> the number of rows in the filtered array of data
// ':Z'+(dstRow-1+filtered.length) -> bottom right cell
sheet.getRange('Y'+dstRow+':Z'+(dstRow-1+filtered.length)).setValues(filtered);
}
I have the script mostly working- except the data being pushed actually says "Range" I must be missing something- can you not set values across a range?
function up4Grabs() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var destsheet = SpreadsheetApp.openById("MYID GOES HERE").getSheetByName('Items');
var destLastRow = destsheet.getLastRow();
var destRange = destsheet.getRange(1,9,destLastRow);
var dataLastRow = sheet1.getLastRow();
var dataRange = sheet1.getRange(1,9,dataLastRow);
var data = dataRange.getValues();
for(var i = 0; i < data.length; i++) {
if (data[i] > 0) {
var targetLastRow = destsheet.getLastRow() + 1;
var test = destsheet.getRange(1,9,targetLastRow);
sheet1.getvalues(test).setValues(sheet1.getRange(i+1,1,1,9))
}
}
}
Problem:
setValue() setting "Range" rather than actual values.
Cause:
You're passing a range rather than a value to the setValue() in the first place.
Solution:
function up4Grabs() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var destsheet = SpreadsheetApp.openById("MY ID GOES HERE").getSheetByName('Items');
var destLastRow = destsheet.getLastRow();
var destRange = destsheet.getRange(1,9,destLastRow);
var dataLastRow = sheet1.getLastRow();
var dataRange = sheet1.getRange(1,9,dataLastRow);
var data = dataRange.getValues();
for(var i = 0; i < data.length; i++) {
if (data[i] > 0) {
var targetLastRow = destsheet.getLastRow() + 1;
var values = sheet1.getRange(i+1,1,1,9).getValues();
destsheet.getRange(1,9,values.length,9).setValues(values);
}
}
}
Since you're setting the values of a whole range, you need to use setValues() rather than setValue(), note: plural rather than singular. I've also added getValues() to the range you were already pulling, this returns the array of values within the range that can then be passed to setValues().
So, I'm not much of a coder to be honest, but I've managed to fumble my way through counting cell background colour, but struggling to get it to work for counting cells where the font is bold. I've detailed my function below, which counts only 6 cells with a bold font style, but there is 13 cells with a bold font style.
function countboldcells() {
var book = SpreadsheetApp.getActiveSpreadsheet();
var sheet = book.getActiveSheet();
var range_input = sheet.getRange("E2:S7");
var range_output = sheet.getRange("G14");
var cell_styles = range_input.getFontStyle();
var count = 0;
for(var r = 0; r < cell_styles.length; r++) {
for(var c = 0; c < cell_styles[0].length; c++) {
if(cell_styles.isBold = true) {
count = count + 1;
}
}
range_output.setValue(count);
}
}
Your if statement needs to have 3 "=" inside the parentheses
if(cell_styles.isBold === true)
getFontWeights() is the method that will return bold or not. Then the easy way to count them would be to flatten the array, filter all of the "bold" elements and get the length of the filtered list
function countboldcells() {
var book = SpreadsheetApp.getActiveSpreadsheet();
var sheet = book.getActiveSheet();
var range_input = sheet.getRange("E2:S7");
var range_output = sheet.getRange("G14");
// Get the fontWeights of the range and flatten the array
var cell_styles = range_input.getFontWeights().join().split(",");
// Filter out any value that is not "bold"
var filter_bold = cell_styles.filter(function (e) { return e == "bold" });
// Set the count
range_output.setValue(filter_bold.length);
}
Here is your code with corrections. Explanations are in the comments.
function countboldcells() {
var book = SpreadsheetApp.getActiveSpreadsheet();
var sheet = book.getActiveSheet();
var range_input = sheet.getRange("E2:S7");
var range_output = sheet.getRange("G14");
var cell_styles = range_input.getFontWeights(); // getFontStyle can only return 'italic' or 'normal'
var count = 0;
for(var r = 0; r < cell_styles.length; r++) {
for(var c = 0; c < cell_styles[0].length; c++) { // isBold is a method for Google Documents only (not sheets)
if(cell_styles[r][c] === "bold") { // you need at least two '=' signs // also include the index of cell_styles
count = count + 1; // count += 1 would also work
}
}
}
range_output.setValue(count); // make sure you setValue only when booth loops are done.
}
I've just started using Google Apps script to manage some sheets for a project i'm working on, I am new to Javascript so please go easy if there are any howlers in my code!.
We have and app called forms2mobile that captures data and drops it into a Google spreadsheet. It actually drops different data into different sheets depending on which part of the app you use.
I've hacked together a script that pulls all data from one sheet (source), and drops only certain columns into a second sheet (destination). It then deletes all rows from the source, and any blank rows from the destination.
The problem I have is with deleting blank rows from the destination. Typically the destination will have empty rows at the bottom, and the code I have will only delete empty rows within the range that contains data. So i'm always left with empty rows at the bottom.
The destination sheet will then be used as a data source for forms2mobile, which of course isn't happy with empty rows.
I've found the class getMaxRows() but i'm not sure how to implement it. If anyone could make any suggestions that would be great.
Cheers
Paul
function NEW_copyColumnNumbers( ) {
var spreadsheet_source = SpreadsheetApp.openById('1a89ZIUcy-8168D1damCV3Q9Ix0arQn9jGS6pgp');
var spreadsheet_target = SpreadsheetApp.openById('1GQiLt9utSH_6CV__oJwmcLOkI4E9iNIRPWU7Xr');
var range_input = spreadsheet_source.getRange("A2:CC407");
var range_output = spreadsheet_target.getRange("A"+(spreadsheet_target.getLastRow()+1));
var keep_columns = [66,66,10,11,12,13,14,23,26,31,69,71,74,75,80];
copyColumnNumbers(range_input, range_output, keep_columns);
clearEmptyRows();
clearSourceData();
}
function copyColumnNumbers( range_input, range_output, columns_keep_num ) {
// Create an array of arrays containing the values in the input range.
var range_values = range_input.getValues();
// Loop through each inner array.
for ( var i = 0, row_count = range_values.length; i < row_count; i++ ) {
// Loop through the indices to keep and use these indices to
// select values from the inner array.
for ( j = 0, col_keep_count = columns_keep_num.length; j < col_keep_count; j++ ) {
// Capture the value to keep
var keep_val = range_values[i][columns_keep_num[j]];
// Write the value to the output using the offset method of the output range argument.
range_output.offset(i,j).setValue(keep_val);
}
}
}
function clearEmptyRows() {
var ss = SpreadsheetApp.openById('1GQiLt9utSH_6CV__oJwmcLOkI4E9iNIRPWU7Xr');
var s = ss.getActiveSheet();
var values = s.getDataRange().getValues();
nextLine: for( var i = values.length-1; i >=0; i-- ) {
for( var j = 0; j < values[i].length; j++ )
if( values[i][j] != "" )
continue nextLine;
s.deleteRow(i+1);
}
//I iterate it backwards on purpose, so I do not have to calculate the indexes after a removal
}
function clearSourceData() {
var ss = SpreadsheetApp.openById('1a89ZIUcy-8168D1damCV3Q9Ix0arQn9jGS6pgp');
var s = ss.getActiveSheet();
var data = s.getDataRange().getValues();
for(var n =data.length+1 ; n<0 ; n--){
if(data[n][0]!=''){n++;break}
}
s.deleteRows(2, (s.getLastRow()-1));
}
This is how it works :
function removeEmptyRows(){
var sh = SpreadsheetApp.getActiveSheet();
var maxRows = sh.getMaxRows();
var lastRow = sh.getLastRow();
sh.deleteRows(lastRow+1, maxRows-lastRow);
}
Note : you can handle columns the same way if necessary using getMaxColumn(), getLastColumn() and deleteColumns(number, howMany)
EDIT
by the way, here is also another way to delete empty rows in a spreadsheet... if you combine both it will "clean" your sheet entirely !
function deleteEmptyRows(){
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getDataRange().getValues();
var targetData = new Array();
for(n=0;n<data.length;++n){
if(data[n].join().replace(/,/g,'')!=''){ targetData.push(data[n])};
Logger.log(data[n].join().replace(/,/g,''))
}
sh.getDataRange().clear();
sh.getRange(1,1,targetData.length,targetData[0].length).setValues(targetData);
}
Demo sheet in view only - make a copy to use
Script to removeEmptyRows and removeEmptyColumns in Google Sheets. It puts together everything Serge and apptailor mentioned previously. Here is a sample sheet with the script included File > Make a copy... to edit a copy of the sheet. Also a video that shows you how to use this sheet.
//Remove All Empty Columns in the Entire Workbook
function removeEmptyColumns() {
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
for (var s in allsheets){
var sheet=allsheets[s]
var maxColumns = sheet.getMaxColumns();
var lastColumn = sheet.getLastColumn();
if (maxColumns-lastColumn != 0){
sheet.deleteColumns(lastColumn+1, maxColumns-lastColumn);
}
}
}
//Remove All Empty Rows in the Entire Workbook
function removeEmptyRows() {
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
for (var s in allsheets){
var sheet=allsheets[s]
var maxRows = sheet.getMaxRows();
var lastRow = sheet.getLastRow();
if (maxRows-lastRow != 0){
sheet.deleteRows(lastRow+1, maxRows-lastRow);
}
}
}
Just a quick note, I added this "if" statement to keep Serge insas's code from throwing an error if there is no empty bottom row when you are trying to remove empty rows.
Place this if around the last line function removeEmptyRows() and it
will not throw an error:
if (maxRows-lastRow != 0){
sh.deleteRows(lastRow+1, maxRows-lastRow);
}
Removing all empty lines (bottom-up)
before
after
function isEmptyRow(row){
for (var columnIndex = 0; columnIndex < row.length; columnIndex++){
var cell = row[columnIndex];
if (cell){
return false;
}
}
return true;
}
function removeEmptyLines(sheet){
var lastRowIndex = sheet.getLastRow();
var lastColumnIndex = sheet.getLastColumn();
var maxRowIndex = sheet.getMaxRows();
var range = sheet.getRange(1, 1, lastRowIndex, lastColumnIndex);
var data = range.getValues();
sheet.deleteRows(lastRowIndex+1, maxRowIndex-lastRowIndex);
for (var rowIndex = data.length - 1; rowIndex >= 0; rowIndex--){
var row = data[rowIndex];
if (isEmptyRow(row)){
sheet.deleteRow(rowIndex + 1);
}
}
}
function removeEmptyLinesFromAllSheets(){
SpreadsheetApp.getActive().getSheets().forEach(removeEmptyLines);
}
Removing only empty lines from below and above the data
before
after
function isEmptyRow(row){
for (var columnIndex = 0; columnIndex < row.length; columnIndex++){
var cell = row[columnIndex];
if (cell){
return false;
}
}
return true;
}
function getFirstNonBlankRowIndex(data){
for (var rowIndex = 0; rowIndex < data.length; rowIndex++){
var row = data[rowIndex];
if (!isEmptyRow(row)){
return rowIndex;
}
}
return 0;
}
function removePaddedEmptyLines(sheet){
var lastRowIndex = sheet.getLastRow();
var lastColumnIndex = sheet.getLastColumn();
var maxRowIndex = sheet.getMaxRows();
var range = sheet.getRange(1, 1, lastRowIndex, lastColumnIndex);
var data = range.getValues();
var firstRowIndex = getFirstNonBlankRowIndex(data);
sheet.deleteRows(lastRowIndex+1, maxRowIndex-lastRowIndex);
sheet.deleteRows(1, firstRowIndex);
}
function removePaddedEmptyLinesFromAllSheets(){
SpreadsheetApp.getActive().getSheets().forEach(removePaddedEmptyLines);
}
I have tried this piece of code and it works good, you may take a look and try it:
function DeleteBlankRows(){
var sh = SpreadsheetApp.getActiveSheet();
var maxRows = sh.getMaxRows();
var lastRow = sh.getLastRow();
for (var Raw = 1; Raw < sh.getLastRow() ; Raw++)
{
if( sh.getRange('A'+Raw).getValue() == '')
{
sh.deleteRow(Raw) //deleteRows(lastRow+1, maxRows-lastRow);
}
}
This works perfectly for me.
function removeEmptyRows(){
var spreadsheet = SpreadsheetApp.openById("IDOFYOURSPREADSHEETFOUNDINURL");
var sh = SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
var maxRows = sh.getMaxRows();
var lastRow = sh.getLastRow();
sh.deleteRows(lastRow+1, maxRows-lastRow);
}
This version allows you to specify top rows you don't want removed and also to ignore columns after ignoreAfterCol in case you don't want some columns considered when you are looking for blanks:
function removeEmptyLines(sheet,ignoreFirstRows,ignoreAfterCol){
sheet=ss.getSheetByName('Sheet12')
//get data and boundaries
var allData = sheet.getRange(1,1,sheet.getMaxRows(),ignoreAfterCol).getValues();
var sheetLength = allData.length;
while(allData[allData.length-1].toString().replace(/,/g,'')=='') allData.pop();
var lastPopulatedRow = allData.length;
//delete empty rows from end
var rowsToDeleteFromEnd = sheetLength - lastPopulatedRow;
if(rowsToDeleteFromEnd > 0) sheet.deleteRows(lastPopulatedRow+1,rowsToDeleteFromEnd);
//iterate through rows and delete blanks one by one
for(var i=lastPopulatedRow-1; i>ignoreFirstRows; i--){
if(allData[i].toString().replace(/,/g,'')=='') sheet.deleteRow(i+1);
}
}
this will help to delete exactly what you want:
Plus point:
you can check as many columns as you want to identify if a row is empty
this will also delete blank rows that contain formula
improve performance: this script deletes directly the empty rows according to their position without iteration through all the rows.
function deleteBlankRows(start_row=4) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
//temporarily insert last column to avoid affecting existing data
sheet.insertColumnsAfter(sheet.getMaxColumns(),1);
var lastRow = findLastRow();
var lastCol = sheet.getMaxColumns()
var temp_col = sheet.getRange(start_row,lastCol,lastRow-start_row,1)
//insert formula to show row position if any row is blank from column A to N (can adjust if needed)
sheet.getRange(start_row,lastCol).setFormula('=if(countif(A'+start_row+':N'+start_row+',"*?")=0,row(),0)').copyTo(temp_col)
//get a reversed list of rows position excluded non-empty rows
var rowsPosition = temp_col.getValues().filter(x => x != 0).reverse()
//delete empty rows from bottom to top
rowsPosition.forEach(function(rowPosition){
if (Number(rowPosition) > start_row) {
sheet.deleteRow(Number(rowPosition))
}
})
//finally, delete the temporary column
sheet.deleteColumn(lastCol)
}
function findLastRow() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const data = sh.getRange("A:L").getValues();
const mR = sh.getMaxRows();
const indexes = [];
data[0].forEach((_, ci) => {
let col = data.map(d => d[ci]);
let first_index = col.reverse().findIndex(r => r != '');
if (first_index != -1) {
let max_row = mR - first_index;
indexes.push(max_row);
}
});
last_row = indexes.length > 0 ? Math.max(...indexes) : 0;
return last_row;
}
function deleteblankRw(){
var sheet=SpreadsheetApp.getActive().getSheetByName('test')
var e=sheet.getRange('A'+sheet.getMaxRows()).getNextDataCell(SpreadsheetApp.Direction.UP).getRow()
for (k=2;k<=e;k++) {
if(sheet.getRange('A'+k).getValue()=='') {
sheet.deleteRow(k);
k=2;e--
if(k==e){break};
SpreadsheetApp.flush();
}
}
}