Google App Script - Insert Data Into Next Column - javascript

This script fetches the data from the sheet and insert it into a new sheet. I want the second function to insert into the third row each time.
I want the result to be -
Timestamp | Impressions | CTR
function AggregateData() {
Impressions();
CTR();
}
function Impressions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Metrics");
var source = sheet.getRange("G16:H16");
var values = source.getValues();
var sheet = ss.getSheetByName("Aggregate");
values[0][0] = new Date();
sheet.appendRow(values[0]);
};
function CTR() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Metrics");
var source = sheet.getRange("F16:G16");
var values = source.getValues();
var sheet = ss.getSheetByName("Aggregate");
values[0][0] = new Date();
sheet.appendRow(values[0]);
};
This code appends the second function in the second column itself below the result of the first function.

This code will copy your data to a new sheet in the order you want. However, I have reduced it to one function. The reason your code puts the new data in a new row is this line:
Sheet.appendRow(data)
puts the data you supply to a new row which is empty. That is also the reason why i have combined the two functions into one.
function AggregateData() {
Impressions();
}
function Impressions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Metrics");
var source = sheet.getRange("F16:H16");
var values = source.getValues();
var pasteValues = [] // create new array which will hold the data you need to be pasted into the aggregate Sheet
pasteValues[0] = [] // Adding a second dimesion to the array
var sheet = ss.getSheetByName("Aggregate");
// below 3 lines does the switch of data and adds the time stamp
pasteValues[0][0] = new Date();
pasteValues[0][1] = values[0][2] //Copy the col h (impressions value) value into the new array
pasteValues[0][2] = values[0][1] //Copy the col G (impressions value) value into the new array
sheet.appendRow(pasteValues[0]); //Append the new array into the sheet
};

Related

Google Apps Script: Replace all text in slide table with values and formatting from sheets

