getNumColumns() doesn't update? - javascript

Basically what I'm trying to do is insert a certain number of values into a spreadsheet via a script. The way I have it set up, it inserts each value separately, calling the function x amount of times.
Let's say I have 4 values. I want to insert all the values into row 1 then, column 1, column 2, column 3, column 4. What's happening right now in my code, is it inserts all of the values into column 1 only, and it just overwrites anything already in column 1, so I only end up with the last value.
var column = sheet.getDataRange().getNumColumns() + 1;
sheet.getRange(1, column).setValue(question);
If I add in that + 1 to getNumColumns, it will add all four values, but into columns 2, 3, 4, and 5. So basically, if I don't use the + 1, the getNumColumns() never updates, and each time a value is inserted it stays at 1. I have no idea why this is and have been searching for quite some time now for an answer.
EDITED CODE:
var range = sheet.getDataRange();
var data = range.getValues();
if (range.isBlank()){
var column = 1;
sheet.getRange(1, column).setValue(question);
}else{
var column = sheet.getDataRange().getNumColumns();
sheet.getRange(1, column).setValue(question);
}

It looks like your data range initializes as column 1, meaning that the first time through you add 1+1 to get column 2, etc. The simplest approach is probably to write an if-statement so that when getDataRange().getNumColumns() == 1, you don't add the 1, but you add it every other time. Even better would be finding a way to initialize the data range to 0 instead of 1, if the API allows that.
Edited: On second thoughts, the safer way would be to check to see if the data range is blank, rather than if the number of columns is 1. You can use the isBlank() method for that.

Related

Get a range but I need to get it until the last row no empty

I am trying to program some information in Excel with Dinamyc information and I am using the next line of code to get a range of information
var rangoValidacion = hojaResumen.getRange(9, 3, 3);
but with that I only get up to 3 rows and that might change later I want to make it where it gets the range of all the raws but until it gets to a empty one, how can I do that?
var rangoValidacion = hojaResumen.getRange(9, 3, getlastrownoblank);

Copy filtered range from one spreadsheet to another - Google app script

I have a large google sheet with 30275 rows and 133 columns in a google sheet. I want to filter the data and copy column AZ to another spreadsheet.
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1aiuHIYzlCM7zO_5oZ0aOCKDwPo06syXhWvhQMKgJE2I/edit?usp=sharing
I have been trying to follow this link
I am not that familiar with javascript and the code is designed to exclude items from filter rather than including items on filter. I have 500+ items to exclude so need to work out something that will be efficient in filtering large dataset in short time before execution limit is reached.
Here is my code so far. Any help to get this working would be appreciated.
NOTE: Filter/ Query with importrange formulas dont work due to the large volume of data. So I need an efficient script to filter large dataset and move them to another sheet before execution time limit.
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
var destsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('JockeyList');
var demosheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValues();
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here
//Logger.log(jockey);
var hiddenValues = jockey;
values = values.filter(function(v) {
return hiddenValues.indexOf(v[51]) == 1;
});
Logger.log(values.length);
// Set filtered data on the target sheet
destsheet.getRange(10, 5, values.length, 2).setValues(values);
}
Ok so it seems like you want to copy only the values from AZ in 'Sheet1' that are equal to whatever string value is contained in cell L14 of sheet 'Betting data - Demo.' If that is the case, then here is a change to your original code that will accomplish that:
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
// this assumes that your destsheet and demosheet are in the same spreadsheet. Keep in mind that opening spreadsheets with SpreadsheetApp is costly so you want to minimize your calls to new sheets.
var destsheet = ss.getSheetByName('JockeyList');
var demosheet = ss.getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValue();
var searchTerm = new RegExp(jockey);
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here and return ONLY THE VALUE IN COLUMN AZ
var filteredValues = values.reduce(function(resultArray, row) {
if (searchTerm.test(row[51])) resultArray.push([row[51]]);
return resultArray;
}, [])
// Set filtered data on the target sheet
// Note* not clear why you are starting at row 10, but as is this will overwrite all of the data in column 5 of destsheet starting from row 10 every time this function runs
destsheet.getRange(10, 5, filteredValues.length, 1).setValues(filteredValues);
}
As it says in the code sample, this will only copy and paste the value in column AZ of 'sheet1'. It does not alter 'sheet1' in any way. If that is really all you want to do, then this function works, but it's overkill. Since you are just filtering values in AZ against a single string value, it would be more efficient to simply count the number of times that string occurs in column AZ and then add the string that number of times to your destination sheet.
Also note that your original function is pasting values into destsheet into a constant row (row 10). That means that every time your function runs, the data from row 10 on will be overwritten by whatever data you are copying from 'sheet1'

