Google Script adding cell name on a formula - google-apps-script

I'm new to google script, and learn a lot by searching through this site, but now I'm trying to figure out how can I add a cell name (A1, A2, .....) to a formula using google script.
Please see my sample here: https://docs.google.com/spreadsheets/d/1mttb7dD4RvfXmNt3xGe7cAR6SAXB7Tom97vNOK-YQB0/edit?usp=sharing
On column C you will see "=A16+1" but it should be like "=A2+1" since I'm on row 2
here is the google script code
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("test1");
var range = sheet.getActiveCell();
var valueToWatch = "y";
var searchRange = sheet.getRange("A1:A" + sheet.getLastRow()); // Modified
// get the values in an array
var values = searchRange.getValues();
// examine the values in the array
var i = [];
for (var y = 0; y < values.length; y++) {
if (values[y][0] == valueToWatch) {
i.push("C" + (y + 1)); // Modified
}
}
//sheet.getRangeList(i).setValue("this is a test");
var data = [];
for (var x = 0; x < values.length; x++) {
data = ['=A' + (x + 1).toString() + '&"1"'];
}
sheet.getRangeList(i).setFormula(data);
}

Upon reviewing your code, it looks like you want to add formula to column C if the same row in column A has y.
Try this code below:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("test1");
var valueToWatch = "y";
var searchRange = sheet.getRange("A1:A" + sheet.getLastRow()); // Modified
var values = searchRange.getValues();
var i = [];
for (var y = 0; y < values.length; y++) {
if(values[y][0] == valueToWatch){
i.push("C" + (y + 1));
}else{
i.push('');
}
}
var data = [];
for (var x=0; x < i.length; x++){
if(i[x] != ''){
var rowNum = i[x].replace( /^\D+/g, '');
data.push(['=A' + rowNum + '&"1"' ])
}else{
data.push(['']);
}
}
sheet.getRange("C1:C" + sheet.getLastRow()).setFormulas(data);
}
Example:
Reference:
Range.setFormulas(formulas)

Related

google apps script: get gmail jpg attachments & insert them into google sheets