Here is the description of my problem.
I have a range of placeholder text and its associated values in a spreadsheet. The placeholder text also exists in a slide presentation which gets replaced using the replacealltext function. However, the colors in the spreadsheet for the values do not change. Please see the examples below.
Google Apps Script:
// Google Sheets
var masterSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = masterSheet.getSheetByName('Monthly Report'); //gets the data from the active pubfile
var range = sheet.getRange('S1:T110');
var data = range.getValues();
var titleName = sheet.getRange('AA14:AA14').getValues().toString();
data.shift(); //removes the headers in the sheets
// Creating the new slide
var spreadsheetID = SpreadsheetApp.getActiveSpreadsheet().getId(); //Ensure Code is applied to active Pubfile
var spreadsheetFolder = DriveApp.getFileById(spreadsheetID);
var parentFolder = spreadsheetFolder.getParents();
var folderID = parentFolder.next().getId();
var reportTemplate = DriveApp.getFileById('SLIDE ID'); // Gets the report Template
var copiedTemplate = reportTemplate.makeCopy(titleName, DriveApp.getFolderById(folderID)); //Makes a copy of the orginal and saves it in the specified folder
var newPresoID = copiedTemplate.getId();
var skeleton = SlidesApp.openById(newPresoID); //opens the new template presentation
var slides = skeleton.getSlides(); //calls the new slides
return newSlide1();
function newSlide1() {
var slide1new = slides[0]; // defining the location of the new slide 1
data.forEach(function (row) {
var templateVariable = row[0]; // First column contains variable names
var templateValue = row[1]; // Second column contains values
slide1new.replaceAllText(templateVariable, templateValue); //replaces all the text that matches the placeholders
slide1new.
});
As you can see, this code just replaces the value but does not bring in the source formatting.
Here are snapshots of the original spreadsheet data and the slides:
Source Data
Destination Slide with Placeholders
Current Result
Desired Result
Please suggest a way to fix this issue. Thank you!
Here is an example of applying the colors of a spreadsheet cell to the table cells of a slide.
My spreadsheet looks like this.
My slide looks like this.
Code.gs
function myFunction() {
try {
let spread = SpreadsheetApp.openById("xxxxxxxxxxxxxxxxxxxxxxxxxxx");
let sheet = spread.getSheetByName("Sheet1");
let range = sheet.getRange(2,1,sheet.getLastRow()-1,2);
let values = range.getDisplayValues();
let colors = range.getFontColors();
let present = SlidesApp.getActivePresentation();
let slide = present.getSlides()[0];
let table = slide.getTables()[0];
for( let i=0; i<table.getNumRows(); i++ ) {
let row = table.getRow(i);
for( let j=1; j<row.getNumCells(); j++ ) {
let text = row.getCell(j).getText();
values.some( (value,k) => {
let l = text.replaceAllText(value[0],value[1]);
if( l > 0 ) {
text.getTextStyle().setForegroundColor(colors[k][1]);
return true;
}
return false;
}
);
}
}
}
catch(err) {
console.log(err);
}
}
And the final results look like this.
Reference
TableCell
Array.some()

Trying to mark startDate and endDate from spreadsheet1 to spreadsheet2

I have spreadsheet1 with all the details as in this image(Spreadsheet1), there are columns with startDate and endDate with some dates. Now i have a different spreadsheet2 like in this image (spreadsheet2) with header row of all the dates in the year (from 01/01/2021 to 31/12/2021). Now startDate and endDate from spreadsheet1 should match the header in spreadsheet2 and put the values of the column Type from spreadsheet1 to the respective cells in spreadsheet2 (like it is present in spreadsheet2 image for reference). Below is the code i'm working with but i'm not reaching my goal. Please help me i'm new to coding world. Thank you.
function myFunction() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getActiveSheet();
let last_row = sheet.getLastRow();
let data = sheet.getRange("A2:E"+last_row).getValues();
let start_date = [];
let end_date = [];
let dates_between = [];
let id = [];
let name = [];
let message = [];
let dd = SpreadsheetApp.openById('1z5WB1sACp1zvgfyXDbAmYxklSZOMIC8kNi_3Yci-PkM');
let dsheet = dd.getActiveSheet();
let dlast_row = dsheet.getLastRow();
let ddata = dsheet.getRange('C2:NC'+dlast_row).getValues();
let did = dsheet.getRange('A2:A'+last_row);
for(let i = 0; i<data.length;i++){
// let id = data[i][0];
id.push(data[i][0]);
name.push(data[i][1]);
start_date.push(data[i][2]);
end_date.push(data[i][3]);
message.push(data[i][4]);
dates_between.push(DATES_BETWEEN(start_date[i], end_date[i]));
}
did.setValue(id);
}
function DATES_BETWEEN(dateFrom, dateTo) {
var t = dateFrom.getTime(),
tMax = dateTo.getTime(),
values = [];
while (t <= tMax) {
values.push(new Date(t));
t += 24000 * 3600;
}
return values;
}
If you're able to put your 'types' on the row at start date and at end date you can fill the gap in-between with Array.fill() method.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
All you need is to get the row as an array and to put it back on the sheet. You don't even need to calculate dates in the gap. You just fill all these empty elements between filled start and end cells.
Here is your row/array: ['','','x','','','x','','']
Start cell is array.indexOf('x')
End cell is array.lastIndexOf('x')
To fill the gap with 'x' strings use array.fill('x', start, end)
You will get: ['','','x','x','x','x','','']
Below is my solution that doesn't use Dates. If your dates have the same format on both sheets and if your destination sheet always has the dates of the rows of your source sheet you can consider them as strings, and use them as keys of an object (a map in my case):
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var src_sheet = ss.getSheetByName('Sheet1');
var dest_sheet = ss.getSheetByName('Sheet2');
// get dates from first row of destination sheet
var dates = dest_sheet.getDataRange().getDisplayValues()[0].slice(2);
// get rows (without first row) from source sheet
var rows = src_sheet.getDataRange().getDisplayValues().slice(1);
// loop through the rows and get the table
var table = rows.map(row => {
// get variables from the row
var [id, name, type, start, end] = row.slice(0, 5);
// create empty Map with dates-keys (date1:'', date2:'', ...)
var dates_map = new Map(dates.map(date => [date, '']));
// assign 'type' to key['start date'] and to key['end date']
dates_map.set(start, type).set(end, type);
// create array (row) from values of the Map
var row_array = Array.from(dates_map.values());
// fill empty elements of the array between first and last 'type'
row_array.fill(type, row_array.indexOf(type), row_array.lastIndexOf(type));
// return row
return [id, name, ...row_array];
});
// set the table on the destination sheet
dest_sheet.getRange(2, 1, table.length, table[0].length).setValues(table);
}
The same code without comments:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var src_sheet = ss.getSheetByName('Sheet1');
var dest_sheet = ss.getSheetByName('Sheet2');
var dates = dest_sheet.getDataRange().getDisplayValues()[0].slice(2);
var rows = src_sheet.getDataRange().getDisplayValues().slice(1);
var table = rows.map(row => {
var [id, name, type, start, end] = row;
var dates_map = new Map(dates.map(date => [date,'']));
dates_map.set(start, type).set(end, type);
var row_array = Array.from(dates_map.values());
row_array.fill(type, row_array.indexOf(type), row_array.lastIndexOf(type));
return [id, name, ...row_array];
});
dest_sheet.getRange(2, 1, table.length, table[0].length).setValues(table);
}
Just in case, this is a destructuring assignment:
var [id, name, type, start, end] = row;
It means:
var id = row[0];
var name = row[1];
var type = row[2];
var start = row[3];
var end = row[4];
Here is the link to my dummy spreadsheet.

