I am new to Javascript, my error is Missing ; before statement on Line 25.
The other question was Java related, not JavaScript related.
Here is the code that is problematic.
Line 24 function emailChecker(){
Line 25 var readMessages() = DocumentApp.create();
Line 26 var emailAddress() = Session.getActiveUser().getEmail();
Line 27 GmailApp.getInboxUnreadCount();
Line 28 var unreadMessages() = InboxUnreadCount();
Line 29 GmailApp.sendEmail(emailAddress) (You have + unreadMessages + unread messages!)
}
The problem is at var readMessages() = .... when you write var x = something;, you are assigning something to the variable x. Brackets are used for functions, not variables. Try this instead:
var readMessages = DocumentApp.create();
Related
I have this statement:
var destinationRange = destinationSheet.getRange("D26:E39");
and want to replace it with
var destinationRange = destinationSheet.getRange(daGrowaRange);
The reason I want to use daGrowaRange is not just cause da name, but that the range is not always the same.
D is a fixed constant value and never changes
E is a fixed constant
value and never changes
BUT
26 is dynamic and changes and
39 is an offset based on the 26 (in
this case 13 so 39 = 26+13, but the 13 is a variable value also).
I am sure that I could put this together in some ugly ass way, but I am sick of looking at my crappy code and want to learn how you crackz out there make it nice.
Thank you
You can use Template literals to accomplish this task:
const dValue = 26;
const eValue = dValue + 13;
const daGrowaRange = `D${dValue}:E${eValue}`;
const destinationRange = destinationSheet.getRange(daGrowaRange);
I have a variable which needs to be formatted into a 4 digit format,
i.e. 4 would be 0004, or 38 would be 0038
I've tried using getNumberFormat as below but this gives me no luck. Looking around I'm struggling to find a clean solution to this?
var stringVal = 38;
var prettyVal = stringVal.getNumberFormat('0000');
worksheet.getRange(row+1, AUTOINC_COLUMN+1).setValue("GL"+prettyVal);
EDIT - It needs to be formatted before being placed into my spreadsheet - since I'll append the string 'GL' before the value to form the key
To achieve expected result, use below option
var stringVal = 38;
var format = "0000"
var prettyVal = stringVal.toString().length < 4 ? format.slice(stringVal.toString().length) + stringVal.toString() : stringVal ;
console.log(prettyVal)
I'm assuming you are referring to a spreadsheet. Once you have placed the value in a cell or cells you can setNumberFormat.
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("A1");
range.setValue(38);
range.setNumberFormat("000#");
I am running a function which I am trying to find the value for the last row, last column of a sheet and use this value as part of a range value. In my test sheet, the last column, last row value is the number 3.
Lines 45 and 46 are from another function I am using on the same sheet to rename the active sheet. This function works OK, i.e., the script finds the number 3 and renames the active sheet to 3.
Line 56 shows that the script works properly when using static values.
Line 57 is my attempt to use the getLastRow and getLastColumn method to insert this number as part of the getRange values. When I run this script, it throws an error “Range not found”.
The “Logger.log” value at Line 55 is 3.0 and shows that the script is running up to that point. I conclude that the error is coming from Line 57.
Questions:
1. Am I trying to do something that cannot be done by using the (lastCell, getValue()) value? As mentioned, the value is 3.0 and not just 3, but this works for Lines 45 and 46.
2. If this can be done, am I formatting the information incorrectly? I have also tried to write Line 57 as (‘A:A+(lastCell.getValue())’) by adding the “+” sign.
Thanks for any assistance!
45 // SpreadsheetApp.setActiveSheet(ss.getSheetByName('Copy of Sheet1'));
46 // SpreadsheetApp.getActiveSpreadsheet().renameActiveSheet(lastCell.getValue()); This works OK!!!
47 //
48 // Next need to make the next row have columnA and last Column data added
49 //
50 var ss = SpreadsheetApp.getActiveSpreadsheet();
51 var sheet = ss.getSheetByName('Master FCR Listing');//ss.getSheets()[1];
52 var lastColumn = sheet.getLastColumn();
53 var lastRow = sheet.getLastRow();
54 var lastCell = sheet.getRange(lastRow, lastColumn);
55 Logger.log(lastCell.getValue());// Shows a value of 3.0 ?? This the problem??
56 //* sheet.getRange('A:A3').copyTo(sheet.getRange('A:A4')); //. This works!
57 sheet.getRange('A:A(lastCell.getValue())').copyTo(sheet.getRange('A:A4'));//A4 will be +1!
Replace
sheet.getRange('A:A(lastCell.getValue())')
to
sheet.getRange('A:A'+(lastCell.getValue()))
to pass the range in format of string.
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.
In a mail merge application I use the .replace() method to replace field identifiers by custom values and also in a reverse process to get the identifiers back.
The first way works every time since the replace first argument is a pretty normal string that I have chosen on purpose... but when I reverse the process it happens sometimes that the string contains incorrect regular expression characters.
This happens mainly on phone numbers in the form +32 2 345 345 or even with some accentuated characters.
Given I can't prevent this from happening and that I have little hope that my endusers won't use this phone number format I was wondering if someone could suggest a workaround to escape illegal characters when they come up ? note : it can be at any place in the string.
below is the code for both functions.
... (partial code)
var newField = ChampSpecial(curData,realIdx,fctSpe);// returns the value from the database
if(newField!=''){replacements.push(newField+'∏'+'#ch'+(n+1)+'#')};
//Logger.log('value in '+n+'='+realIdx+' >> '+Headers[realIdx]+' = '+ChampSpecial(curData,realIdx,fctSpe))
app.getElementById('textField'+(n+1)).setHTML(ChampSpecial(curData,realIdx,fctSpe));
if(e.parameter.source=='insertInText'){
body.replaceText('#ch'+(n+1)+'#',newField);
}
}
UserProperties.setProperty('replacements',replacements.join('|'));
cloakOn();
colorize('#ffff44');
return app;
}
function fieldsInDoc(e){
cloakOff();// remet d'abord les champs vides
var replacements = UserProperties.getProperty('replacements').split('|');
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
for(var n=0;n<replacements.length;++n){
var field = replacements[n].split('∏')[1];
var testVal = replacements[n].split('∏')[0];
body.replaceText(testVal,field);
}
colorize('#ffff44');
}
In the reverse process you are using the fieldvalues provided that can include regex special characters. you have to escape them before replacing:
body.replaceText(field.replace(/[[\]{}()*-+?.,\\^$|#\s]/, '\\$&'), '#ch'+(n+1)+'#');
This said, the "replace back the markers" a bad idea. What happens if two fields of the mail merge have the same value or the replacement text is already present in the document template...
One possible solution was to prevent the example fields in the doc from containing regex special characters so the replace had to occur in the forward process, not in the reverse (as suggested in the other answer).
Escaping these character in the fields values didn't work* so I ended up with a simple replacement by a hyphen (which make sense in most cases to replace a slash or a '+').
(*) the reverse process uses the value kept in memory so the escape sign was disturbing the replace in that function, preventing it to work properly.
the final working code goes simply like this :
//(in the first function)
var newField = ChampSpecial(curData,realIdx,fctSpe).replace(/([*+?^=!:${}()|\[\]\/\\])/g, "-");// replace every occurrence of *+?^... by '-' (global search)
About the comment stating that this approach is a bad idea I can only say that I'm afraid there is not really other ways to get that behavior and that the probability to get errors if finally quite low since the main usage of mail merge is to insert proper names, adresses, emails and phone numbers that are rarely in the template itself.
As for the field indicators they will never have the same name since they are numerically indexed (#chXX#).
EDIT : following Taras's comment I'll try another solution, will update later if it works as expected.
EDIT June 19 , Yesssss... found it.
I finally found a far better solution that doesn't use regular expression so I'm not forced to escape special characters ... the .find() method accepts any string.
The code is a bit more complex but the results is worth the pain :-))
here is the full code in 2 functions if ever someone looks for something similar.
function valuesInDoc(e){
var lock = LockService.getPrivateLock(); // just in case one clicks the second button before this one ends
var success = lock.tryLock(5000);
if (!success) {
Logger.log('tryLock failed to get the lock');
return
}
colorize('#ffffff');// this function removes the color tags on the field marlers
var app = UiApp.getActiveApplication();
var listVal = UserProperties.getProperty('listSel').split(',');
var replacements = [];
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var find = body.findText('#ch');
if(find == null){return app };
var curData = UserProperties.getProperty('selItem').split('|');
var Headers = [];
var OriHeaders = UserProperties.getProperty('Headers').split('|');
for(n=0;n<OriHeaders.length;++n){
Headers.push('#'+OriHeaders[n]+'#');
}
var fctSpe = 0 ;
for(var i in Headers){if(Headers[i].indexOf('SS')>-1){fctSpe = i}}
for(var n=0;n<listVal.length;++n){
var realIdx = Number(listVal[n]);
Logger.log(n);
var newField = ChampSpecial(curData,realIdx,fctSpe);
//Logger.log(newField);
app.getElementById('textField'+(n+1)).setHTML(ChampSpecial(curData,realIdx,fctSpe));
if(e.parameter.source=='insertInText'){
var found = body.findText('#ch'+(n+1)+'#');// look for every field markers in the whole doc
while(found!=null){
var elemTxt = found.getElement().asText();
var startOffset = found.getStartOffset();
var len = ('#ch'+(n+1)+'#').length;
elemTxt.deleteText(startOffset, found.getEndOffsetInclusive())
elemTxt.insertText(startOffset,newField);// remove the marker and write the sample value in place
Logger.log('n='+n+' newField = '+newField+' for '+'#ch'+(n+1)+'#'+' at position '+startOffset)
replacements.push(newField+'∏'+'#ch'+(n+1)+'#'+'∏'+startOffset);// memorize the change that just occured
found = body.findText('#ch'+(n+1)+'#',found); //loop until all markers are replaced
}
}
}
UserProperties.setProperty('replacements',replacements.join('|'));
cloakOn();
colorize('#ffff44');// colorize the markers if ever one is left but it shouldn't happen
lock.releaseLock();
return app;
}
function fieldsInDoc(e){
var lock = LockService.getPrivateLock();
var success = lock.tryLock(5000);
if (!success) {
Logger.log('tryLock failed to get the lock');
return
}
cloakOff();// remet d'abord les champs vides > shows the hidden fields (markers that had no sample velue in the first function
var replacements = UserProperties.getProperty('replacements').split('|');// recover replacement data as an array
Logger.log(replacements)
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
for(var n=replacements.length-1;n>=0;n--){ // for each replacement find the data in doc and write a field marker in place
var testVal = replacements[n].split('∏')[0]; // [0] is the sample value
if(body.findText(testVal)==null){break};// this is only to handle the case one click on the wrong button trying to place markers again when they are already there ;-)
var field = replacements[n].split('∏')[1];
var testValLength = testVal.length;
var found = body.findText(testVal);
var startOffset = found.getStartOffset();
Logger.log(testVal+' = '+field+' / start: '+startOffset+' / Length: '+ testValLength)
var elemTxt = found.getElement().asText();
elemTxt.deleteText(startOffset, startOffset+testValLength-1);// remove the text
// elemTxt.deleteText(startOffset, found.getEndOffsetInclusive() )
elemTxt.insertText(startOffset,field);// and write the marker
}
colorize('#ffff44'); // colorize the marker
lock.releaseLock();// and release the lock
}