0 numeral not recognized when copying data from sheet to a file - javascript

I'm trying to create a my own CSV file using info in a google sheet. The info copies correctly, however any time there is a 0 in a cell, it gets ignored and I get a blank spot in my CSV file. Any suggestions? Code below.
function saveAsCSV() {
var filename = "trainingImport"; // CSV file name
var folder = "1vzTFeLwwR35XluyE39Uk9mzbLVJHE3XB"; // Folder ID
var sprdSheet = SpreadsheetApp.getActiveSpreadsheet();
var outPut = sprdSheet.getSheetByName("Output");
var range = outPut.getDataRange();
var values = range.getValues();
var csv = "";
for (var i = 0; i < values.length; i++) {
var row = "";
for (var j = 0; j < values.length[i]; j++) {
if (values[i][j]) {
row = row + values[i][j];
}
if (outPut.getRange((i+1),(j+2)).isBlank()) {
break;
}
row = row + ",";
}
csv += row + " \n";
}
var url = DriveApp.getFolderById(folder)
.createFile(filename, csv, MimeType.CSV)
.getDownloadUrl()
.replace("?e=download&gd=true","");
return url;
}

The problem lies in the if statement just in the inner for loop:
if (values[i][j]) {
row = row + values[i][j];
}
The statement will be false, if values[i][j] is 0, beacause 0 is falsy.
That means, that when converted to a Boolean, 0 acts like literal false, this also applies to empty strings, null, undefined and NaN.
If you change it to
if (values[i][j] || values[i][j] === 0) {
row = row + values[i][j];
}
0 will be added to the row.

Related

Convert entire Google Sheet to xlsx file

I have tried to amend the below script to essentially convert a entire google sheet to xlsx file, keeping tab names the same and locating them to a folder,
The issue I am experiencing with the below is that is is splitting out each tab into separate files but I would like to keep them all together in one file
https://webapps.stackexchange.com/questions/58615/export-all-sheets-in-a-spreadsheet-to-csv-in-google-apps
function saveAsxlsx() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
// create a folder from the name of the spreadsheet
var folder = DriveApp.getFolderById('xxxxxxx');
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".xlsx" extension to the sheet name
fileName = sheet.getName() + ".xlsx";
// convert all available sheet data to xlsx format
var xlsxFile = convertRangeToxlsxFile_(fileName, sheet);
// create a file in the Docs List with the given name and the xlsx data
folder.createFile(fileName, xlsxFile);
}
Browser.msgBox('Files are waitig in a folder named ' + folder.getName());
}
function convertRangeToxlsxFile_(xlsxFileName, sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var xlsxFile = undefined;
// loop through the data in the range and build a string with the xlsx data
if (data.length > 1) {
var xlsx = "";
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
xlsx += data[row].join(",") + "\r\n";
}
else {
xlsx += data[row];
}
}
xlsxFile = xlsx;
}
return xlsxFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
The script you're using was designed to get each sheet as a separate file. You can refer to this example instead that will convert Google Sheet to Excel XLSX Spreadsheet. I added a couple of lines to the code to save the file to a folder instead of sending an email as the example does.
function getGoogleSpreadsheetAsExcel() {
try {
var ss = SpreadsheetApp.getActive();
var url = 'https://docs.google.com/feeds/download/spreadsheets/Export?key=' + ss.getId() + '&exportFormat=xlsx';
var folder = DriveApp.getFolderById('folderID'); //Add the folder ID of the folder where you want to save the file
var params = {
method: 'get',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
muteHttpExceptions: true,
};
var blob = UrlFetchApp.fetch(url, params).getBlob();
blob.setName(ss.getName() + '.xlsx');
folder.createFile(blob)
} catch (f) {
Logger.log(f.toString());
}
}

Google Script Help Script to pull Values or Formulas depending on Cell

