You don't say, but apparently you're using a library, "ScriptsLib". I've done searches, but can't find any public code with both getRowsData
and getKeys
methods, so it's probably a private library.
I need to do some guessing about what those two functions do. If you can provide the source for them from your ScriptsLib, it would help to validate or revise my guesses, which are:
The getRowsData
method creates an array of objects, by calling getObjects
. The getObjects
method iterates over the given range creating an array of objects with named properties from each row. If there is a blank cell in a row, there will be no property with the name for that column.
In your code, you loop over the keys contained in data[0]
, which will be incomplete (missing properties) when there were blanks in the source data, because of the way getObjects
works. That means that you never really process the blanks, and don't have an opportunity to replace the relevant keys with "N/A".
What you need to do then, is loop over the key values that are in the template document - and those are probably represented by the headings in the spreadsheet. (...after normalization to camelCase, that is).
var keys = ScriptsLib.normalizeHeaders(sheet.getRange('A1:1').getValues()[0]);
That will give us the full list of keys to iterate over. But we're not done yet.
You've got a bug in the logic that checks whether you have a property. Look at this line:
if (data[0][keys[key]] != null || data[0][keys[key]] != ''){
With an OR operator there, you will end up executing the IF block when
data[0][keys[key]]
is null. You've written an else clause that should replace a key with "N/A", but it's not going to get executed.
:: when data[0][keys[key]] == null
data[0][keys[key]] != null :: false
data[0][keys[key]] != '' :: true (because null != '')
You probably meant to use AND.
if (data[0][keys[key]] != null && data[0][keys[key]] != ''){
That should make things work the way you want. But I'd suggest explicitly dealing with the possibility that a data object won't have a property with a particular key name, and getting around that and/or bug at the same time. JavaScript gives us hasOwnProperty()
to do that.
if (data[0].hasOwnProperty(keys[key])) // property is present
The refactored code becomes:
function formatTemplate(){
var postFlightTemplate = DocsList.getFileById('templateKey').makeCopy().getId();
var template = DocumentApp.openById(postFlightTemplate);
var templateHeader = template.getHeader();
var templateBody = template.getActiveSection();
var flightLog = SpreadsheetApp.openById('spreadsheetKey');
var sheet = flightLog.getSheetByName('Flight Tracking');
var data = ScriptsLib.getRowsData(sheet, sheet.getRange('A2:2'), 1);
var keys = ScriptsLib.normalizeHeaders(sheet.getRange('A1:1').getValues()[0]);
for (var key in keys){
if (data[0].hasOwnProperty(keys[key])) { // property is present
Logger.log('key:'+keys[key]+' / value:'+data[0][keys[key]]);
templateHeader.replaceText('%'+keys[key]+'%', data[0][keys[key]]);
templateBody.replaceText('%'+keys[key]+'%', data[0][keys[key]]);
}else{
Logger.log('empty key:'+keys[key]+' / value:'+data[0][keys[key]]);
templateBody.replaceText('%'+keys[key]+'%', 'N/A');
}
}
template.setName('RR-'+data[0].incidentNumber+'-'+data[0].flightNumber);
template.saveAndClose();
MailApp.sendEmail('email@email.com', 'Post Flight Report','See Run Report', {name: 'P1AR Flight Log', attachments: template});
}