How To Add Sheets Based on Cell Values?

I want to create a new worksheet each time I have a new user details in column 1 of my USERS sheet. Here is the code I have so far:
// Get the data from the sheet called CreateSheets
var sheetNames = SpreadsheetApp.getActive().getSheetByName("USERS").getDataRange().getValues();
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("USERS");
var data = ss.getDataRange().getValues();
var lr = ss.getLastRow();
var dataRange = ss.getRange(1, 1, lr, 1);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
// For each row in the sheet, insert a new sheet and rename it.
sheetNames.forEach(function(row) {
var sheetName = data;
var sheet = SpreadsheetApp.getActive().insertSheet();
sheet.setName(sheetName);
});
}}
The code works but it is combining the data in the cells in column 1 into the name of the new spreadsheet. Thanks
function myfunc() {
const ss = SpreadsheetApp.getActive();
const ush = ss.getSheetByName("USERS");
const names = ush.getRange(1, 1, ush.getLastRow(), 1).getValues().flat();
const enames = ss.getSheets().map(s => s.getName());
names.forEach(n => {
if (~e.names.indexOf(n)) {
ss.insertSheet().setName(n);
enames.push(n); //add name to array to avoid duplicate names in column
}
});
}
Updated to account for existing sheet names and potential duplicate names in column 1.
I think this should do what you want. You should probably build in some sort of check to ensure the sheet doesn't already exist.
function makeSheetHappen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var wsUser = ss.getSheetByName("USERS");//the sheet with users
//this gets all values in column 1 to end of spreadsheet (it might include blanks)
//flat function avoids having to pull 2-dim array (h/t COOPER!)
var sheetNames = wsUser.getRange(1, 1, wsUser.getLastRow(), 1).getValues().flat();
//mapping function to get an array of the spreadsheet's sheet names.
var theExistingNames = ss.getSheets().map(function (aSheet) {
return aSheet.getName();
});
//loops through the sheetNames and ensures not blank and not currently existing.
sheetNames.forEach(function (aName) {
if (aName != '' && !theExistingNames.includes(aName)) {
var newSheet = ss.insertSheet();
newSheet.setName(aName);
theExistingNames.push(aName); //add name to array to avoid duplicate names in column
}
});
}

Auto Move Data of Specific Date