I have two functions that I am trying to combine into one or find a better way to write one function to get the proper end result.
My goal is to read a range of cells and append them to the first open set of columns to the right of the current data. Depending on what is in the cell, I would like it to either pull the value or the function of the cell. Some cells are text, some are numbers imported from other sheets and some are formulas that react to those numbers. While doing that, I also need it to pull the conditional formatting from the cells as well.
Here is what I currently have written and need to somehow combine recordValue and recordFormulas into one function that properly pulls the right information to the appended cells.
Any and all help would be appreciated!
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Record value')
.addItem('Record Formulas','testFormulas')
.addToUi();
}
function testFormulas() {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var row1 = 1;
var column1 = 31;
var row2 = 40;
var column2 = 6;
var values = sheet.getRange(row1,column1,row2,column2).getValues();
var formulas = sheet.getRange(row1,column1,row2,column2).getFormulasR1C1();
var i=0;
var j=0;
var rules = sheet.getConditionalFormatRules();
var newRules = [];
var sheet = ss.getSheets()[0];
newRules = newRules.concat(rules);
for( i=1; i<formulas.length; i++ ) {
for( j=4; j<formulas[0].length; j++ ) {
if( formulas[i][j] !== "" ) values[i][j] = formulas[i][j];
}
}
Logger.log(values);
sheet.getRange(1,1,values.length,values[0].length).setValues(values);
sheet.getRange(1,1,values.length,values[0].length).setNumberFormats(format);
}
catch(err) {
Logger.log(err);}
var rowToWriteCounter = 1;
const firstColumnAvailable = sheet.getLastColumn() + 1;
var columnToWriteCounter;
for (var row in values) {
columnToWriteCounter = firstColumnAvailable;
for (var col in values[row]) {
//write to the new cell
sheet.getRange(rowToWriteCounter, columnToWriteCounter).setValue(values[row][col]).setBorder(true, true, true, true, false, false);
//this part checks for conditional formatting
for (var r = 0; r < rules.length; r++) {
var rule = rules[r];
//Get condition for each rule
var booleanCondition = rule.getBooleanCondition();
//Get the ranges to which each rule applies and iterate through
var ranges = rule.getRanges();
for (var i = 4; i < ranges.length; i++) {
var ruleColumn = ranges[i].getColumn();
var ruleRow = ranges[i].getRow();
//If condition isn't null and edited column is the same as the one in the range, add rule
if ((ruleColumn == Number(col)+1) && (ruleRow == Number(row)+1) && (booleanCondition != null)) {
var newRule = SpreadsheetApp.newConditionalFormatRule()
.withCriteria(booleanCondition.getCriteriaType(), booleanCondition.getCriteriaValues())
.setBackground(booleanCondition.getBackgroundObject())
.setBold(booleanCondition.getBold())
.setItalic(booleanCondition.getItalic())
.setRanges([sheet.getRange(rowToWriteCounter, columnToWriteCounter)])
.build();
newRules.push(newRule);
}
}
}
sheet.setConditionalFormatRules(newRules);
columnToWriteCounter++;
}
rowToWriteCounter++;
}
}
Here is a simple test case for combining values and formulas.
function test() {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Sheet3");
var values = sh.getDataRange().getValues();
var formulas = sh.getDataRange().getFormulas();
var format = sh.getDataRange().getNumberFormats();
var i=0;
var j=0;
for( i=0; i<formulas.length; i++ ) {
for( j=0; j<formulas[0].length; j++ ) {
if( formulas[i][j] !== "" ) values[i][j] = formulas[i][j];
}
}
Logger.log(values);
sh = ss.getSheetByName("Sheet4");
sh.getRange(1,1,values.length,values[0].length).setValues(values);
sh.getRange(1,1,values.length,values[0].length).setNumberFormats(format);
}
catch(err) {
Logger.log(err);
}
}

Generate JS files from google sheets using app script

I am trying to create a folder structure and javascript files based on the sheet name and the Type (column a). Where Type "Spec" starts i'd like to group everything between where "Spec" begins and ends and input the content into that file using Google App Script.
Content Example
Desired Output
Code Example
The current code I have to get this is below. But I'm currently not able to add the middle content in.
function export() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var filename = ""
for (var i in sheets) {
var name = sheets[i].getSheetName();
var fo = DriveApp.getFoldersByName(name);
var folder = fo.hasNext() ? fo.next() : DriveApp.getRootFolder().createFolder(name);
var values = sheets[i].getDataRange().getValues();
values.shift();
var type, title, value, emptyCode, code;
for (var j in values) {
[type, title, value, emptyCode, code] = values[j];
if (type == "Spec") {
var filename = title+'.js'
folder.getFilesByName(filename).hasNext() || folder.createFile(filename, code, MimeType.PLAIN_TEXT)
}
}
}
}
I had to edit the code slightly to add the title into the file and change the filename.
function generateStories() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (var i in sheets) {
var sheetName = sheets[2].getSheetName();
var fo = DriveApp.getFoldersByName(sheetName);
var folder = fo.hasNext() ? fo.next() : DriveApp.getRootFolder().createFolder(sheetName);
var values = sheets[2].getDataRange().getValues();
var type, title, code;
loop1:
for (var j = 0; j < values.length; j++) {
type = values[j][0];
if (type == "Spec") {
var title = values[j][1];
var filename = title+'.spec';
var code = values[j][4] + "\n";
loop2:
for (i = j+1; i < values.length; i++){
if (values[i][0] != "Spec"){
code += values[i][4] + "\n";
} else {
break loop2;
}
}
folder.getFilesByName(filename).hasNext() || folder.createFile(filename, code, MimeType.PLAIN_TEXT);
}
}
}
}
Two things
Values is a 2-D array - you need to address single values by specifying a row and a column indices, e.g. values[0][1] or values[i][4]
You need to specify the beginning and end of the content of each file. This can be done with the method indexOf() to verify in which rows type == "Spec" is fullfilled or with a combination of two nested for loops and an if statement.
Here is a sample of how to implement the functionality with the nested loops and statement combination:
function export() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (var i in sheets) {
var name = sheets[i].getSheetName();
var fo = DriveApp.getFoldersByName(name);
var folder = fo.hasNext() ? fo.next() : DriveApp.getRootFolder().createFolder(name);
var values = sheets[i].getDataRange().getValues();
var type, title, value, emptyCode, code;
loop1:
for (var j = 0; j < values.length; j++) {
type = values[j][0];
if (type == "Spec") {
var title = values[j][4];
var filename = title+'.js';
var code = "";
loop2:
for (i = j+1; i < values.length; i++){
if (values[i][0] != "Spec"){
code += values[i][4] + "\n";
} else {
break loop2;
}
}
folder.getFilesByName(filename).hasNext() || folder.createFile(filename, code, MimeType.PLAIN_TEXT);
}
}
}
}

