Cannot convert NaN to (class) - google-apps-script

While writing a Google Apps Script, I ran across this error:
"Cannot convert NaN to (class). (line 19, file "Code")
The line in question:
pos[pos.length] =
ss.getSheets()[sheetNumber + 13].getRange(teamRow + i, teamCol + 1).getValue();
I searched stackoverflow, but the best I could find was that "getRange" wasn't being passed integers. However, I derived the teamRow and teamCol from integers, and i is an index for a for loop, also an integer.
This error only appears when I call my function through another function.
Final question: what does the error mean, and what can I do to fix it?

NaN means Not a Number. It is basically used in floating point arithmetic to significate that a value cannot be expressed using the convention. You can look for IEEE 754 to get more details.
Your error message informs you that, in your script, you are using a NaN value in an expression that forbids it.
To track it, you could make your life simplier in using local variables to store intermediate values. Then you'll be able to inspect them either using the debugger or by logging them, as suggested in a comment.
For instance :
var allSheets = ss.getSheets();
var targetSheetIndex = sheetNumber + 13;
var targetSheet = allSheets[targetSheetIndex];
var targetRow = teamRow + i;
var targetCol = teamCol + 1;
var targetCell = targetSheet.getRange(targetRow, targetCol);
var targetValue = targetCell.getValue();
Using this technique you can identify where your code may fail and prevent it from failing by guarding it with tests (existence tests, boundary tests, …). After that, you can reassemble your code, either using your original single line or a balance between a single line and the above splitting example.

Related

JXA 'Can't convert types'

JavaScript for Apple Numbers - I'm trying to use the row.address of a selected range to step through a for{} loop, but the values returned aren't compatible integers (if that makes sense). A spreadsheet is open, and several rows are selected when the script runs.
var firstRow = cells[0].row.address;
var lastRow = cells[cells.length-1].row.address;
// these values seem valid, and can be inserted into the spreadsheet
cells[0].value = firstRow;
cells[1].value = lastRow;
for (i=firstRow; i<lastRow; i++) {
// this generates an error that terminates the script:
// The action "Run JavaScript" encountered
// an error: "Error: Error: Can't convert types."
cells[2].value = i; // this line never runs
}
If I use math on firstRow or lastRow, I get the same error (e.g., var j = lastRow+1), so it's like the 'integer' value isn't really an integer value. How do I reference these values as integers, or at least so as to not get the error?
Thanks.
I think you have to run the getter on address. It's all in the poor documentation: firstRow = cells[0].row.address(); should do the trick.
address is an "ObjectSpecifier", and address() is syntactic sugar to get the value of whatever this ObjectSpecifier points to.
You could try to get the properties of objects in JXA with app.properties(object), but that doesn't always work.

copyValuesToRange returns nothing if startColumn is integer