Link of My sheet is :
https://docs.google.com/spreadsheets/d/1czJbRU5ELNft1IfGq1cABGe30j8BWjnffVCEa8A_AeY/edit?usp=sharing
I am trying to move data if N is equal to today. I have set the trigger. This script runs on time driven between 8 PM to 9 PM. It copies the data in Row 8 when column K onwards there is noting mentioned. In the current Payment Approval Sheet, while running the script it copies the data in 1500th row.
The script I am using is as below:
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Complete Invoice Sheet'); //source sheet
var testrange = sheet.getRange('N:N');
var testvalue = (testrange.setNumberFormat("#").getValues());
var ds = ss.getSheetByName('Payment Approval Sheet'); //destination sheet
var data = [];
var j =[];
var dt = new Date();
var today = Utilities.formatDate(new Date(), 'GMT-0', 'dd/MM/yyyy')
//Condition to check in N:N, if true, copy the same row to data array
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] == today) {
data.push.apply(data,sheet.getRange(i+1,1,1,13).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
ds.getRange(ds.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
Issue:
Your current solution considers the last row of your destination
sheet Payment Approval Sheet. However, in that sheet, checkboxes
are populated in column N until the bottom of the sheet. Therefore,
getLastRow() returns the row at the bottom of column N which is not
what you want.
Explanation:
Instead of using getLastRow(), calculate the number of elements after cell A7 by using the filter() operation and then use this as a starting point when you copy & paste the data to the destination sheet:
var start_row=ds.getRange('A8:A').getValues().filter(String).length +7; //calculate max row
ds.getRange(start_row+1,1,data.length,data[0].length).setValues(data);
Solution:
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Complete Invoice Sheet'); //source sheet
var testrange = sheet.getRange('K:K');
var testvalue = (testrange.setNumberFormat("#").getValues());
Logger.log(testvalue);
var ds = ss.getSheetByName('Payment Approval Sheet'); //destination sheet
var data = [];
var j =[];
var dt = new Date();
var today = Utilities.formatDate(new Date(), 'GMT-0', 'dd/MM/yyyy')
//Condition to check in N:N, if true, copy the same row to data array
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] == today) {
data.push.apply(data,sheet.getRange(i+1,1,1,13).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
var start_row=ds.getRange('A8:A').getValues().filter(String).length +7; //calculate max row
ds.getRange(start_row+1,1,data.length,data[0].length).setValues(data);
}

drive.properties for loop with google sheets

I have two functions in a google sheet that are meant to loop through a single column containing the file IDs of files in google drive, issuing a Properties.get to retrieve a single property "LastReview" for each document and paste all of the LastReview times in the next available column.
I'm having trouble getting the loop in "loopForMetadata" to work. I want it to acquire a list of all the LastReview times associated with each fileID and then post that to the next available column so that all of the LastReview times align with the fileIDs.
function getProperty(fileId) {
var propertyKey = 'LastReview'
var fileId = '1UaQkJU8r1kE9sxpFg6OD8aOuUCoRnSpB9Agg_R9HJ3s'
var response = JSON.stringify(Drive.Properties.get(fileId, 'LastReview', { visibility: 'PUBLIC' }).value);
var key = "value";
var resposeNoQuote = response.replace(/\"/g, "")
Logger.log(resposeNoQuote);
}
function loopForMetadata() {
var columnNeeded, data, lastColumn, sh;
sh = SpreadsheetApp.getActiveSheet();
lastColumn = sh.getLastColumn();
data = sh.getRange(1, 1, 1, lastColumn).getValues();//Get 2D array of all values in row one
data = data[0];//Get the first and only inner array
columnNeeded = data.indexOf('ID') + 1;//Arrays are zero indexed- add 1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(2, columnNeeded, lastRow - 1, 1);
// Get array of values in the search Range
var rangeValues = searchRange.getValues();
// Loop through array and if condition met, add relevant
// background color.
var resultValues = []
for (i = 0; i < rangeValues.length; i++) {
resultValues.push(getProperty(rangeValues[i]));
Utilities.sleep(10);
}
Logger.log(resultValues);
};
I believe your goal as situation as follows.
You want to retrieve the values using the key of LastReview in the property from the files of fileId.
You want to put the retrieved values to the same row of fileId in the next available column.
You want to achieve this using Google Apps Script.
Modification point:
In your script,
getProperty() doesn't return the values.
resultValues is not put to the Spreadsheet.
When you want to retrieve the value of the key LastReview, Drive.Properties.get(fileId, 'LastReview', { visibility: 'PUBLIC' }).value directly returns the value.
As an important point, when the file of fileId has not property of the key LastReview, it seems that Drive.Properties.get() occurs an error. So in this modification, as a simple workaround, I used the try catch.
When above points are reflected to your script, it becomes as follows.
Sample script:
function loopForMetadata() {
var columnNeeded, data, lastColumn, sh;
sh = SpreadsheetApp.getActiveSheet();
lastColumn = sh.getLastColumn();
data = sh.getRange(1, 1, 1, lastColumn).getValues();//Get 2D array of all values in row one
data = data[0];//Get the first and only inner array
columnNeeded = data.indexOf('ID') + 1;//Arrays are zero indexed- add 1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(2, columnNeeded, lastRow - 1, 1);
var rangeValues = searchRange.getValues();
var resultValues = []
// I modified below script.
for (i = 0; i < rangeValues.length; i++) {
var fileId = rangeValues[i];
var value = "";
try {
value = Drive.Properties.get(fileId, 'LastReview', { visibility: 'PUBLIC' }).value;
} catch(e) {}
resultValues.push([value]);
// Utilities.sleep(10); // I'm not sure whether this is required.
}
sheet.getRange(2, lastColumn + 1, resultValues.length, 1).setValues(resultValues);
Logger.log(resultValues);
};
Note:
Please confirm whether Drive API is enabled at Advanced Google services, again.
Reference:
Properties: get

Categories