I have written the following Google Spreadsheet script that attempts to loop through all selected cells and then update the value so that it adds an indent, by adding =CONCAT(REPT( CHAR( 160 ), 5),"' + value[row] + '") around the value.
However I am hitting an error when processing the loop and I am unsure how the code should be modified to correct/resolve. The error I am getting is: TypeError: Cannot call method "setValue" of undefined.
Does anyone know what I should change?
var ss = SpreadsheetApp.getActiveSpreadsheet();
function indentText() {
var cells = ss.getActiveRange();
var values = cells.getValues();
row = [];
len = [];
Logger.log(values);
for (row = 0, len = values.length; row < len; row++) {
if (values[row] != '') {
cells[row].setValue('=CONCAT(REPT( CHAR( 160 ), 5),"' + value[row] + '")');
}
}
};
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Indent Text",
functionName : "indentText"
}];
sheet.addMenu("Indent Text", entries);
};
Edit: After reviewing my code I now have a working solution. I have added it here for completeness:
var ss = SpreadsheetApp.getActiveSpreadsheet();
function indentText() {
var values = ss.getActiveRange().getValues();
var newValues = new Array();
for (i = 0; i < values.length; i++) {
if (values[i][0] != '') {
newValues.push(['=CONCAT(REPT( CHAR( 160 ), 5),"' + values[i][0] + '")']);
} else {
newValues.push(['']);
}
}
ss.getActiveRange().setValues(newValues);
};
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Indent Text",
functionName : "indentText"
}];
sheet.addMenu("Indent Text", entries);
};
Of course would be interested if there is a better way to achieve this.
Related
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)
I have a program that filters and updates data from an existing sheet.
The program works as follows:
1. Find and filter out the required value
2. Enter data in [Adjustment] column then update to database in Record sheet.
I tried to try but my program doesn't seem to work.
I tried to edit the program code but when run it will affect the other columns and the [adjustment] column value is entered wrong.
This is my link program
function Searchold(){
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var shtRecords = ss. getSheetByName ("RECORD");
var shtForm = ss. getSheetByName ("TEST") ;
var records = shtRecords. getDataRange () . getValues ();
var sField = shtForm. getRange ("A3").getValue ();
var sValue = shtForm.getRange ("A6").getValue();
var sCol = records [0].lastIndexOf(sField);
var results = records.filter(function(e){return sValue == e[sCol] });
if(results.length==0){SpreadsheetApp.getUi().alert("not found values");}
else{
shtForm.getRange(9,1,results.length,results[0].length).setValues(results);
}
}
function Updatenew(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var shtRecords = ss.getSheetByName("RECORD");
var shtForm = ss.getSheetByName("TEST");
var LastRow = shtForm.getRange("A8").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow();
var newData = shtForm.getRange(9,1,LastRow -1,7).getValues();
for(var i =0; i<newData.length;i++){
var oldData= shtRecords.getDataRange().getValues();
for(var j= 0;j<oldData.length;j++){
if(newData[i][0] ==oldData[j][0]){
var newData2 = [newData[i]];
shtRecords.getRange(j + 1,1,1,newData2[0].length).setValues(newData2);
}
}
}
}
Can you help me with the update program? Sincerely thank you
Modification points:
When I saw your showing script of Updatenew, I think that each row of var oldData = shtRecords.getDataRange().getValues() is used in each loop of for (var i = 0; i < newData.length; i++) {}. By this, each row is overwritten by each row of newData. By this, all searched rows in "RECORD" sheet are the same value. I thought that this might be the reason for your issue.
var oldData = shtRecords.getDataRange().getValues(); can be used one call.
In order to avoid this issue by modifying your script, as one of several methods, how about the following modification?
From:
for (var i = 0; i < newData.length; i++) {
var oldData = shtRecords.getDataRange().getValues();
for (var j = 0; j < oldData.length; j++) {
if (newData[i][0] == oldData[j][0]) {
var newData2 = [newData[i]];
shtRecords.getRange(j + 1, 1, 1, newData2[0].length).setValues(newData2);
}
}
}
To:
var oldData = shtRecords.getDataRange().getValues();
for (var j = 0; j < oldData.length; j++) {
for (var i = 0; i < newData.length; i++) {
if (newData[0][0] == oldData[j][0]) {
var newData2 = newData.splice(0, 1);
shtRecords.getRange(j + 1, 1, 1, newData2[0].length).setValues(newData2);
break;
}
}
}
Note:
At the above modification, setValues is used in a loop. In this case, the process cost becomes high. If you want to reduce the process cost of the script, how about using Sheets API? When Sheets API is used, how about the following modification? Please enable Sheets API at Advanced Google services.
To
var temp = newData.slice();
var data = shtRecords.getDataRange().getValues().reduce((ar, r, i) => {
if (temp[0][0] == r[0]) {
var t = temp.splice(0, 1);
t[0][2] = Utilities.formatDate(t[0][2], Session.getScriptTimeZone(), "dd/MM/yyyy");
t[0][4] = Utilities.formatDate(t[0][4], Session.getScriptTimeZone(), "dd/MM/yyyy");
ar.push({ range: `'RECORD'!A${i + 1}`, values: t });
}
return ar;
}, []);
Sheets.Spreadsheets.Values.batchUpdate({ data, valueInputOption: "USER_ENTERED" }, ss.getId());
I want to split the google sheet into different workbooks, not tabs in the same workbook based on values in column A. Although I have got a script that splits the data into different workbooks but the data range in it is not dynamic like the number of columns to be added into each workbook are fixed. I want them to be dynamic like till the last column of the data range. I have tried a lot to make it dynamic by adding loops but it shows The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 12. this error. The data in the log has almost no difference for the fixed range (which is working fine) and for the dynamic range that I have tried to it But don't know why it is showing error. Have got stuck into it. any help will be highly appreciated.
This the function that I am trying.
function splitSheets() {
var theWorkbook = SpreadsheetApp.getActiveSpreadsheet();
var theSheet = theWorkbook.getSheetByName("Master");
var slc = theSheet.getDataRange().getLastColumn()
var slcv = theSheet.getRange("B1:B" + slc).getValues()
var sheets = theWorkbook.getSheets();
for (i = 0; i < sheets.length; i++) {
switch(sheets[i].getSheetName()) {
case "Master":
break;
default:
theWorkbook.deleteSheet(sheets[i]);
}
}
var key = theSheet.getRange("A:A").getValues();
var rows = theSheet.getDataRange().getValues();
var headerFormat = theSheet.getRange("2:2").getValues();
var folderId = '16XVypjB5_PWe2PaBIREpDGCNQlZuWL4k'
var completedSheets = [];
for (var i = 2; i < key.length; i++) {
// if(completedSheets.includes('Blank') && key[i][0] === ""){
// }else{
if(!completedSheets.includes(key[i][0]) ) {
if (key[i][0] === "") {
var name = 'Blank'
var resource = {
title: name,
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{ id: folderId }]
}
var insertedFile = Drive.Files.insert(resource)
var csid = insertedFile.id
var currentSheet = SpreadsheetApp.openById(csid).getSheetByName("Sheet1")
// var currentSheet = theWorkbook.insertSheet("Blank");
} else {
var name = key[i][0]
var resource = {
title: name,
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{ id: folderId }]
}
var insertedFile = Drive.Files.insert(resource)
var csid = insertedFile.id
var currentSheet = SpreadsheetApp.openById(csid).getSheetByName("Sheet1")
// var currentSheet = theWorkbook.insertSheet(key[i][0]);
}
var theNewRows =[];
var b=0;
for(var j = 1; j < rows.length; j++) {
var rown = []
for(var c = 0; c < slcv.length; c++){
// some other trials
// if((rows[j][0] == key[i][0]) || (rows[j][0] === '' && currentSheet.getName() == "Blank")){
// theNewRows[b]=[];
// theNewRows[b].push (
// rows[j][c].toString()
// This although adds the data and range dynamically but also shows the mentioned error.
rown.push(rows[j][c])
// );
// b++;
// }
}
if((rows[j][0] == key[i][0]) || (rows[j][0] === '' && currentSheet.getName() == "Blank")){
theNewRows[b]=[];
theNewRows[b].push (
rown.toLocaleString()
// These are the fixed column for data rnage
// rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7],rows[j][8],rows[j][9],rows[j][10],rows[j][11]
);
b++;
}
Logger.log(rown)
}
Logger.log(theNewRows)
// Logger.log(theNewRows)
currentSheet.getRange("1:1").setValues(headerFormat)
var outrng = currentSheet.getRange(2,1,theNewRows.length, slc);//Make the output range the same size as the output array
outrng.setValues(theNewRows);
currentSheet.autoResizeColumns(1, slc);
if(currentSheet.getSheetName() == 'Blank') {
completedSheets.push('Blank');
last = "Blank";
}else{
completedSheets.push(key[i][0])
last = key[i][0]
// }
}
}
}
SpreadsheetApp.setActiveSheet(theWorkbook.getSheetByName('Master'));
}
I overhauled and improved your script to be more readable and use a lot less Spreadsheet calls by using array methods instead.
Script:
function splitSheets() {
var folderId = '*** FOLDER ID ***';
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheets = spreadsheet.getSheets();
var sheet = spreadsheet.getSheetByName('Master');
// delete sheets that are not named 'Master'
sheets.forEach(sheetIter => {
if(sheetIter.getSheetName() != 'Master')
spreadsheet.deleteSheet(sheetIter);
});
var data = sheet.getDataRange().getValues();
// remove 1st row (blank row)
data.shift();
// remove 2nd row from data and assign as headers
var headers = data.shift();
// get unique list of sheet names from column A
var sheetNames = data.map(row => row[0]).filter(onlyUnique);
// loop those unique sheetNames
sheetNames.map(sheetName => {
// filter data by getting only rows with same column A and sheetName
var outputData = data.filter(row => row[0] == sheetName);
// add header from data filtered
outputData.unshift(headers);
var resource = {
title: sheetName || 'Blank',
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{ id: folderId }]
}
var file = Drive.Files.insert(resource);
var currentSheet = SpreadsheetApp.openById(file.id).getSheetByName('Sheet1');
// write data filtered with the header
currentSheet.getRange(1, 1, outputData.length, outputData[0].length).setValues(outputData);
// resize the columns
currentSheet.autoResizeColumns(1, outputData[0].length);
});
}
// function to get unique values from array using filter
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
Sample Output:
I have a column which is a date in string format with this format
2020-02-23T12:14:06+0000
And i want to remove the T and replace it with space and also just completely remove the last part (+0000)
I have tried this
var A1 = CONTENT.getRange("B:B").getValue();
var A1String = A1.toString().replace("T*", "");
but it doesn't work.
Any ideas?
This is the original script in which i want to incorporate it into.
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('sheetname');
var range = sheet.getRange("A:C");
var response = UrlFetchApp.fetch("API CALL");
var dataAll = JSON.parse(response.getContentText());
var dataSet = dataAll.data;
var rows = [],
data;
for (i = 0; i < dataSet.length; i++) {
data = dataSet[i];
rows.push([new Date(),data.created_time,data.message,data.permalink_url,
data.reactions.summary.total_count
,data.comments.summary.total_count,data.insights.data[1].values[0].value,data.insights.data[2].values[0].value,data.insights.data[3].values[0].value,data.insights.data[0].values[0].value['link clicks'],data.insights.data[0].values[0].value['photo view'],data.insights.data[0].values[0].value['other clicks'],data.insights.data[0].values[0].value['video play'],data.insights.data[4].values[0].value,data.insights.data[5].values[0].value,data.insights.data[6].values[0].value,data.insights.data[7].values[0].value["like"],data.insights.data[7].values[0].value["love"],data.insights.data[7].values[0].value["wow"],data.insights.data[7].values[0].value["haha"],data.insights.data[7].values[0].value["sorry"]]); //your JSON entities here
}
Logger.log(rows)
//sheet.getRange(getlastRow() + 1, 1, rows.length, 2).setValues(rows);
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 22).setValues(rows);
/**
* Removes duplicate rows from the current sheet.
*/
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetname');
var data = sheet.getDataRange().getValues();
data.reverse(); //reverses the row order.
var last=sheet.getLastRow();
var newData = new Array();
for(i in data){
//Logger.log(i);
var row = data[i];
//Logger.log(row[5]);
var duplicate = false;
for(j in newData){
//Logger.log(newData[j][3]);
if(row[3] == newData[j][3]){
duplicate = true;
}
}
if(!duplicate){
newData.push(row);
}
}
newData.reverse(); // reverses your data back to its original order.
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
//
//
If you want to remove always the same thing (i.e. "T" and "+0000"), you could use the following script:
The result obtained: 2020-02-23 12:14:06
CODE:
// ---------- Menu ----------
// Add a Menu named Format Date to run the script
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Format Date')
.addItem('Go!', 'FormatDate')
.addToUi();
}
function FormatDate() {
var ss = SpreadsheetApp.getActiveSheet(),
array = [];
ss.getRange("B2:B") // Choose the range here
.getValues()
.forEach(function (dates) {
// "T" is replaced with a space: " " and "+0000" is replace with empty:""
[["T", " "], ["+0000", ""]]
.map(function (a, i) {
return dates = replace(dates.toString(), a[0], a[1])
})
array.push([dates])
});
// You can set a different column to write the data
// Or keep B2:B to overwrite your data
ss.getRange("B2:B")
.setValues(array)
}
function replace(d, a, r) {
return d.indexOf(a) > -1 ? d.split(a)
.join(r) : d;
}
Credit: got inspired by JPV's code to a different question long time ago
The script below does not work as expected. Can anybody help me to check if I missed anything? Gives me error TypeError: Cannot call method "getValue" of null. I run the script again and it goes through but doesn't change anything on the file.
Below are the parts of the script and how they should work:
First part is to automatically get data from the CSV Reports in Keyword Inspector. I have this "Settings" sheet where it has the password, email, and URL Links to the reports. > first part works fine.
Second part is to paste data in the "GetCSV" sheet. But first we must check if we have data in the first three columns, if there is any existing data we must move all data to the right. We paste what we get from the .csv file in "GetCSV" sheet, in Column 2, Row 2. In Column 1, row 2 we paste date and time format starting from A2 down to the last row with data:
setValue(Utilities.formatDate(new Date(), "GMT", "MM-dd HH:mm AM/PM"));
Third part, we copy the same data we updated to its final destination "Data" sheet, starting from the first empty row.
I am not very savvy with the Java script and I already have this script in place, I just need to modify it a bit based on my needs.
function getCsv(){
//populateSheetWithCSV("http://simple.keywordinspector.com/simple/download.php?id=12612", "###.######gmail.com", "Abc12345")
//;
//var settingsSheet= SpreadsheetApp.getActiveSpreadsheet().getSheetByName("settings");
var passCell = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("password");
//getRange("B3");
var emailCell = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("email");
Logger.log(emailCell)
var cp = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_512, passCell.getValue());
var sp = '';
for (i = 0; i < cp.length; i++) {
var byte = cp[i];
if (byte < 0)
byte += 256;
var byteStr = byte.toString(16);
// Ensure we have 2 chars in our byte, pad with 0
if (byteStr.length == 1) byteStr = '0'+byteStr;
sp += byteStr;
}
var payload =
{
"email" : emailCell.getValue(),
"password" : "",
"p" : sp
}
Logger.log(cp);
//return;
var options =
{
"method" : "post",
"payload" : payload,
"followRedirects" : false
};
var login = UrlFetchApp.fetch("http://simple.keywordinspector.com/simple/process_login.php" , options);
login.getContentText()
var sessionDetails = login.getAllHeaders()['Set-Cookie'];
Logger.log(sessionDetails)
var csvUrlId = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("URL_Id").getValue();
var csvUrls = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("URLS").getValues();
Logger.log(csvUrls[csvUrlId-1]);
var downloadCsv = UrlFetchApp.fetch(csvUrls[csvUrlId-1] ,//"http://simple.keywordinspector.com/simple/download.php?id=12612",
{"headers" : {"Cookie" : sessionDetails},
"method" : "post",
"payload" : payload
});
//Logger.log(downloadCsv.getContentText())
var csvContent = Utilities.parseCsv(downloadCsv.getContentText());
var sheet= SpreadsheetApp.getActiveSpreadsheet().getSheetByName("GetCSV");
var fisrtEmptyColumn
for (i=1 ; i<1024 ; (i=i+2)) {
var range = sheet.getRange(2,i,1,1);
if (range.isBlank()) {
firstEmptyColumn = i
break;
}
}
Logger.log(firstEmptyColumn);
for (i = firstEmptyColumn ; i>3 ; i=i-3){
Logger.log(i)
var rangeToCopy =sheet.getRange(1, i-3 ,sheet.getMaxRows(),3);
rangeToCopy.copyTo(sheet.getRange(1, i));
}
var cell = sheet.getRange(1,2)
var A1not = sheet.getRange(3, 2, sheet.getMaxRows()-2, 1).getA1Notation();
cell.setFormula("=COUNTA("+A1not+")");
//
for (i = firstEmptyColumn ; i>4 ; i=i-2){
for (j = 3; j < sheet.getMaxRows()-2 ; j++){
var cell = sheet.getRange(j,1);
cell.setValue(Utilities.formatDate(new Date(), "GMT", "MM-dd HH:mm AM/PM"));
sheet.getRange(2, 2, csvContent.length /* rows */, csvContent[0].length /* columns */).setValues(csvContent);
firstEmptyColumn = firstEmptyColumn +2 ;
if (firstEmptyColumn>21) {
firstEmptyColumn = 21
}
Logger.log(firstEmptyColumn);
var sourcesheet= SpreadsheetApp.getActiveSpreadsheet().getSheetByName("GetCSV");
var SourceRange = sourcesheet.getRange(3, 1, sourcesheet.getLastRow(), sourcesheet.getLastColumn());
var target = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data");;
var targetRange = target.getRange(target.getLastRow() + 1, 2);
SourceRange.copyTo(targetRange)
}
var cell = sourcesheet.getRange("A1")
for (j = target.getlastrow() +1; j < sheet.getMaxRows()-2 ; j++){
var targetRange2 = target.getRange(j,1);
cell.copyto(targetRange2)
}
}
}