Writing a script where a cell with a formula is overwritten with value shown in the same cell. The following code WORKS (however formatted for readability):
var TargetHistorySheetRow = 95; //some arbitrary integer
var HistorySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("History");
HistorySheet.getRange(TargetHistorySheetRow, HistorySheet.getRange("1:1").getValues()[0].indexOf("Allocated")+1)
.copyValuesToRange(
HistorySheet,
HistorySheet.getRange("1:1").getValues()[0].indexOf("Allocated")+1,
HistorySheet.getRange("1:1").getValues()[0].indexOf("Allocated")+1,
TargetHistorySheetRow,
TargetHistorySheetRow
);
There is a repeating piece of code throughout (HistorySheet.getRange("1:1").getValues()[0].indexOf("Allocated")+1;) for finding a specific column number dynamically. For readibility, I moved this snippet to a variable and used the variable throughout instead. The following update DOES NOT WORK and changes the target cell to a blank
var TargetHistorySheetRow = 95; //some arbitrary integer
var HistorySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("History");
var HistorySheetAllocatedColumn = HistorySheet.getRange("1:1").getValues()[0].indexOf("Allocated")+1;
HistorySheet.getRange(TargetHistorySheetRow, HistorySheetAllocatedColumn)
.copyValuesToRange(
HistorySheet,
HistorySheetAllocatedColumn,
HistorySheetAllocatedColumn,
TargetHistorySheetRow,
TargetHistorySheetRow
);
However, if I change only the startColumn parameter of copyValuesToRange back, it WORKS again:
HistorySheet.getRange(TargetHistorySheetRow, HistorySheetAllocatedColumn)
.copyValuesToRange(
HistorySheet,
HistorySheet.getRange("1:1").getValues()[0].indexOf("Allocated")+1,
HistorySheetAllocatedColumn,
TargetHistorySheetRow,
TargetHistorySheetRow
);
Changing that parameter to a static value (eg: 7), doesn't work either. What's going on here?
This appears to be a bug!
The behaviour you describe here is very interesting. When you call Range.copyValuesToRange(sheet, column, columnEnd, row, rowEnd), according to the documentation, the column, columnEnd, row and rowEnd parameters should all be Integers.
Now after some testing, you can see that the following line returns number:
typeof HistorySheet.getRange("1:1").getValues()[0].indexOf("ColumnHeaderC")
As does:
typeof HistorySheet.getRange("1:1").getValues()[0].indexOf("ColumnHeaderC") + 1
However when you log HistorySheetTargetColumn and HistorySheet.getRange("1:1").getValues()[0].indexOf("ColumnHeaderC") + 1 separately, you get the following result:
var HistorySheetTargetColumn = (HistorySheet.getRange("1:1")
.getValues()[0]
.indexOf("ColumnHeaderC") + 1);
Logger.log('variable = ' + HistorySheetTargetColumn); // => variable = 3
Logger.log('method call = ' + HistorySheet.getRange("1:1")
.getValues()[0]
.indexOf("ColumnHeaderC") + 1);
// => method call = 21
You can see that the 21 concatenation happens because HistorySheet.getRange("1:1").getValues()[0].indexOf("ColumnHeaderC") is being evaluated as a string before the + operator, meaning that after the + 1 the value becomes 21 and not 3, as it should be if it was being evaluated as an integer.
It therefore appears that when you use HistorySheetTargetColumn in .copyValuesToRange() is is re-evaluating HistorySheet.getRange("1:1").getValues()[0].indexOf("ColumnHeaderC") + 1 each time, getting 2 from the indexOf() return as a string, and then concatenating the 1 at the end. This is why your cell is evaluating to be blank - because Cell A21 is blank.
Workaround:
You can fix this in the mean time by adding parenthesis around HistorySheet.getRange("1:1").getValues()[0].indexOf("ColumnHeaderC") + 1 on assignment:
var HistorySheetTargetColumn = (HistorySheet.getRange("1:1")
.getValues()[0]
.indexOf("ColumnHeaderC") + 1);
Reporting the Issue:
I have taken the liberty of reporting this on Google's Issue Tracker for you, detailing the behaviour:
Range.copyValuesToRange(sheet, column, columnEnd, row, rowEnd) reading string instead of integer
You can hit the ☆ next to the issue number in the top left on the page which lets Google know more people are encountering this and so it is more likely to be seen to faster.
References:
Google Apps Script - Range.copyValuesToRange(sheet, column, columnEnd, row, rowEnd)
w3schools - JavaScript Array indexOf() Method
MDN web docs - Arithmetic operators
Google's Issue Tracker
Range.copyValuesToRange(sheet, column, columnEnd, row, rowEnd) reading string instead of integer