The code finds all the jpg's from a sender and then creates an array with those images and then is supposed to insert the received images into the cells of the sheet.
Instead, the code inserts the word Blog into the cells instead of the images.
I've tried several methods to solve the problem but have not had any luck.
function importEmailsWithJPGs() {
var sheet = SpreadsheetApp.getActiveSheet();
var emailAddress = "a#gmail.com";
var threads = GmailApp.search("from:" + emailAddress + " filename:jpg");
var attachments;
var date;
var rowData = {};
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
attachments = messages[j].getAttachments();
date = messages[j].getDate();
var dateString = Utilities.formatDate(date, "GMT", "yyyy-MM-dd");
if (!rowData[dateString]) {
rowData[dateString] = [date];
}
for (var k = 0; k < attachments.length; k++) {
if (attachments[k].getContentType().indexOf("image/jpeg") !== -1) {
//var image = attachments[k].getAs('image/jpeg');
// var imageName = attachments[k].getName();
// var blob = new Blob([image], { type: 'image/jpeg' });
// rowData[dateString].push(blob);
//var image = attachments[k].getAs('image/jpeg');
// var imageName = attachments[k].getName();
// var byteArray = image.getBytes();
// var base64EncodedImage = Utilities.base64Encode(byteArray);
// var blob = Utilities.newBlob(base64EncodedImage, 'image/jpeg', imageName);
// rowData[dateString].push(blob);
var image = attachments[k].copyBlob();
var imageName = attachments[k].getName();
var blob = Utilities.newBlob(image.getBytes(), 'image/jpeg', imageName);
rowData[dateString].push(blob);
}
}
}
}
for (var key in rowData) {
sheet.appendRow(rowData[key]);
}
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
for (var j = 1; j < data[i].length; j++) {
var cell = sheet.getRange(i + 1, j + 1);
var value = data[i][j];
if (value && value.getBytes) {
//var image = value;
var image = value.getAs('image/jpeg');
//var imageData = new Uint8Array(image.getBytes());
var cellWidth = cell.getWidth();
var cellHeight = cell.getHeight();
var imageWidth = image.getWidth();
var imageHeight = image.getHeight();
var ratio = Math.min(cellWidth / imageWidth, cellHeight / imageHeight);
cell.setValue("");
// cell.setImageData(imageData);
cell.setImageData(image);
}
}
}
}
Modification points:
First, I think that the reason that the text of Blob is put to the cell is due to that appendRow cannot put the image blob to the cell.
After that line of var data = sheet.getDataRange().getValues();, I think that value && value.getBytes is always false. Because, value.getBytes is undefined, and also, there is no method of setImageData in Class Range at cell.setImageData(image);. And, an error occurs at value.getAs('image/jpeg') because value has no method.
Unfortunately, from your reply, I cannot understand the relationship between for (var key in rowData) { sheet.appendRow(rowData[key]); } and the script below var data = sheet.getDataRange().getValues();. But, if you want to just put the image data from the image blob to the cells instead of the text of Blob, how about the following modification?
In this modification, a Google Apps Script library is used. Because in the current stage, unfortunately, the image blob cannot be directly put into a cell. So, I created this library. In order to use the following modified script, please do the following flow.
Usage:
1. Install Google Apps Script library.
You can see how to install it at https://github.com/tanaikech/DocsServiceApp#how-to-install. (Author of this library: me)
2. Enable Drive API.
Please enable Drive API at Advanced Google services.
3. Modified script:
Please modify your script as follows.
From:
for (var key in rowData) {
sheet.appendRow(rowData[key]);
}
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
for (var j = 1; j < data[i].length; j++) {
var cell = sheet.getRange(i + 1, j + 1);
var value = data[i][j];
if (value && value.getBytes) {
//var image = value;
var image = value.getAs('image/jpeg');
//var imageData = new Uint8Array(image.getBytes());
var cellWidth = cell.getWidth();
var cellHeight = cell.getHeight();
var imageWidth = image.getWidth();
var imageHeight = image.getHeight();
var ratio = Math.min(cellWidth / imageWidth, cellHeight / imageHeight);
cell.setValue("");
// cell.setImageData(imageData);
cell.setImageData(image);
}
}
}
To:
var lastRow = sheet.getLastRow();
var v = Object.values(rowData);
var values = v.map(([a]) => [a]);
sheet.getRange(lastRow + 1, 1, values.length).setValues(values);
var obj = v.map(([, blob], i) => ({ blob, range: { row: lastRow + i + 1, column: 2 } }));
DocsServiceApp.openBySpreadsheetId(sheet.getParent().getId()).getSheetByName(sheet.getSheetName()).insertImage(obj);
When this script is run, the text value and the image data are put into the columns "A" and "B", respectively.
Reference:
DocsServiceApp (Author: me)

Find all empty cells in several columns