I need help creating a script to hide columns in google sheets if cells in range are empty

I am trying to create a script which will hide columns where cells in a range are empty (the condition).
Below is what my table looks like, you can see there are 12 roles. I basically want to hide any columns from Role 4 onwards which are unused e.g. no values in the 3 rows.
i have a script that works (see below) but it also hides Roles 1, 2 and 3 if they are blank. I want the script to only work from Role 4 (column F) onwards. What do i need to change in the script for this to work?
P.s. I have used code from other posts to put this together so there may be lines in the code I do not need, I am still very new to google script.
function hidecolumns() {
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getSheetByName("Project Team Resources");
var r = ss.getRange("C5:N10");
var data = r.getValues();
var rData, cData, x;
cData = data[0].map(function (col, c) {
return data.map(function (row, r) {
return data[r][c];
});
});
Logger.log(cData.length);
Logger.log(data.length);
for(var i=0;i<cData.length;i++){
if(cData[i].filter(String).length==0)
ss.hideColumns(i+3)
}
}
Explanation:
Your goal is to hide a column if it is empty with the exception of the first three columns in the range.
One approach to achieve this to iterate over all columns in the desired range and check if they contain at least one non-empty value (length>0). If the length is 0, meaning that all values in this column are empty, then hide it.
In more detail, I use a forEach loop to iterate over each column. Each column is given by a simple map expression:
data.map(d => d[col]) where col takes values 0, 1, 2, ...
I filter on the non-empty values and hide only columns if the length of the non-empty array is 0.
Since the data range starts from column C which is the 3rd column, I hide column col+3. Be careful with this, since it depends on the input range.
Finally, your goal is to keep the first 3 columns (Roles 1,2,3) fixed-unhidden regardless if they contain values or not. To do that, add an extra condition in the if condition to check if column is larger than 2: col>2.
Solution:
function hidecolumns() {
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getSheetByName("Project Team Resources");
var data = ss.getRange("C5:N10").getValues();
data[0].forEach((_,col)=>{
if(data.map(d => d[col]).filter(e=>e!='').length==0 && col>2){
ss.hideColumns(col+3);
}
});
}
underscore as a parameter reference

Hide Rows and Columns That Are Empty

On Open, In Worksheet "Time per Job & Job Costing", if Row from column A is empty or includes a 0 value hide it. If Column from row 1 is empty or includes a 0 value hide it.
I looked around and can find techniques for hiding rows if a column is empty but not the other way around, nor if the value is 0.
I have the Rows accomplished with this, but it only works on empty rows:
function onOpen(e) {
["Time per Job & Job Costing"].forEach(function (s) {
var sheet = SpreadsheetApp.getActive()
.getSheetByName(s)
sheet.getRange('A:A')
.getValues()
.forEach(function (r, i) {
if (!r[0]) sheet.hideRows(i + 1)
});
});
}
If Column from row 1 is empty or includes a 0 value hide it.
Explanation:
I believe your goal is to hide a column if a cell of that column
in the first row is empty or 0. You also want to achieve that when you open the spreadsheet file.
To achieve that, the first step is to get the values of the first row. You can use getRange() to get the first row starting from the first column until the last column with content. For the latter you need to use getLastColumn(). Then you can flatten the array in order to perform a forEach loop. For every element in the first row, you check whether it is empty or 0. If this condition evaluates to true then you hide that particular column.
Solution:
function onOpen() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Time per Job & Job Costing');
const first_row = sh.getRange(1,1,1,sh.getMaxColumns()).getValues().flat();
first_row.forEach((fr,i)=>{
if(fr=='' || fr==0){
sh.hideColumns(i+1);
}});
}

