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
Related
I have a code to add a array of content in a row but i need to add it in a specific range so the checkboxes in the first column are not read as information, so it can add up the row but in the same row that the checkbox it's in.
function criarRegistro() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("EQUIPAMENTOS NO LABORATÓRIO");
var destinyLog = ss.getSheetByName("EQUIPAMENTOS NO LABORATÓRIO");
sheet.activate();
var source = sheet.getRange("C2:G2");
var rangeLimpeza = sheet.getRange("C2:G2");
var values = source.getValues();
//rangeLimpeza.clearContent();
destinyLog.appendRow(values[0]);
ss.toast("Registro finalizado");
SpreadsheetApp.flush();
}
That's the code i'm using, basically i want to appendRow or copy the row information starting in B column, while in the A column i would have a preset of unmarked checkboxes.
You cannot use appendRow but you can calculate the correct destination range where the values should be copied and then use a basic getRange().setValues().
Rewriting and cleaning your function
function criarRegistro() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("EQUIPAMENTOS NO LABORATÓRIO");
var destinyLog = ss.getSheetByName("EQUIPAMENTOS NO LABORATÓRIO");
var source = sheet.getRange("C2:G2");
var values = source.getValues();
var nbOfCols = values[0].length; // how many columns do we need
var lastLineOfData = destinyLog.getDataRange().getNumRows() // how many rows are already present in the destination
destinyLog.getRange(lastLineOfData+1, 2, 1, nbOfCols).setValues(values) // we write after the last line, starting at the second column (B)
ss.toast("Registro finalizado");
SpreadsheetApp.flush();
}
My information is set in columns (A to E), info paste in 2 rows (A2:A3, B2:B3...). What I want to happen is when info set in last column E (E2:E3, E5:E6 and more), new info paste with a new row in column A (A5:A6, B5:B6).
My info is in the spreadsheet:
This code paste info doesn't work correctly:
function submitData1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form"); //Form Sheet
var datasheet = ss.getSheetByName("Job"); //Data Sheet
//Input Values
var values1 = [[formSS.getRange("B6").getValue()], [formSS.getRange("B7").getValue()]];
var sr = 1
var sc = 1
var nr = 2
var nc = 1
for (var i=1;i<1;i++)
var workingCell = datasheet.getRange(i,7);
{
if (workingCell ==null)
{datasheet.getRange(sr,datasheet.getLastColumn()+1,nr,nc).setValues(values1)
}
else {datasheet.getRange(datasheet.getLastRow()+1, sc, nr, nc).setValues(values1)
sc= sc+1}
}
}
Here is a sample replication code:
function submitData1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var datasheet = ss.getSheetByName("Job"); //Data Sheet
//Input Values
var values1 = [["Name X"], ["Job X"]];
var lastRow = datasheet.getLastRow();
var lastRow_ColCount = datasheet.getRange(lastRow,1,1,5).getValues().flat().filter(String).length;
Logger.log(lastRow);
Logger.log(lastRow_ColCount);
if(lastRow_ColCount==5){
//Add data on a new row, column A
datasheet.getRange(lastRow+2, 1,2,1).setValues(values1);
}
else{
//Add data on the next column in the same row
datasheet.getRange(lastRow-1, lastRow_ColCount+1,2,1).setValues(values1);
}
}
I used a fixed value for the input data during this replication.
Just replace the values from your original code that will be read from your form sheet
You can also remove the logs in the script, I just used them to debug the code
What it does?
Get the last row of the sheet, It will determine the last row that has a valid data
Get the data/values of the last row from column A to column E. Use Array.flat() to change 2-d array to 1-d array. Use Array.filter() to get non empty cells then count the data available in the last row.
If the current data available is 5, then the new data will be added on the new row, else the new data will be added on the next column
Output:
To get this specific function to work, I'm trying it out in a simple test sheet.
I've got two sheets(STATUS and FEBRUARI) in the FEBRUARI sheet I've selected a certain cell. This cell has a value. What I want the script to do is to look at that value, find that value in the STATUS sheet(say it finds it in A1) and return the value in B1 to a cell note in the selected cell in the FEBRUARI sheet. As example: in the cell it says "Project 6" and the cell-note gives info about this project.
This is what I got. This gives me a certain value(-1) but it doesn't seem to matter where i put the lookupvalue.. it always returns -1.
// My Script
function noteSetter() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lookupvalue = SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
var sheet = ss.getSheetByName("STATUS"); //source sheet
var sheet2 = ss.getSheetByName("FEBRUARI"); //result sheet
var cellnote = SpreadsheetApp.getActiveSheet().getActiveCell();
var lc = sheet.getLastColumn()
var lookup = sheet.getRange(1,1,1,lc).getValues() //
var index = lookup.indexOf(lookupvalue)
cellnote.setNote(index);
// This part will actually run the script once it's up and running
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Set cell note",
functionName : "noteSetter"
}];
sheet.addMenu("Scripts", entries);
};
}
var lookup = sheet.getRange(1,1,1,lc).getValues();
var index = lookup.indexOf(lookupvalue)
The first line returns a 2D array. indexOf() only works on flattened arrays. Try using:
var lookup = sheet.getRange(1,1,1,lc).getValues()[0];
According to Google preferably use getCurrentCell() instead of getActiveCell() because it returns the current highlighted (or selected) cell.
Also your onOpen() function should be outside of your noteSetter() function otherwise it is not being called when the spreadsheet opens.
The following code will do what you want for a sheet like yours. If the data order is altered you have to alter the range formulas accordingly.
/*
* This function will run when the Spreadsheet is opened and,
* will add a Menu item for the noteSetter function
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Set cell note",
functionName : "noteSetter"
}];
sheet.addMenu("My Menu", entries);
};
function noteSetter() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("STATUS"); //source sheet
var sheet2 = ss.getSheetByName("FEBRUARI"); //result sheet
var noteCell = sheet2.getCurrentCell();
var lookUpValue = noteCell.getValue();
// Search through Col C in "STATUS" sheet to get the matching row
// You need to transpose the lookUpRange
var lookUpRange = sheet.getRange(2,3,sheet.getDataRange().getLastRow(),1).getValues();
lookUpRange = transpose(lookUpRange);
var index = lookUpRange[0].indexOf(lookUpValue); // Starts at 0
var row = index + 2; // One for the omitted header and one because rows start at 1
var note = sheet.getRange(row,7).getValue();
noteCell.setNote(note);
}
// You need to transpose to avoid looping through the array
function transpose(a)
{
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
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]);
}
}
I have an array pulled from a Google Sheet column using the following code. How can I distribute these values across a row inside of a different sheet? Essentially, I would like the value at decisionPoint[1] to populate cell 'B2', decisionPoint[2] to populate cell 'C2', decisionPoint[3] to populate cell 'D2', and so on. Thanks in advance for any help!
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // get the spreadsheet object
var decisionPointSheet = spreadsheet.getSheets()[2]; // set decision point sheet
var lastDecisionPoint = decisionPointSheet.getDataRange().getLastRow();
var decisionPoints = decisionPointSheet.getDataRange().getValues();
for ( var i = 1; i < lastDecisionPoint; i++){
Logger.log(decisionPoints[i][0]);
}
You may try that:
function transpose(){
var input = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Requests"); // origin sheet
var out = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("output"); // destination sheet
var data = input.getDataRange().getValues();
data.shift(); // remove first row (apparently you are not taking the title)
var output = []; // better to create your object and then push it at once - it run faster
for(var i in data){ // I prefer that than the classical var i =1;i<numCol ....
if(i<10) output.push(data[i][0]);
}
out.getRange(4, 1,1,output.length).setValues([output]); // i you want to specify the row where it need to end
// out.appendRow(output); // or you can change for that just to appen a new row
}