Javascript Read data from spreadsheet

I am using a HTML form to get data from google spreadsheet.
I need to get the row where SerNo= 2 (or any specific number)
I am looping through the sheet and trying to get the values as below - but it does nothing
ex:
SerNo Col2
2 Option1
3 Option2
4 Option3
So,if SerNo=2 ...I want to get Option1.
This has 24 columns so i have used the getLastColumn
{function getDataRows_(ss, sheetname) {
var sh = ss.getSheetByName(sheetname);
var lr= sh.getLastRow();
for(var i=1;i<=lr;i++){
var SerNo1 = sh.getRange(i, 2).getValue();
if(SerNo1==SerNo){
return sh.getRange(i, 2, 1, sh.getLastColumn()).getValues();
}
}
}
----edit---
I have posted the whole code I use since it looks like i am filtering records at the wrong place
function read_value(request,ss){
var output = ContentService.createTextOutput(),
data = {};
var sheet="sheet1";
data.records = readData_(ss, sheet);
var callback = request.parameters.callback;
if (callback === undefined) {
output.setContent(JSON.stringify(data));
} else {
output.setContent(callback + "(" + JSON.stringify(data) + ")");
}
output.setMimeType(ContentService.MimeType.JAVASCRIPT);
return output;
}
function readData_(ss, sheetname, properties) {
if (typeof properties == "undefined") {
properties = getHeaderRow_(ss, sheetname);
properties = properties.map(function(p) { return p.replace(/\s+/g, '_'); });
}
var rows = getDataRows_(ss, sheetname),
data = [];
for (var r = 0, l = rows.length; r < l; r++) {
var row = rows[r],
record = {};
for (var p in properties) {
record[properties[p]] = row[p];
}
data.push(record);
}
return data;
}
function getDataRows_(ss, sheetname) {
var sh = ss.getSheetByName(sheetname);
return sh.getRange(2, 1, sh.getLastRow() -1,sh.getLastColumn()).getValues();
}
function getHeaderRow_(ss, sheetname) {
var sh = ss.getSheetByName(sheetname);
return sh.getRange(1, 1, 1, sh.getLastColumn()).getValues()[0];
}
One thing I would recommend is to not retrieve the data on row at a time; in other words retrieve all of the data that you want to search through into an array (i.e. row 1 through last row) and then test each row of the array, looking for your value.

Deleting a file in Google Script .setTrashed 'You do not have authorization to perform that action.'

I am trying to create a csv file from a Google spreadsheet every day or so. for some reason, I can delete files using the .setTrashed(True) and the file will delete, but i get an error saying 'You do not have authorization to perform that action. '
here is my code. any help would be appreciated.
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
// create a folder from the name of the spreadsheet
var folder = DocsList.getFolder(ss.getName().toLowerCase().replace(/ /g,'_'));
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
// update a file in the Docs List with the given name and the csv data
var folder = DocsList.getFolder('fitbitdata_mk3');
folder.createFile(fileName, csvFile);
deleteDocByName('Sheet1.csv');
Logger.log('deleted');
// folder.createFile(fileName, csvFile); //i put it before the delete
}
Browser.msgBox('UPDATED Files are waiting in a folder named ' + folder.getName());
}
function deleteDocByName(fileName){
var docs=DocsList.find(fileName)
for(n=0;n<docs.length;++n){
if(docs[n].getName() == fileName){
var ID = docs[n].getId()
DocsList.getFileById(ID).setTrashed(true)
}
}
}
function convertRangeToCsvFile_(csvFileName, sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
// loop through the data in the range and build a string with the csv data
if (data.length > 1) {
var csv = "";
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
I had the same problem. Please star the issue on the issue tracker here.
https://code.google.com/p/google-apps-script-issues/issues/detail?id=4145&colspec=Stars%20Opened%20ID%20Type%20Status%20Summary%20Component%20Owner

Categories