Is there an easy way to color the rows containing empty cells in specific columns? So far, I only came up with a solution to highlight the cells themselves, but this script also takes some time to run.
Will appreciate any advice or guidance!
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('FRs & NFRs')
var columns = ['J17:J','L17:L', 'V17:V', 'AB17:AB','AI17:AI', 'AK17:AK'];
for(var col in columns){ //loop to iterate the desired ranges
var range = sheet.getRange(columns[col]);
//range.activate();
var values = range.getValues();
var formulas = range.getFormulas();
//for each row that data is present
for(var i = 0; i < values.length; i++) { //loop to iterate the rows
for( var j = 0; j< values[i].length ; j++){ //loop to iterate the columns
var cell = range.getCell(i+1, j+1);
if ( values[i][j] == "" )
{
cell.setBackground('red');
cell.activate
}
else
{ cell.setBackground('white')
}
Use ConditionalFormatRuleBuilder instead. This will create a Conditional format rule in your Sheet.
Try this.
Code:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('FRs & NFRs');
var ranges = sheet.getRangeList(['J17:J','L17:L', 'V17:V', 'AB17:AB','AI17:AI', 'AK17:AK']);
var rule = SpreadsheetApp.newConditionalFormatRule()
.whenCellEmpty()
.setBackground('red')
.setRanges(ranges.getRanges())
.build();
var sheetRules = sheet.getConditionalFormatRules();
sheetRules.push(rule);
sheet.setConditionalFormatRules(sheetRules);
}
Output:
Conditional Formatting:
Highlighting empty cells using rangeList.setBackgroundColor(color) ​
In my code below, I collected the cell name of the empty cells and use it to create a RangeList. Then I used the RangeList to set the background to red. This reduced the Google Sheet Service calls from thousands to 11.
function columnToLetter(column)
{
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
function highlightEmptyCell(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('FRs & NFRs')
var rangeList = sheet.getRangeList(['J17:J','L17:L', 'V17:V', 'AB17:AB','AI17:AI', 'AK17:AK']);
var rangeArray = rangeList.getRanges();
var ranges = [];
rangeArray.forEach(range =>{
var data = range.getValues();
for( var i = 0; i < data.length; i++ ){
for( var j = 0; j < data[0].length; j++ ){
if(data[i][j] == ""){
var cellName = columnToLetter(range.getColumn()) + (i + 17)
ranges.push(cellName);
}
}
}
});
sheet.getRangeList(ranges).setBackground("red");
}
Reference:
Class ConditionalFormatRuleBuilder
RangeList.setBackgroundColor(color)

onEdit(e) less than 30s trigger problem require help to shorten code to make it more efficient

I have a problem where my trigger onEdit() stopped after 30seconds and i need to keep re-pasting to trigger it again. Can you take a look and guide me on how to shorten it to make it work? I saw a person writing about it on this forum link: Google sheets script, timed out just after 30ish something seconds but i was not able to relate to it. Can anybody help me? Much appreciated as i am very new to this.
My code is as per below:
function onEdit(e){
//Variables
var row = e.range.getRow();
var col = e.range.getColumn();
var IBDataEntry = "IB";
var IBDataSheet = e.source.getSheetByName(IBDataEntry);
var IBlastRow = IBDataSheet.getLastRow();
var InboundPO = "Inbound POs";
var InboundPOSheet = e.source.getSheetByName(InboundPO);
var InboundlastRow = InboundPOSheet.getLastRow();
var searchRange = InboundPOSheet.getRange(2,2,InboundlastRow,1);
var rangeValues = searchRange.getValues();
var IBDataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("IB");
//Data Entry for Date Of Approval
if(col === 22 && row > 2 && e.source.getActiveSheet().getName() === IBDataEntry){
var POList3 = IBDataSheet.getRange("V3:V").getValues();
var LastRow3 = POList3.filter(String).length + 2;
var Entries3 = LastRow3 - row + 1;
for (var x = 0; x < Entries3 ; x++){
var ApprovalPO = IBDataSheet.getRange(row + x, 22).getValue();
var ApprovalDate = IBDataSheet.getRange(row + x, 23).getValue();
if (IBDataSheet.getRange(row + x, 23).getValue() != '')
for(var j=1;j<=InboundlastRow;j++){
if(rangeValues[j] == ApprovalPO){
InboundPOSheet.getRange(j+2,11).setValue(ApprovalDate);
}
}
}
} SummarySheet.getRange(36,3).setValue(currentDate);
//Data Entry for Date Of Arranging
if(col === 22 && row > 2 && e.source.getActiveSheet().getName() === IBDataEntry){
var POList4 = IBDataSheet.getRange("V3:V").getValues();
var LastRow4 = POList4.filter(String).length + 2;
var Entries4 = LastRow4 - row + 1;
for (var x = 0; x < Entries4 ; x++){
var ArrangingPO = IBDataSheet.getRange(row + x, 22).getValue();
var ArrangingDate = IBDataSheet.getRange(row + x, 24).getValue();
if (IBDataSheet.getRange(row + x, 24).getValue() != '')
for(var j=1;j<=InboundlastRow;j++){
if(rangeValues[j] == ArrangingPO){
InboundPOSheet.getRange(j+2,12).setValue(ArrangingDate);
}
}
}
} SummarySheet.getRange(36,3).setValue(currentDate);
}
Thank you so much!

Using onEdit to bind a specific cell change value

This is my script. I need to populate the values in I2:I range when the cell value of C2 changes. I have created an array_temp but these are not getting pasted in I2. Can anybody please help me throw some light on it?
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var ss = e.getSheetByName('UserInterface');
var count = ss.getRange("H2").setFormula('=countif(TalukaName!B:B,UserInterface!C2)').getValue();
var DistrictName = ss.getRange('C2').getValue();
var matchindex = ss.getRange('H3').setFormula('=match(C2,TalukaName!B:B,0)').getValue();
var indexvalue = ss.getRange('H4').setFormula('=index(TalukaName!B:B,H3)').getValue();
var array = [] ;
ss.getRange('F2').clearcontent;
var ssTaluka= e.getSheetByName('TalukaName');
var range = ssTaluka.getDataRange();
var data = range.getValues();
for (var i = 0; i < count; i++) {
array[i]= data[i + matchindex - 1][0];
}
var array_temp = [];
for (var j = 0; j < array.length; j++) {
array_temp.push([
array[j]
])
}
ss.getRange('I2:I').clearContent();
ss.getRange('I2:I'+ (count+1)).setValues(array_temp) ;
}

Apps Script: Loop Function to Submit Active Google Sheet entries to running log sheet in same file?

Looking to loop through the following script to set values in my target sheet for all entries below cell a21 in the 'order entry template' i've created in the 'PO Template' sheet.
function submit() {
var app = SpreadsheetApp;
var activeSheet = app.getActiveSpreadsheet().getSheetByName("POTemplate");
var PONo = activeSheet.getRange("N3").getValue();
var PODate = activeSheet.getRange("N4").getValue();
var SKU = activeSheet.getRange("a22").getValue();
var SKUDesc = activeSheet.getRange("d22").getValue();
var SKUQty = activeSheet.getRange("k22").getValue();
var UtCost = activeSheet.getRange("m22").getValue();
var ExtCost = activeSheet.getRange("p22").getValue();
var target = "POHistory";
var targetSheet = app.getActiveSpreadsheet().getSheetByName(target);
targetSheet.getRange(2, 1).setValue(PONo);
targetSheet.getRange(2, 2).setValue(PODate);
targetSheet.getRange(2, 3).setValue(SKU);
targetSheet.getRange(2, 4).setValue(SKUDesc);
targetSheet.getRange(2, 5).setValue(SKUQty)
targetSheet.getRange(2, 6).setValue(UtCost);
targetSheet.getRange(2, 7).setValue(ExtCost);
}
Here you are! Need to run now, I'll add comments later:
function submit() {
var app = SpreadsheetApp;
var tplSheet = app.getActiveSpreadsheet().getSheetByName("POTemplate");
// POTemplate range size
// I prefer not having ranges in A1 notation when I'm going to iterate
var tplFRow = 22, tplLRow = tplSheet.getLastRow();
var tplRowsNum = tplLRow - tplFRow + 1;
var tplFCol = 1, tplLCol = 16;
var tplColsNum = tplLCol - tplFCol + 1;
// Get all data at once: less getValue() calls, much faster
var rangeData = tplSheet.getRange(22, 1, tplRowsNum, tplColsNum).getValues();
// Column indexes to filter (A, D, K, M, P)
var colIndexes = [0, 3, 10, 12, 15];
var fData = filterByIndexes(rangeData, colIndexes);
var target = "POHistory";
var targetSheet = app.getActiveSpreadsheet().getSheetByName(target);
// Set size of destination range in POHistory sheet
var tgtRow = targetSheet.getLastRow() + 1;
var tgtRowsNum = fData.length - tgtRow + 1;
var tgtCol = 1;
var tgtColsNum = fData[0].length - 1 + 1;
// Set all values at once
targetSheet.getRange(tgtRow, tgtCol, tgtRowsNum, tgtColsNum).setValues(fData);
}
// Function to extract only the columns you need
function filterByIndexes(twoDArr, indexArr) {
var fData = [];
// Transpose Array to get only the column needed
twoDArr = twoDArr.transpose();
for(var i=0; i<indexArr.length; i++) {
fData.push(twoDArr[indexArr[i]]);
}
// Transpose result Array
return fData.transpose();
}
// Prototype function to transpose a 2D Array
Array.prototype.transpose = function() {
var a = this,
w = a.length ? a.length : 0,
h = a[0] instanceof Array ? a[0].length : 0;
if (h === 0 || w === 0) {return [];}
var i, j, t = [];
for (i = 0; i < h; i++) {
t[i] = [];
for (j = 0; j < w; j++) {
t[i][j] = a[j][i];
}
}
return t;
};