How can i combine rows range into json format?

I have a google sheet like this
The number of columns and rows may be different (not static). I want my google script to look for last row and column, then run a for loop and combine data of each row into this json format like this.
[["1","Lee","Blue","Active"],["2","Mike","Green","Disabled"],["3","Chan","Yellow","Active"]]
I learned about the JSON.stringify() function that helps and I am able to combine data or each row into json format BUT i want each row data separated by a comma (,), not sure how to add that in the logic since I DO NOT want comma to be added after LAST row.
I have tried creating this code and need help with the logic to dynamically run the loop based on number of columns and rows instead of hard-coding any range and add comma.
var mysheet = SpreadsheetApp.getActive().getSheetByName('mysheet');
function combine_val() {
GetRowsCount();
var startRow = 2; // First row of data to process
var numRows = LastAudienceRow; // Number of rows to process
for (var i = 0; i < numRows; ++i) {
var dataRange = mysheet.getRange(startRow, 1, 1, 4);
var data = dataRange.getValues();
startRow = startRow+1;
var data2= JSON.stringify(data);
}
SpreadsheetApp.getUi().alert(data2);
}
function GetRowsCount() {
LastAudienceRow = mysheet.getLastRow() - 1;
return LastAudienceRow;
}
You've rather over complicated the whole situation, as much of this is done automatically. This script is also not very efficient and when you add more runs, will take too long to execute, eventually hitting the App script limit for maximum execution time.
Here you are trying to get the data from each row individually, and add it to an array. This is very inefficient, and it's much better/faster to just specify the range of data you want. Happily, this also formats it's pretty much as you like.
Here's a sample script:
var mysheet = SpreadsheetApp.getActive().getSheetByName('mysheet');
function combine_val() {
var startRow = 1; // First row of data to process.
var startColumn = 1; //First Column to process, in case that changes.
var numRows = mysheet.getLastRow(); // Number of rows to process
var numCols = mysheet.getLastColumn(); //Also the number of columns to process, again in case that changes.
var dataRange = mysheet.getRange(startRow, startColumn, numRows, numCols);//Get the full range of data in the sheet dynamically.
var data = JSON.stringify(dataRange.getValues());//Get the value of the range, AND convert it to a JSON string in one line.
Logger.log(data); //Use the in built logger to read the values that are returned. You can read this by pressing 'ctrl+enter'.
}
I've also added in some sample dynamic improvements which will mean you are hard coding less of your values into your scripts, preventing it from breaking if the data changes.
Additionally, I have added in a sample of how to read the data via the inbuilt logging tool, rather then via a cumbersome pop up after every run.
JSON.stringify already returns row data separated by commas.
var arr = [["1","Lee","Blue","Active"],["2","Mike","Green","Disabled"],["3","Chan","Yellow","Active"]];
console.info(JSON.stringify(arr))
The above example prints the following string to the console
[["1","Lee","Blue","Active"],["2","Mike","Green","Disabled"],["3","Chan","Yellow","Active"]]
The following example prints each row values separated by comma.
var arr = [["1","Lee","Blue","Active"],["2","Mike","Green","Disabled"],["3","Chan","Yellow","Active"]];
for(var i = 0; i < arr.length; i++){
console.info(JSON.stringify(arr[i]).replace(/[\[\]]/g,''));
}
To use it on as a Google Sheets / Apps Script instead of assigning a literal to arr use getValues() . You could replace console.info by SpreadsheetApp.getUi.alert(message) too.

Categories

Resources