I have a spreadsheet where every day a new column gets added with:
sheet.insertColumnAfter(6)
now i want to show/hide the columns starting at column(7) up till the last column of the sheet (which is a dynamic value).
i had the following thought and no idea why it doenst work:
function Historyausblenden() {
var bereich = SpreadsheetApp.getActive();
var letzte = bereich.getLastColumn();
bereich.getRange("G",letzte).activate();
bereich.getActiveSheet().hideColumns(bereich.getActiveRange().getColumn(), bereich.getActiveRange().getNumColumns());
bereich.getRange('F:F').activate();
}
It seems that getRange doesnt accept var letzte.
The errorcode says: "Methode getRange(string,number) not found!"
Why? What does that mean?
Several issues in your code.
You can't call getLastColumn() on a spreadsheet.
String concatenation in javascript is most easily done with + (e.g. "G" + letzte).
You can't activate a range without first selecting the sheet.
Lastly, you don't really need to activate to accomplish what you're trying to do, but you may have another reason for doing so.
Try this instead (and make sure you're selecting the correct sheet in the third line):
function hideHistory() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Sheet1");
var lastColumn = sheet.getMaxColumns();
var startColumn = 7;
sheet.hideColumns(startColumn, lastColumn-startColumn+1);
}
Related
I want to run a script that copies a sheet data to a master sheet (append all my sheets).
The first part of copying and pasting is working but I want to add a column which tells me the name of the origin sheet. I wrote a loop for it but nothing is happening when I executing the script (only the copy and paste). This is my whole code:
function appendSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var reportLastRow = sh.getLastRow()
var reportLastColumn = sh.getLastColumn()
var reportData = sh.getSheetValues(3,1,reportLastRow,reportLastColumn);
var recordsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2020 Data");
var lastRow = recordsSheet.getLastRow();
//var recordLastRow = sh.getLastRow();
var recordLastColumn = recordsSheet.getLastColumn();
var reportSheetName = sh.getSheetName();
recordsSheet.getRange(lastRow + 1,1,reportLastRow,reportLastColumn).setValues(reportData);
var arrayLength = (lastRow - reportData.length);
for (var i = 0 ; i <= arrayLength ; i ++) {
var taskDateCell = recordsSheet.getRange(arrayLength - i, recordLastColumn);
taskDateCell.setValues(reportSheetName);
}
}
Your code has several problems you should fix
Be aware of the fact that the method getRange() expects the syntax firstRow, firstColumn, numRows, numColumns - not firstRow, firstColumn, lastRow, lastColumn. You need to adjust your range and your function getSheetValues() (I assume it is you custom funciton based on the method getRange() accordingly.
If you assign a value to one cell at a time taskDateCell, you should use setValue() instead of setValues()
It seems like your definition of arrayLength might not be right. Test it by logging it.
Your main problem:
You define:
for (var i = arrayLength ; i < arrayLength ; i ++)
In other words:
Set i to arrayLength and iterate while i is smaller than arrayLength.
This condition is never fullfilled, and thus the number of iterations will be zero.
As a genral advice: Implement in your code many logs - to visualize important values, such a range notations and length of arrays, or counter variables in a loop - this will help you to find bugs faster.
Explanation:
First of all I optimized your code. You have unnecessary lines of code which make your code difficult to be understood but also slow. The optimizations involve reducing the number of lines to the minimum, defining constant variables, making the variable names more descriptive and finally getting rid of the for loop by replacing it with a more efficient approach.
Another correction would be at this line: sh.getSheetValues(3,1,reportLastRow,reportLastColumn); Here you are starting from the third row but you are getting two rows extra; reportLastRow is the number of rows you want to get but since you are starting from the third row you need to deduct 2.
To answer your question, one way to solve your problem is to set the name of the report to the last column of the records sheet where you entered the data from the report sheet. Since you want to add the same value (sheet name) to every row, you can select a 2D range but use setValue.
I am not a big fan of getActiveSheet in const report_sh = ss.getActiveSheet(); since this line is assuming that you have selected the desired sheet (report sheet) in the UI. Please be careful with that, otherwise change that line to something like that:
const report_sh = ss.getSheetByName('report sheet');
and of course adjust 'report sheet' to the name of the sheet you want to append.
Solution:
function appendSheet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const records_sh = ss.getSheetByName("2020 Data");
const report_sh = ss.getActiveSheet();
const reportData = report_sh.getSheetValues(3,1,report_sh.getLastRow()-2,report_sh.getLastColumn());
const records_lr = records_sh.getLastRow();
records_sh.getRange(records_lr+1,1,reportData.length,reportData[0].length).setValues(reportData);
SpreadsheetApp.flush();
records_sh.getRange(records_lr+1,records_sh.getLastColumn()+1,reportData.length,1).setValue(report_sh.getSheetName());
}
I manually select A41 to F80 and it is nicely protecting A41 to F80 using the following line of code.
However, I want to (i) add one more row to the protected data (A41 to F81) though I will select A41 to F80.
Also in another case I want to add double of selected rows plus one to the protected data (A41:F121) though I will select A41 to F80.
Probably getActiveRange() won't work, then I tried to use getRange() but can't solve it. Please help me to solve it.
var protection = SpreadsheetApp.getActiveSheet().getActiveRange().protect().setDescription(description);
You need to create a new range
For this, use first the method getHeight() to retrieve the height of activeRange.
Then, add 1 to it.
Create a new range with the method getRange(row, column, numRows, numColumns)
Whereby row, column and numColumns can be taken from activeRange - only the height is new.
Sample:
var activeRange = SpreadsheetApp.getActiveRange();
var height = activeRange.getHeight();
var newHeight = height + 1;
var activeSheet = SpreadsheetApp.getActiveSheet();
var newRange = activeSheet.getRange(activeRange.getRow(), activeRange.getColumn(), newHeight, activeRange.getWidth());
var protection = newRange.protect().setDescription(description);
I want to be able to quickly and easily add notes (Insert menu / Note) on multiple Google Sheets cells using cell values on other columns on that sheet. For example, F3 would grab the cell values in X3, F4 from X4. But also, if I grab G3, it would grab the values in Y3 (so it consistently grabs the values on the same row, but always the same number of columns to the right (in this case, always 18 columns to the right). I want to grab those values and stick them into a note on the left (so, columns F, G, etc.). I would like to be able to highlight a range (F3-F10), run the Google script, and it will grab all values on X3-X10 and stick them on their relative rows. Is this possible?
I've been hunting for this option, searching for every range of terms I can think of, and I've got pretty close, but I keep getting stuck at numerous points, the most important being able to grab the data from an equal number of columns to the right, relative to the range I highlight. I found this code that gets me close, but I don't know how to edit it to do what I need. It allows me to create the menu option, which works on pulling the value of A1 on the first tab of my spreadsheet (I'm working on the second tab, and it's only grabbing the same data for all of my notes). Here is the code I've been working on, but also a second function that I think has features that I need, such as grabbing the active sheet.
function noteSetter() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //I need to make this grab the right sheet
var cell = sheet.getRange(2, 2); //this and the line below it seem to be critical here...
cell.setNote(sheet.getRange(1,1).getValue());
}
//below gives me the menu option to run the script, but I'm open to changing this
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Set cell note",
functionName : "noteSetter"
}];
sheet.addMenu("Scripts", entries);
};
Here is another one that is used on that post that has features that I think I need, but still doesn't get me the relative reference of the cells.
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getName() == "Project"){ //Change to your sheet name
var sourceRange = e.source.getActiveRange();
var sourceRow = sourceRange.getRow();
var sourceColumn = sourceRange.getColumn();
var sourceValue = sourceRange.getValue();
if(sourceColumn == 1){ //Change to the column you want to get the value from
var noteCell = sheet.getRange(sourceRow, 2); //The cell where the Note should be, B-column on the current row
noteCell.setNote(sourceValue);
}
}
}
This is where I am now, but I may have messed some things up, as it no longer works at all.
function noteSetter() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getActiveRange();
cell.setNote(sheet.getRange(sourceRow, sourceColumn).getValue());
}
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Set cell note",
functionName : "noteSetter"
}];
sheet.addMenu("Scripts", entries);
};
Any suggestions on how to make this work?
Just to close the loop on this a little, I'm 90% of the way there with the below. It works perfectly when I highlight one cell. But if I highlight more (e.g. a range or array), it sticks the only the top and left-most value as the note in all cells I've highlighted.
function noteSetter() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var row = sheet.getActiveRange().getRow();
var column = sheet.getActiveRange().offset(0, 18);
var cells = sheet.getActiveRange();
cells.setNote((row, column).getValue());
}
I think the next step is using the Selection class, but it's good enough for my purposes.
This should be a simple one, but I could not crack it myself...
I want to copy the currently selected cells in the active sheet in an array called data:
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var selection = sheet.getActiveRange();
var data = selection.getValues();
The above results in the array getting the content of cell A1, no matter which cells are actually selected. When I replace getActiveRange() with e.g. getRange(2,1,10,10) that works as expected.
Any clue as to why I cannot get to the currently selected cells is appreciated!
It looks like the problem was on Google's side because after 24 hours of failure the existing code now works flawlessly. All your versions work fine too now.
I think that the problem is
var sheet = SpreadsheetApp.getActive().getActiveSheet();
This because there is some kind of bug when "chaining" methods of two different Object Classes, in this case Class Spreadsheet and Class Sheet. There is a bug report related to this getActiveSheet() returns first sheet name
The workaround is to replace the above line with:
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
Related
Why Class Range getValues sometimes returns [[]] when chained to Class Sheet getActiveRange?
This gets and displays the active range in a dialog window.
function getARange(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getActiveRange();
var vA=rg.getValues();
var s='';
for(var i=0;i<vA.length;i++){
s+=Utilities.formatString('<br />%s', vA[i].join(','));
}
var userInterface=HtmlService.createHtmlOutput(s);
SpreadsheetApp.getUi().showModelessDialog(userInterface, 'The Active Range')
}
So I've created a program that is supposed to mark one of multiple columns when the if conditions are met, so we can categorize our marketing sectors.
If you look at the last line of code you will see sheet (which encapsulates everything) getRange (which defines the range that the next part,getCell should be inside of ) and then you will see getCell.
I added +1 to the get cell Variable because it is not considered an array and therefore doesn't start with zero, which means it an sum of 4 would start in fourth row (as opposed to the 5th row for arrays).The problem is that I get a "Cell reference out of range and google script editor will highlight the aforementioned row.
If the get range is within the sheet, and the getCell is within the getRange I dont know how this could happen.
function myFunction() {
var app = SpreadsheetApp;
var sheet = app.getActiveSpreadsheet().getActiveSheet();
var lr= sheet.getLastRow();
var dataRangeContact = sheet.getRange("B4:B"+lr);
var dataContact = dataRangeContact.getValues();
var dataRangeComp= sheet.getRange("M4:M"+lr);
var dataComp=dataRangeComp.getValues();
var IndigoColumn= sheet.getRange("L4:L"+lr);
var validIndigoColumn =12;
var validLabColumn=11;
var validDesColumn=10;
var validPocColumn=9;
var validArtColumn=8;
for(var i=3; i<=lr; i++) {
var lr=sheet.getLastRow();
var rowTwo=dataContact[i].toString();
var rowThirteen=dataComp[i].toString();
if (rowThirteen=="University Lab") {
if (rowTwo.match(/(process engineer|analytical chemist|scientist|sr.scientist|research scientist|test Engineer|Medical Devices professional|scientific)/i)) {
sheet.getRange(4,12,lr).getCell(i+1,validIndigoColumn).setValue("Y");
}
}
}}
I think this is the same function rewritten a little differently. It will most likely run faster. It only has one range so it may be easier to avoid range errors. Keep in mind that rows and columns start at 1 and array indices start at 0.
I sometimes do this sort of thing to keep them straight.
Anyway here's my shortened version of the function:
function myFunction(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
for(var i=3;i<vA.length;i++){
if(vA[i][12]=='University Lab' && vA[i][1].toString().match(/(process engineer|analytical chemist|scientist|sr.scientist|research scientist|test Engineer|Medical Devices professional|scientific)/i)){
vA[i][11]='Y';
}
}
rg.setValues(vA);//rewrites the data into the range including all changes all at one time
}
I have no way to test it.