How can I insert values into a blank sheet?
The way that I currently know of for inserting values is by retrieving the range and then inserting the values using the values property, such as
range.getRange("A1:" + cellBottomRight);
range.load("values");
context.sync().then(function () {
range.values = twoDimensionalArrayOfValues;
});
Is there a simpler way by using a single function to simply insert the values, rather than first retrieving the range?
Thanks!
EDIT:
I've been trying to create a new sheet and then insert a 2-dimensional array to it, which its values would be inserted starting from the cell A1.
So far, I managed to do the following:
let neeSheet = context.workbook.worksheets.add("New sheet");
newSheet.activate();
newSheet.getRange("A1").values = twoDimensionalArray;
context.sync();
But didn't work.
How can I get it to work?
Thanks!
You don't actually have to load the range if you just want to set the values, so you can do this:
var range = ctx.workbook.worksheets.getItem("Sheet1").getRange("A1");
range.values = [["Value"]];
return ctx.sync();
(Adding this answer in response to the new information that #avi12 added to the question above, under "EDIT")
Philip's answer above correctly shows how to insert a single value into cell A1 of a worksheet. To address the specific scenario that you've described in your (updated) question, here are some code snippets (one in TypeScript and the other in JavaScript) that show how to create a new worksheet and then add data to the worksheet, using a 2-dimensional array of data. The key thing to point out here is that I'm retrieving the range by using getResizedRange (passing in dimensions of my array), so that the size of the range matches the size of the data set that I'm inserting into it.
Note: You can quickly and easily try these snippets yourself by using Script Lab (https://aka.ms/getscriptlab). Simply install the Script Lab add-in (free), then choose "Import" in the navigation menu, and use the following GIST URL: https://gist.github.com/kbrandl/01c4faf352c34286188311c1198f6307.
TypeScript:
async function run_TS() {
try {
await Excel.run(async (context) => {
// define values that will be inserted into new sheet
let values = [["A1", "B1", "C1"], ["A2", "B2", "C2"]];
// create and activate new sheet
let sheets = context.workbook.worksheets;
let newSheet = sheets.add("New sheet TS");
newSheet.activate();
// add data to the new sheet
let range = newSheet.getRange("A1").getResizedRange(values.length - 1, values[0].length - 1);
range.values = values;
// sync
await context.sync();
console.log("Finished with run_TS function");
});
}
catch (error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
}
}
JavaScript:
function run_JS() {
Excel.run(function (context) {
// define values that will be inserted into new sheet
var values = [["A1", "B1", "C1"], ["A2", "B2", "C2"]];
// create and activate new sheet
var sheets = context.workbook.worksheets;
var newSheet = sheets.add("New sheet JS");
newSheet.activate();
// add data to the new sheet
var range = newSheet.getRange("A1").getResizedRange(values.length - 1, values[0].length - 1);
range.values = values;
// sync
return context.sync()
.then(function () {
console.log("Finished with run_JS function");
});
})
.catch(function (error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
});
}
Related
I want to copy values from one range to another sheet (in the same workbook) using Excel JavaScript, that is, taking some range values and pass them to another sheet.
The Excel Javascript API shows how to copy one range to another range in the same worksheet:
let sheet = context.workbook.worksheets.getItem("Sample");
// Copy everything from "A1:E1" into "G1" and the cells afterwards ("G1:K1").
sheet.getRange("G1").copyFrom("A1:E1");
await context.sync();
});
However I can't achieve to do it in another worksheet (of the same workbook).
This is the code that I'm using but it shows me some errors about using wrong parameters in the methods.
await Excel.run(async (context) => {
const captura = context.workbook.worksheets.getItem("Captura");
const historico = context.workbook.worksheets.getItem("Historico");
var rango = captura.getRange("A3:F5");
var i = historico.getUsedRange().getLastRow();
historico.getRange("A" + i).copyFrom(rango);
await context.sync();
});
}
I have written a code to populate data from a spreadsheet into a google doc and save it to drive using g-sript. Here is the code for the same :
function onOpen() {
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu('Invoice creator');
menu.addItem('Generate Invoice', 'invoiceGeneratorFunction');
menu.addToUi();
}
function invoiceGeneratorFunction() {
const invoiceTemplate = DriveApp.getFileById('125NPu-n77F6N8hez9w63oSzbWrtryYpRGOkKL3IbxZ8');
const destinationFolder = DriveApp.getFolderById('163_wLsNGkX4XDUiSOcQ88YOPe3vEx7ML');
const sheet_invoice = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('New Invoice Sheet');
const rows = sheet_invoice.getDataRange().getValues();
Logger.log(rows);
rows.forEach(function(row, index) {
if (index === 0) return;
if (row[12] != "") return;
const copy = invoiceTemplate.makeCopy(`${row[1]} VIN Number: ${row[2]}`,destinationFolder);
const doc = DocumentApp.openById(copy.getId());
const body = doc.getBody();
var friendlyDateBilled = new Date(row[0]).toLocaleDateString();
var friendlyDateDelivery = new Date(row[3]).toLocaleDateString();
body.replaceText('{{Date Billed}}',friendlyDateBilled);
body.replaceText('{{Customer Name}}',row[1]);
body.replaceText('{{VIN Number}}',row[2]);
body.replaceText('{{Date of Delivery}}',friendlyDateDelivery);
body.replaceText('{{Package}}',rows[4]);
body.replaceText('{{Price}}',rows[5]);
body.replaceText('{{Output CGST}}',rows[6]);
body.replaceText('{{Output SGST}}',rows[7]);
body.replaceText('{{Discount}}',rows[8]);
body.replaceText('{{Total Price}}',rows[9]);
body.replaceText('{{Balance}}',rows[10]);
body.replaceText('{{Remarks}}',rows[11]);
doc.saveAndClose();
const url = doc.getUrl();
sheet_invoice.getRange(index+1, 13).setValue(url);
})
}
I have created a menu button for the script to run. But when i run it I get an error saying :
Exception: Invalid argument: replacement
at unknown function
at invoiceGeneratorFunction(Code:17:8)
(Here line 32 is body.replaceText('{{Package}}',rows[4]);
and line 17 is the start of forEach)
Interestingly when I comment out the rest of body.replaceText lines after that line, the code works. I can't understand what the problem is, if it's working if I comment out the lines.
In your script, rows is 2 dimensional array retrieved with sheet_invoice.getDataRange().getValues(). When I saw your loop, after the line of body.replaceText('{{Package}}',rows[4]);, rows is used. In this case, rows[4] is 1-dimensional array. It is required to be the string for the arguments of replaceText(searchPattern, replacement). I think that this might be the reason for your issue. In order to remove this issue, how about the following modification?
From:
body.replaceText('{{Package}}',rows[4]);
body.replaceText('{{Price}}',rows[5]);
body.replaceText('{{Output CGST}}',rows[6]);
body.replaceText('{{Output SGST}}',rows[7]);
body.replaceText('{{Discount}}',rows[8]);
body.replaceText('{{Total Price}}',rows[9]);
body.replaceText('{{Balance}}',rows[10]);
body.replaceText('{{Remarks}}',rows[11]);
To:
body.replaceText('{{Package}}',row[4]);
body.replaceText('{{Price}}',row[5]);
body.replaceText('{{Output CGST}}',row[6]);
body.replaceText('{{Output SGST}}',row[7]);
body.replaceText('{{Discount}}',row[8]);
body.replaceText('{{Total Price}}',row[9]);
body.replaceText('{{Balance}}',row[10]);
body.replaceText('{{Remarks}}',row[11]);
Note:
I'm not sure about your actual values of rows. So I'm not sure whether the values of row[4] to row[11] are what you want. If those values are not the values you expect, please check your Spreadsheet again.
Reference:
replaceText(searchPattern, replacement)
Building a script in google apps script.
I get values from an invoice data sheet with multiple lines per invoice so as to account for line items.
My progress so far has been to extract individual invoice numbers from the column (each invoice number occurs as many line items the individual invoice has).
The array todaysInvoices looks like this: [35033817, 35033818, 35033819, 35033820, 35033821]
Now, I need a way to create an object for each of these invoice numbers that has different properties (such as invoiceDate and customerName etc.). The initial invoice number as in the array should thereby be assigned as 'id' property to the new invoice object.
I need help to use objects in javascript.
If you require additional information, please let me know.
Below is a screenshot of a simplified version of my order sheet:
This is a clipping of my order sheet. Before and after the shown columns there are many more with more details but the hierarchies of information are already in the image
Below is the code I have so far:
const orderSheet = SpreadsheetApp.openById('SPREADSHEETID').getSheetByName('SHEETNAME');
const invoiceTemplate = DriveApp.getFileById('DOCUMENTID');
const tempFolder = DriveApp.getFolderById('FOLDERID');
const invoiceData = orderSheet.getRange(4,7, orderSheet.getLastRow() - 1, 57).getDisplayValues().filter(function (rows){ return rows[0] === 'INVOICED'});
const invDataRepo = SpreadsheetApp.openById('SPREADSHEETID2');
var timestamp = new Date();
function printBulkInvoices() {
logLineItems ();
var todaysInvoices = uniqueInvIDs ();
todaysInvoices.sort();
todaysInvoices.map(String);
//fetchInvData (todaysInvoices);
Logger.log (todaysInvoices)
}
function fetchInvData (invoiceIDs) {
let invoices = {
}
Logger.log(invoices)
invoiceIDs.forEach
}
function fetchLineItems (invoiceDataArray) {
}
// send array of todays unique invoice numbers (later all inv data?) to invdata sheet and log them
function logTodaysInvoices (invIDArr){
invIDArr.forEach
invDataRepo.getSheetByName('invdata').getRange(invDataRepo.getSheetByName('invdata').getLastRow()+1,1,invIDArr.length,1).setValue(invIDArr);
}
// return an array of unique invoice ids from todays invoice data
function uniqueInvIDs (){
let singleArray = invoiceData.map(row => row[5]);
let unique = [...new Set(singleArray)];
return unique;
}
//log incoicedata to invdatarepo-sheet 'lineitems'
function logLineItems (){
invDataRepo.getSheetByName('lineitems').getRange(invDataRepo.getSheetByName('lineitems').getLastRow()+1,2,invoiceData.length,invoiceData[0].length).setValues(invoiceData);
}
It's hard to say exactly what you need since we cannot see your Invoice Data Sheet.
But here's something that might give you a start:
let iobj = {idA:[]};
[35033817, 35033818, 35033819, 35033820, 35033821].forEach((id => {
if(!iobj.hasOwnProperty(id)) {
iobj[id]={date: invoiceDate, name: customName, items:[]};
iobj.idA.push(id);//I find it handy to have an array of object properties to loop through when I wish to reorganize the data after it's all collected
} else {
iobj[id].items.push({item info properties});//I am guessing here that you may wish to addition additional information about the items which are on the current invoice
}
});
Javascript Object
To follow up from your question:
Your loop to collect object data would start to look something like this:
function getInvoiceData() {
const ss = SpreadsheetApp.getActive();
const ish = ss.getSheetByName('Invoice Data');
const isr = 2;
const hA = ish.getRange(1, 1, 1, ish.getLastColumn()).getValues()[0];
let idx = {};//object return head index into row array based on header title which in this case I assume invoice number is labeled 'Invoicenumber'
hA.forEach((h, i) => {idx[h] = i});
const vs = ish.getRange(isr, 1, ish.getLastRow() - isr + 1, ish.getLastColumn()).getValues();
let iobj = { idA: [] };
vs.forEach(r => {
if (!iobj.hasOwnProperty(r[idx['invoicenumber']])) {
iobj[r[idx['invoicenumber']]] = { date: r[idx['invoicedate']], name: r[idx['customername']], items: [] };
iobj.idA.push(r[idx['invoicenumber']]);
} else {
iobj[r[idx['invoicenumber']]].items.push({ iteminfoproperties:'' });
}
});
}
Continuing from Google Apps Script to extract data from Gmail and fill in matching row in Google Sheets , there is another email which contains multiple tracking numbers in a single email. Example...
Your order is ready to be redeemed/ delivered.
Order No. 91401111
Tracking No. (Actual Weight/Chargeable Weight) JK5SD8F4M6 (2.1lb)
J6HDO9L665 (2.1lb)
J3SDG76435 (9.8lb)
Courier UPS
Shipment No. 23879924905
I would like to extract the data in the email and fill in the correct cells such as this...
Currently, the script is like this...
function extractDetails(message){
var emailData = {
body: "Null",
trackingno: "Null",
weight: "Null",
orderno: "Null",
courier: "Null",
shipmentno: "Null"
}
emailData.body = message.getPlainBody();
emailData.trackingno = emailData.body.match(/(?<=Tracking No. \(Actual Weight/Chargeable Weight\) ).*/).toString().trim();
emailData.weight = emailData.body.match(/????????/).toString().trim();
emailData.orderno = emailData.body.match(/(?<=Order No. ).*/).toString().trim();
emailData.courier = emailData.body.match(/(?<=Courier ).*/).toString().trim();
emailData.shipmentno = emailData.body.match(/(?<=Shipment No. ).*/).toString().trim();
var activeSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = activeSheet.getSheetByName('Sheet1');
var range = sheet.getRange("A2:A" + sheet.getLastRow()).createTextFinder(emailData.trackingno).findNext();
if (range) {
range.offset(0, 3).setValue(emailData.weight);
range.offset(0, 4).setValue(emailData.orderno);
range.offset(0, 5).setValue(emailData.courier);
range.offset(0, 6).setValue(emailData.shipmentno);
} else {
sheet.appendRow([emailData.trackingno, '', '', emailData.weight, emailData.orderno, emailData.courier, emailData.shipmentno]);
}
}
I know there are few errors in the above script. First, I have no idea how to write the regex to find the weight. Then, I don't know how to extract all tracking numbers. I should probably store the extracted the tracking numbers in an array and then do the matching using for loop. Please help. Thanks.
I believe your goal is as follows.
You want to retrieve the values of Order No, Courier, Shipment No, Parcel Weight, and Tracking No from the following text.
Your order is ready to be redeemed/ delivered.
Order No. 91401111
Tracking No. (Actual Weight/Chargeable Weight) JK5SD8F4M6 (2.1lb)
J6HDO9L665 (2.1lb)
J3SDG76435 (9.8lb)
Courier UPS
Shipment No. 23879924905
You want to put the values to the Spreadsheet by searching the tracking No.
You want to achieve this using Google Apps Script.
In this case, how about the following sample script? In this case, I used your sample text for testing the script.
Sample script:
I think that in your script, text of my sample script is the same as emailData.body.
function myFunction(){
// This text is from your question.
const text = `Your order is ready to be redeemed/ delivered.
Order No. 91401111
Tracking No. (Actual Weight/Chargeable Weight) JK5SD8F4M6 (2.1lb)
J6HDO9L665 (2.1lb)
J3SDG76435 (9.8lb)
Courier UPS
Shipment No. 23879924905`;
// 1. Retrieve each value you want to retrieve.
const obj1 = text.split("\n").reduce((o, e) => {
const regex = new RegExp("([A-Z0-9]+) \\(([0-9.]+)lb\\)");
if (e.includes("Order")) {
o.orderNo = Number(e.trim().split(" ").pop());
} else if (e.includes("Courier")) {
const t = e.trim().split(" "); // Modified
t.shift(); // Modified
o.courier = t.join(" "); // Modified
} else if (e.includes("Shipment")) {
o.shipmentNo = Number(e.trim().split(" ").pop());
} else if (regex.test(e)) {
const [, trackingNo, parcelNo] = e.match(regex);
o.trackingNo.push({trackingNo: trackingNo, parcelNo: parcelNo});
}
return o;
}, {orderNo: "", courier: "", shipmentNo: "", trackingNo: []});
// 2. Create an object for searching tracking No.
const obj2 = obj1.trackingNo.reduce((o, {trackingNo, parcelNo}) => Object.assign(o, {[trackingNo]: [parcelNo, obj1.orderNo, obj1.courier, obj1.shipmentNo]}), {});
// 3. Retrieve existing values from Spreadsheet and creating new values for putting to Spreadsheet.
var activeSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = activeSheet.getSheetByName('Sheet1');
var range = sheet.getRange("A2:G" + sheet.getLastRow());
var newValues = range.getValues().map(([a, b, c, ...efg]) => { // Modified
var temp = [];
if (obj2[a]) {
temp = [a, b, c, ...obj2[a]];
delete obj2[a];
} else {
temp = [a, b, c, ...efg]; // Modified
}
return temp;
});
// 4. If the tracking No is not found, the values are appended to the last row.
var tempAr = Object.entries(obj2);
if (tempAr.length > 0) {
newValues = newValues.concat(tempAr.map(([k, v]) => [k, "", "", ...v]));
}
// 5. Clear sheet and put the new values to the sheet.
range.clearContent();
sheet.getRange(2, 1, newValues.length, newValues[0].length).setValues(newValues);
}
Note:
In this sample script, when your text is different from the text in your question, the script might not be able to be used. So please be careful about this.
References:
reduce()
map()
I have two sheets. Test Data has 3-4k entries of many columns of data and Order Changes has no data at all. I would like to search two specific columns on Test Data, a column of names and a column of yes or no. If column two of Test Data contains a 'yes' in the cell then the name of that person would be placed into a cell on order changes.
This is what I have so far:
function isThreshold(){
var data = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test Data");
var cdata = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Order Changes");
var lc = data.getLastColumn();
var lookUp = data.getRange(1,6,3,2).getValues();
lookUp.forEach(var info in lookUp){
}
Logger.log(lookUp);
}
I probably shouldn't loop through that many entries but I don't know of any other way. Should I combine the forEach loop with an if loop to get the desired result or use some other method?
I believe your goal as follows.
You want to retrieve the values from the cells "F1:G" of sheet "Test Data".
You want to search yes from the column "G" and when the column "G" is yes, you want to put the value of the column "F" to the sheet "Order Changes".
Modification points:
SpreadsheetApp.getActiveSpreadsheet() can be declared one time.
In this case, you can retrieve the values from the range of "F1:G" + data.getLastRow() of "Test Data", and create the array for putting to the sheet "Order Changes", and put it.
When above points are reflected to your script, it becomes as follows.
Modified script:
function isThreshold(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getSheetByName("Test Data");
var cdata = ss.getSheetByName("Order Changes");
var valuesOfTestData = data.getRange("F1:G" + data.getLastRow()).getValues();
var valuesForOrderChanges = valuesOfTestData.reduce((ar, [f, g]) => {
if (g.toLowerCase() == "yes") ar.push([f]);
return ar;
}, []);
if (valuesForOrderChanges.length > 0) {
cdata.getRange(1, 1, valuesForOrderChanges.length, valuesForOrderChanges[0].length).setValues(valuesForOrderChanges);
// or cdata.getRange(cdata.getLastRow() + 1, 1, valuesForOrderChanges.length, valuesForOrderChanges[0].length).setValues(valuesForOrderChanges);
}
}
In this modified script, from your question, it supposes that the columns "F" and "G" are the value of name and yes or no.
References:
getRange(a1Notation) of Class Sheet
reduce()