Service error: Spreadsheets(line... with .setColumnFilterCriteria

This question is an extension from another.
Apply basic filter to multiple values in a spreadsheet column
I am experiencing an error, specifically Service error: Spreadsheets (line 8, file "Filter") with the following code:
function testFilter() {
var ss = SpreadsheetApp.getActive();
var monthlyDetailSht = ss.getSheetByName("Monthly_Detail");
var filterRange = monthlyDetailSht.getRange(2,12,359,1).getValues(); //Get L column values
var hidden = getHiddenValueArray2(filterRange,["Apple"]); //get values except Apple
var filterCriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hidden).build();
var rang = monthlyDetailSht.getDataRange();
var filter = rang.getFilter() || rang.createFilter();// getFilter already available or create a new one
//remove filter and flush
if(monthlyDetailSht.getFilter() != null){monthlyDetailSht.getFilter().remove();}
SpreadsheetApp.flush();
filter.setColumnFilterCriteria(12, filterCriteria);
};
//flattens and strips column L values of all the values in the visible value array
function getHiddenValueArray2(colValueArr,visibleValueArr){
var flatArr = colValueArr.map(function(e){return e[0];}); //Flatten column L
visibleValueArr.forEach(function(e){ //For each value in visible array
var i = flatArr.indexOf(e.toString());
while (i != -1){ //if flatArray has the visible value
flatArr.splice(i,1); //splice(delete) it
i = flatArr.indexOf(e.toString());
}
});
return flatArr;
}
I have used a Logger.log(hidden) to capture the values returned by the function and it is a list of all of the other "fruits" repeated as many times as they are available in column L. I am using fruits as a substitute for the sensitive data.
So here goes my question. Why am I getting that error now when it was working perfectly fine for a couple of days? How can I correct this?
Attempted fixes:
I've tried to add rows to the end of my data. Did not fix.
I tried removing filter, flushing, setting filter. Did not fix. (updated code above with what I did to flush in case anyone else is interested.)
It's working now. A couple of things I want to note for people who stumble upon this with their google searches. First, the issue was in fact an error on Google's side. Using the same code I have above it now works. I did not change it.
Second, I was able to record the filtering through the macro recorder and that code worked when my original code did not. This may help people who are on a time crunch and can't wait for google to get their stuff together. I'm still not sure what specifically in my original code caused the error, but my guess is that it does not matter. I've dedicated a full day to researching this error and it seems sporadic with not a single culprit. My issue may not be the same as yours if it happens in the future.
Hope that helps!

How to use the getRange() method with an array value as one of the parameters

I don't have much experience using Javascript but I'm developing a simple code to filter some information relevant to a professor I'm helping. I am searching the row number of a certain amount of data using a for and then I'm using an array to store all the rows that contain those words. Since I'm using Appscript, I only need to relocate a certain amount of data from the row I'm returning to a final row I've already know. My code is as follows:
if(cell === "Average")
{
index++;
initialcoords[index] = n; // n is the iteration variable in the for
}
I've tested the contents of the array and they are just fine, so I'm storing correctly the rows. The problem is that I'm using a different method to paste the data in a different sheet in Google Spreadhsheets. My code to do so is the following:
function pasteInfo()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getSheetByName("Sheet 1");
var destination = ss.getSheetByName("Sheet 2");
var range = source.getRange(initialcoords[1], 1, 8, 3);
range.copyValuesToRange(destination, 4, 6, 4, 6);
}
My probelm is the getRange() since it prints an error like this:
can't find method getRange((class),number,number,number).
I believe that even if n is declared as an integer, the values that I'm returning are of a different type incompatible with the getRange() method. Could anyone help me to confirm this and to help me convert it to integer? I would really appreciate your help.
You first need to define the Sheet you want to get the data from since a Spreadsheet can have multiple Sheets.
You need to ensure you have appropriate default values defined before using the parameters, otherwise the interpreter will start making guess.
Provide defaults if parameters are empty:
function fillLine(row, column, length, bgcolor)
{
row = row || 0;
column = column || 0;
length = length || 1;
bgcolor = bgcolor || "red";
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1+row, 1+column, 1, length).setBackground(bgcolor)
}
You may also try the solution offered by community: Can't get Google Scripts working

Can't Figure out why setValue() returns an error

Code I've run v1:
var G = SpreadsheetApp.getActiveSheet();
var Resp1 = UrlFetchApp.fetch(url1, parameters);
var parResp1 = JSON.parse(Resp1);
var k = parseInt(parResp1.time);
G.getRange("B5").setValues(k);
Code v2 Change replaces 4th line with:
var k = JSON.stringify(parResp1.time);
After I run my Code I get this error message
Cannot find method setValues(number). (line 27, file "Code")
The Value that is returned is a number but I don't understand why it doesn't see it as one.
What could be going on?
If you only want to update a single cell, in your case getRange("B5") you should use setValue, not setValues
setValues would be used in the case where you want to set the values for a range between two points such as "A1:B2"
While the other answer is correct, it doesn't explain the reason why you are having this error.
As mentioned in the documentation about setValues(), the argument for setValues() must be a 2 dimensions array (an array of arrays) either built from scratch or captured using getValues().
see The doc below :
By the way, the funny thing is that the title of your post uses setValue() without S while your code has the problematic S ...