what I want to do is access an excel file, take the contents of a column and then store it in an array. I'm guessing this can be done by iterating through each element of the range object and copying it to an array. My current code is shown below:
function GetData(){
var excel = new ActiveXObject("Excel.Application");
var excel_file = excel.Workbooks.Open("C:\\Data.xls");
var excel_sheet = excel.Worksheets("Sheet2");
//returns a RANGE object
var myrow = excel_sheet.Columns(1);
//doing this puts a single range object in myarray
var myarray = new Array(myrow);
//try printing the contents of the range object
for (mycell in myrow){
document.getElementById('div1').innerHTML = mycell;
}
}
Please check the following code to get data from an excel file. Hope this helps you:
CODE:
function GetData(){
var excel = new ActiveXObject("Excel.Application");
var excel_file = excel.Workbooks.Open("C:\\Data.xls");
var excel_sheet = excel.Worksheets("Sheet2");
for(var i=2;i<20;i++){
var myrow = excel_sheet.Range("A"+i); //to read values in row A
document.getElementById('div1').innerHTML = myrow;
}
}
Tested in IE9.
Related
I am trying to copy the logger values into a dedicated tab(history) in the same spreadsheet with a date and time stamp,
I am getting values in the logger just need to arrange them and copy them into a dedicated tab(history).
its gonna have 2 trigers per day and every day a new column in the new dedicated tab(history).
thank.
// custom menu function
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('History')
.addItem('save','saveData')
.addToUi();
}
// function to save data
function saveData() {
// starts with active sheet for data entry
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Moshiko");
var sheet2 = ss.getSheetByName("History");
// collects values in data entry row
var total = sheet.getRange("Moshiko!O11:O34").getValues();
var daily = sheet.getRange("Moshiko!R11:R34").getValues();
var portfolio = sheet.getRange("Moshiko!L11:L34").getValues();
var lastportfolio = sheet.getRange("Moshiko!Q11:Q34").getValues();
var curentstock = sheet.getRange("Moshiko!K11:K33").getValues();
var laststock = sheet.getRange("Moshiko!P11:P33").getValues();
var buystock = sheet.getRange("Moshiko!I11:I33").getValues()
var all = [[total,daily,portfolio,lastportfolio,curentstock,laststock,buystock,]];
Logger.log(all);
Issues:
The return of .getValues() is 2 dimensional array. Appending [[]]
will make it 4 dimensional array. .setValues() can only take 2
dimensional array.
The data collected is in row data. Each row represent sub-array in our 2d array.
Row data example: [[a][b][c][d]]
This is what it looks like in sheets:
Solution:
Merge the collected row data using concat(). This will make [[a][b][c][d]] into [a,b,c,d].
Since the structure of the concatenated data is now in single row format, we can transpose it to make it column data.
Example Data:
Code:
function myFunction() {
// starts with active sheet for data entry
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Moshiko");
var sheet2 = ss.getSheetByName("History");
// collects values in data entry row
var total = sheet.getRange("Moshiko!O11:O34").getValues();
var daily = sheet.getRange("Moshiko!R11:R34").getValues();
var portfolio = sheet.getRange("Moshiko!L11:L34").getValues();
var lastportfolio = sheet.getRange("Moshiko!Q11:Q34").getValues();
var curentstock = sheet.getRange("Moshiko!K11:K33").getValues();
var laststock = sheet.getRange("Moshiko!P11:P33").getValues();
var buystock = sheet.getRange("Moshiko!I11:I33").getValues();
var columns = [["Total", "Daily", "portfolio", "lastportfolio", "currentstock", "laststock", "buystock"]]
var date = Utilities.formatDate(new Date(), "GMT+8", "dd/MM/yyyy")
var dateStamp = [["Date stamp", date]]
//concat each 2d array to make 1d array and enclose the 1d arrays with '[]' to make it 2d.
var arr = [[].concat(...total),[].concat(...daily),[].concat(...portfolio),[].concat(...lastportfolio),[].concat(...curentstock),
[].concat(...laststock),[].concat(...buystock)];
//set dateStamp
sheet2.getRange("A1:B1").setValues(dateStamp);
//set columns
sheet2.getRange("A2:G2").setValues(columns);
//set values
Logger.log(arr)
var transposed_arr = transpose(arr);
Logger.log(transposed_arr.length);
Logger.log(transposed_arr[0].length);
sheet2.getRange(3, 1, transposed_arr.length, transposed_arr[0].length).setValues(transposed_arr);
}
function transpose(matrix) {
return matrix[0].map((col, i) => matrix.map(row => row[i]));
}
Output:
Reference:
Array.concat
setValues
getValues
I have a script that takes data from a gsheet and replaces placeholders on gdoc. I am looking to optimise the script by using arrays instead.
This is a sample of my gsheet (the original gsheet spans 1000+ rows and 15+ columns),
Original script:
function generategdoc() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").activate();
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow();
for (var i =2;i<=lr;i++){
if(ss.getRange(i, 1).getValue()){
//Make a copy of the template file
var documentId = DriveApp.getFileById('FileID').makeCopy().getId();
var Client = ss.getRange(i, 2).getValue();
var Amount = ss.getRange(i, 3).getValue();
var AmountFormat = Amount.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
var Date = ss.getRange(i, 4).getValue();
var temp = new Date(Date)
var DateFormat = Utilities.formatDate(temp, "GMT+0400", "dd MMM yyyy")
//Rename the copied file
DriveApp.getFileById(documentId).setName(Client);
//Get the document body as a variable
var body = DocumentApp.openById(documentId).getBody();
body.replaceText('##Client##', Client).replaceText('##Amount##', AmountFormat).replaceText('##Date##', DateFormat)
}
else {}
}
}
As you can see this script will only run for all the rows which have been checkboxed TRUE.
Attempt 1 at optimising:
function optimise() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").activate();
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow();
var rng = ss.getRange("A1:"+"D"+lr).getValues(); //Creation of Array
for (var i =2;i<=lr;i++){
if(ss.getRange(i, 1).getValue()){
var Client = rng[i-1][1];
var Amount = rng[i-1][2];
var Date = rng[i-1][3];
var documentId = DriveApp.getFileById('FileID').makeCopy().getId();
DriveApp.getFileById(documentId).setName(Client);
var body = DocumentApp.openById(documentId).getBody();
body.replaceText('##Client##', Client).replaceText('##Amount##', Amount).replaceText('##Date##', Date)
}
else {}
}
}
Question:
I was able to format the original script for Amount and Date. How can I have the same formatting for arrays? As I cant apply formatDate(class utilities) and toFixed to my variables anymore because they are now arrays.
I believe you can optimize your code by using the appropriate method(s) to preserve the text format of your Google sheet values.
Look into using the following method(s) of class Range from SpreadsheetApp service.
Method getDisplayValue() returns the displayed value of the cell in the range. The value is a String. The displayed value takes into account date, time and currency formatting, including formats applied automatically by the spreadsheet's locale setting. Empty cells return an empty string.
This should optimize your code by removing the necessity of regex. If I didn't understand your issue correctly, please leave a comment.
References:
getDisplayValue()
getDisplayValues()
getRichTextValue()
getRichTextValues()
You can try something like this. But it may not make any difference because creating files takes a long time.
function optimise() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var vA= ss.getRange(1,1,ss.getLastRow(),4).getValues();
var file = DriveApp.getFileById('FileID');
for(var i=0;i<vA.length;i++){
if(vA[i][0]){
var Client=vA[i][1];
var Amount=vA[i][2];
var Date=vA[i][3];
DriveApp.getFileById(file.makeCopy().getId()).setName(Client);
var body=DocumentApp.openById(documentId).getBody();
body.replaceText('##Client##', Client).replaceText('##Amount##', Amount).replaceText('##Date##', Date)
}
}
}
I wonder if you need to saveAndClose() the document.
I'm trying to create an input field in a google spreadsheet to enable simple data collection, but I'm having some trouble with a for loop. I'm a JS novice, and this is the first time I've attempted to use Google Apps Script.
App logic:
- data entered into a input field ("Sheet1!F13:F36")
- button with script assigned is clicked
- data is loaded from the input field and appended to a dataset in Sheet2
Please see my code below:
function appendToDB() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dashboard = ss.getSheetByName("Dashboard");
var inputRange = dashboard.getRange("F13:F36");
var db = ss.getSheetByName("Database");
var storeName = dashboard.getRange("C7").getValue();
var category = dashboard.getRange("C9").getValue();
for(var i=0; i<inputRange.length; i++){
var currentCellValue = inputRange[i].getValue();
db.appendRow([storeName,category,currentCellValue]);
}
}
The following dashboard.getRange("F13:F36") function returns a range class not an array. Hence when you do try to get a length like so inputRange.length you get a return of undefined and loop is never run.
You can get the values of the cells by using getValues and run through the array in loop and append the values to the db sheet like so
function appendToDB() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dashboard = ss.getSheetByName("Dashboard");
var inputRange = dashboard.getRange("F13:F36").getValues(); //returns a 2D array
var db = ss.getSheetByName("Database");
var storeName = dashboard.getRange("C7").getValue();
var category = dashboard.getRange("C9").getValue();
for(var i=0; i<inputRange.length; i++){
var currentCellValue = inputRange[i][0];
db.appendRow([storeName,category,currentCellValue]);
}
}
Equivalently, you can use getNumRows() function of range class, to get the number of rows. Use that as a counter to loop through to get individual values of individual cell by getCell(row,column).getValue()
Which would look like this:
function appendToDB() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dashboard = ss.getSheetByName("Dashboard");
var inputRange = dashboard.getRange("F13:F36");
var db = ss.getSheetByName("Database");
var storeName = dashboard.getRange("C7").getValue();
var category = dashboard.getRange("C9").getValue();
for(var i=1; i<=inputRange.getNumRows(); i++){
var currentCellValue = inputRange.getCell(i,1).getValue();
db.appendRow([storeName,category,currentCellValue]);
}
}
// save to CSV
var csv = document.getElementById('a');
var csvContent = new Array();
csvContent.push(["COL_A","COL_B","COL_C"]);
var fileName = "file.csv";
var blob = new Blob(["\ufeff", csvContent]);
var url = URL.createObjectURL(blob);
csv.href = url;
csv.setAttribute('download', fileName);
csv.click();
// load CSV file
..
var lines = loadedCsvFile.split(/\r\n|\n/);
var result = [];
var headers = lines[0].split(",");
for(var i=0;i<lines.length;i++){
var obj = {};
var currentLine = lines[i].split(",");
for(var j=0;j<headers.length;j++){
obj[headers[j]] = currentLine[j];
}
result.push(obj);
}
this is my csv save/load code.
But, this code can use only first sheet.
how can I use second sheet?
I should be very grateful to you if you might help me.
I assume you're talking about a CSV from Excel (or the likes) which 'had' multiple sheets?
CSVs don't use the sheet concept, they're are saved as a flat file. You will either need to save each sheet as a CSV individually and read separately, or concatenate the sheets.
I have a sheet that will update based on new articles in an RSS feed using importfeed() and the URLs are analyzed with importxml(). Problem is the data is always changing and I would like to archive old data from the importfeed() function. I'd just like to move the most updated data from one sheet to another without overwriting anything.
Here is the sample code from: https://stackoverflow.com/users/650206/jeremy:
function myFunction() {
// Get Spreadsheets
var source = SpreadsheetApp.openById("spreadsheetKeySource");
var target = SpreadsheetApp.openById("spreadsheetKeyTarget");
// Set Sheets
var source_sheet = source.getSheetByName("Sheet1");
var target_sheet = target.getSheetByName("Sheet1");
// Get target last row
var last_row = target_sheet.getLastRow();
// Set Ranges
var source_range = source_sheet.getRange("A1:B1");
var target_range = target_sheet.getRange("A"+(last_row+1)+":B"+(last_row+1));
// Fetch values
var values = source_range.getValues();
// Save to spreadsheet
target_range.setValues(values);
}
Problem with the above code is it only selects one row when I need it to select an entire range (e.g. A1:G55) and paste that data below the old data in another sheet.
Any help would be much appreciated!
EDIT
The error I'm getting when I change:
var source_range = source_sheet.getRange("A1:B1");
var target_range = target_sheet.getRange("A"+(last_row+1)+":B"+(last_row+1));
to:
var source_range = source_sheet.getRange("A1:G25");
var target_range = target_sheet.getRange("A"+(last_row+1)+":G"+(last_row+1));
is "Incorrect range height, was 5 but should be 1 (line 21, file "Code")"
which is this piece of code:
target_range.setValues(values);
var source_range = source_sheet.getRange("A1:G25");
var target_range = target_sheet.getRange("A"+(last_row+1)+":G"+(last_row+1));
The lines above attempt to copy 25 rows of data and paste that into one row. I'm surprised that the error message says "was 5 but should be 1". I'd have expected it to say "was 25 but should be 1".
Try this instead:
var source_range = source_sheet.getRange("A1:G25");
var target_range = target_sheet.getRange("A"+(last_row+1)+":G"+(last_row+25));