I am working on a slide that would take dynamic data from Google sheet.
I want to keep the slide template
Update the slide values in real-time
I want to use Google app scripts to connect the data from the sheet to the slide. I am new to Java Scripts and following a tutorial online to achieve this but with no luck.
My 2 files are set up as follows
and the slides I am working on can be found here
A copy of the data can also be found here
The tutorial I am following is found in this link
Below is the code I have implemented but the problem is it does not work and tries to create multiple pages and repeat same value on each page. I only want one page with the values updated from the sheet
Your help would be grately appareciated. Thank you
function generateLandingPagesReport() {
var dataSpreadsheetUrl = "https://docs.google.com/spreadsheets/d/1UccsFtqKKsXhlus4-02dXfJP0ECcCsBUmLNZajJnS_4/edit"; //make sure this includes the '/edit at the end
var ss = SpreadsheetApp.openByUrl(dataSpreadsheetUrl);
var deck = SlidesApp.getActivePresentation();
var sheet = ss.getSheetByName('metrics'); // sheet name
var values = sheet.getRange('C4:L12').getValues(); // range for values
var slides = deck.getSlides();
var templateSlide = slides[0];
var presLength = slides.length;
values.forEach(function(page){
if(page[0]){
var Current = page[2];
var Target = page[3];
var Emea = page[5];
var Depac = page[7];
var Emma = page[9];
var Comment = page[11];
templateSlide.duplicate(); //duplicate the template page
slides = deck.getSlides(); //update the slides array for indexes and length
newSlide = slides[2]; // declare the new page to update
var shapes = (newSlide.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{Current}}',Current);
shape.getText().replaceAllText('{{Target}}',Target);
shape.getText().replaceAllText('{{Emea}}',Emea);
shape.getText().replaceAllText('{{Depac}}',Depac)
shape.getText().replaceAllText('{{Emma}}',Emma);
shape.getText().replaceAllText('{{Comment}}',Comment);
});
presLength = slides.length;
newSlide.move(presLength);
} // end our conditional statement
}); //close our loop of values
//Remove the template slide
templateSlide.remove();
}
I believe your goal as follows.
You want to convert the table from Google Spreadsheet to Google Slides.
As the sample situation, you want to achieve as follows. This is from your question.
When I saw your sample situation, I can confirm that there are 2 values of Samuel Tuffuor in Google Slides. From this situation, you want to put the values to the Google Slides using the row titles of METRIC.
Modification points:
In your current script,
duplicate() is used in the loop. By this, new slide is inserted every loop. I think that this is one of several reasons of your issue.
At 1st loop of values.forEach(), all values are replaced. Because in the template of your Google Slides, {{current}}, {{Target}}, {{Emea}}, {{Depac}}, {{Emma}}and{{Comment}}of each row is replaced by eachreplaceAllText`.
In this case, it is required to distinguish {{current}}, {{Target}}, {{Emea}}, {{Depac}}, {{Emma}}and{{Comment}}` of each row.
In order to distinguish the values of each row of template of Google Slides, I would like to propose to group each row.
Usage:
1. Grouping each row of template of Google Slides.
Please group each row of template of Google Slides as follows. The red dotted line is the groups. In your sample Google Slides, 9 groups are created. Using these groups, the values retrieved from Google Spreadsheet are replaced with the placeholders of each group.
2. Sample script.
In order to replace the values retrieved from Google Spreadsheet with the place holders of each row of Google Slides, I modified your script as follows.
function generateLandingPagesReport() {
var dataSpreadsheetUrl = "https://docs.google.com/spreadsheets/d/1UccsFtqKKsXhlus4-02dXfJP0ECcCsBUmLNZajJnS_4/edit";
var ss = SpreadsheetApp.openByUrl(dataSpreadsheetUrl);
var deck = SlidesApp.getActivePresentation();
// 1. Retrieve values from Google Spreadsheet.
var sheet = ss.getSheetByName('metrics');
var values = sheet.getRange('A4:L12').getDisplayValues(); // or .getValues();
// 2. Create an object for using replacing the values.
var obj = values.reduce((o, [a,,c,d,,f,,h,,j,,l]) => Object.assign(o, {[a.trim()]: {"{{current}}": c, "{{Target}}": d, "{{Emea}}": f, "{{Depac}}": h, "{{Emma}}": j, "{{Comment}}": l}}), {});
// 3. Replace values for each group.
var slides = deck.getSlides();
var templateSlide = slides[0];
var groups = templateSlide.getGroups();
groups.forEach(g => {
var c = g.getChildren();
var key = "";
var r = new RegExp(/{{\w.+}}/);
for (var i = 0; i < c.length; i++) {
var t = c[i].asShape().getText().asString().trim();
if (!r.test(t)) {
key = t;
break;
}
}
// I modified below script as the additional modification.
if (obj[key]) {
c.forEach(h => {
var t = h.asShape().getText().asString().trim();
if (r.test(t)) h.asShape().getText().setText(obj[key][t]);
});
}
});
}
The flow of this modified script is as follows.
Retrieve values from Google Spreadsheet.
Create an object for using replacing the values.
Replace values for each group.
3. Result.
When the modified script is used for your sample Google Spreadsheet and the sample Google Slides with grouping each row, the following result is obtained. In this case, the 1st slide in the Google Slides is used. So templateSlide.remove(); is not required to be used.
Note:
In your script, the values are retrieved from Google Spreadsheet using getValues(). In this case, 10 % is 0.1. If you want to use 10 %, please use getDisplayValues() instead of getValues(). In above modified script, getDisplayValues() is used.
References:
replaceAllText
setText(newText)
getDisplayValues()
Added:
The reason of your current issue is due to the different row titles between Google Slides and Google Spreadsheet. There are 2 different titles in your sample Google Slides and Google Spreadsheet.
Mashal Mashal and Mashal Mashal for Google Slides and Google Spreadsheet, respectively.
Mashal Mashal is 1 space between Mashal and Mashal.
Mashal Mashal is 2 spaces between Mashal and Mashal.
Chelsea Great and Chelea Great for Google Slides and Google Spreadsheet, respectively.
Please use the same row titles for Google Slides and Google Spreadsheet. When the row title is different, I modified above script for not replacing the values. So could you please confirm it? When above modified script is used for your Google Slides and Google Spreadsheet, the rows of Mashal Mashal and Chelsea Great are not replaced.
Related
I want that Apps Script to automatically generate a new set of slides using data from a Sheets document which has rows of the different information I want inserted into a Slides template replacing the placeholder tags. I want it to do it instantly for each row inside the table with one action, so if there are 10 rows, 10 sets of Slides documents will be generated.
Everything works as it but i get an time aout error from the script because i have about 600 rows and more.
My goal is to separate the rows for processing and safe the Generated slides in an separate created folder in drive named Cerificates.
And that is the point i dont no how to do it. So i hope for your Help. Thx for your Time
And that is the point i dont no how to do it. So i hope for your Help. Thx for your Time.
This is the code for the script:
function mailMergeSlidesFromSheets() {
// Load data from the spreadsheet
var dataRange = SpreadsheetApp.getActive().getDataRange();
var sheetContents = dataRange.getValues();
// Save the header in a variable called header
var header = sheetContents.shift();
// Create an array to save the data to be written back to the sheet.
// We'll use this array to save links to Google Slides.
var updatedContents = [];
// Add the header to the array that will be written back
// to the sheet.
updatedContents.push(header);
// For each row, see if the 4th column is empty.
// If it is empty, it means that a slide deck hasn't been
// created yet.
sheetContents.forEach(function(row) {
if(row[14] === "") {
// Create a Google Slides presentation using
// information from the row.
var slides = createSlidesFromRow(row);
var slidesId = slides.getId();
// Create the Google Slides' URL using its Id.
var slidesUrl = `https://docs.google.com/presentation/d/${slidesId}/edit`;
// Add this URL to the 4th column of the row and add this row
// to the updatedContents array to be written back to the sheet.
row[14] = slidesUrl;
updatedContents.push(row);
}
});
// Write the updated data back to the Google Sheets spreadsheet.
dataRange.setValues(updatedContents);
}
function createSlidesFromRow(row) {
// Create a copy of the Slides template
var deck = createCopyOfSlidesTemplate();
// Rename the deck using the firstname and lastname of the student
deck.setName(row[4] + " " + row[9] + row[3]);
// Replace template variables using the student's information.
deck.replaceAllText("{{id}}", row[0]);
deck.replaceAllText("{{tag}}", row[3]);
deck.replaceAllText("{{besetzung}}", row[4]);
deck.replaceAllText("{{beginn}}", row[5]);
deck.replaceAllText("{{ende}}", row[6]);
deck.replaceAllText("{{halle}}", row[7]);
deck.replaceAllText("{{stand}}", row[8]);
deck.replaceAllText("{{firma}}", row[2]);
deck.replaceAllText("{{veranstaltung}}", row[9]);
deck.getSlides()[0].getShapes().find(s => s.getText().asString().trim().toUpperCase() == "{{IMAGE}}").replaceWithImage(`https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=${row[12]}`);
return deck;
}
function createCopyOfSlidesTemplate() {
//
var TEMPLATE_ID = "19PKvWoDtbeVHcqm4DnWUxRx1OBO817uG3cL5Ox-dQoo";
// Create a copy of the file using DriveApp
var copy = DriveApp.getFileById(TEMPLATE_ID).makeCopy();
// Load the copy using the SlidesApp.
var slides = SlidesApp.openById(copy.getId());
return slides;
}
function onOpen() {
// Create a custom menu to make it easy to run the Mail Merge
// script from the sheet.
SpreadsheetApp.getUi().createMenu("⚙️ Create BWN by Pavlos")
.addItem("Create Slides","mailMergeSlidesFromSheets")
.addToUi();
}
Problem:
I got 06 charts in a sheet. So the script does the following:
It iterates over a list of tickers from Sheet named List.
It pastes each ticker being iterated in cell A3 of sheet template
Copies one of the charts from sheet named template
Pastes it in cell E5 of sheet List
The script below runs up to the last line and then I got the following error:
TypeError: ss.getRange(...).insertChart is not a function
Here's the script, I'm using:
function updateTickers() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("List");
var tickerRng = ss.getRange(2, 1, ss.getLastRow(), 1).getValues();
var allSharesSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template");
var startRow = 2;
for (var a = 0; a < tickerRng.length; a++) {
var ticker = tickerRng[a][0];
if (ticker == 'nndm') {
if (ticker[0] != '') {
var setRow = parseInt(a) + startRow;
allSharesSheet.getRange("a3").setValue(ticker);
var chart1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(ticker).getCharts()[0];
ss.getRange(setRow, 5).insertChart(chart1); //This is where the error pops up.
}
}
}
}
Any help is appreciated.
I believe your goal as follows.
You want to copy a chart in the sheet of ticker to the sheet "List".
You want to move the copied sheet to the cell "E5".
In your script, it seems that you want to move the copied sheet to getRange(setRow, 5). This answer follows to this.
Modification points:
The method of insertChart() is for Class Sheet. Ref But in your script, this method is used for Class Range. I think that the reason of your issue is due to this.
I have already mentioned this at my comment.
In order to move the position of chart, it is required to update the chart.
When above points are reflected to your script, it becomes as follows.
Modified script:
Please modify your script as follows.
From:
ss.getRange(setRow, 5).insertChart(chart1); //This is where the error pops up.
To:
ss.insertChart(chart1.modify().setPosition(setRow, 5, 0, 0).build());
or, you want to put the chart to the cell "E5", please use the following script.
ss.insertChart(chart1.modify().setPosition(5, 5, 0, 0).build());
References:
insertChart(chart)
modify()
Are there any way to choose some content in the Google Document Table and copy to the Google Spreadsheet by the Google App Script
Following with my photo idea
that I would like to copy some content in the red box / blue box to the Google Spreadsheet including with the data in column name : level , Due Date 1, Due Date 2
I've started with the following code outline:
function Tables() {
var doc = DocumentApp.getActiveDocument().getBody();
var tables = doc.getTables()[1];
for (var i = 0; i < tables.getNumRows(); ++i) {
var cell = tables.getRow(i);
var text =cell.getText();
Logger.log(text);
}
}
Although I cannot see your sample Spreadsheet, from your sample Google Document and sample output image, I believe your goal as follows.
You want to retrieve the values from the 1st table in Google Document and put the values to Google Spreadsheet by converting the values as follows.
From
To
Modification points:
In your script, 2nd table is retrieved. In your sample Document, an error occurs.
In your case, I think that it is required to retrieve the values from each cell. But in your script, the values are directly retrieved from the rows.
In your script, the values are only retrieved from the rows. In order to achieve your goal, it is required to convert the retrieved values from Document for putting to Spreadsheet.
When above points are reflected to a script, it becomes as follows.
Modified script:
Please copy and paste the following script to the script editor and set the variables and run the script. About the variable of excludeTexts, in this case, these values are from your sample Google Document. When you change the exclude text line in the table of Document, please modify the values.
function myFunction() {
const documentId = "###"; // Please set Document ID.
const spreadsheetId = "###"; // Please set Spreadsheet ID of the destination Spreadsheet.
const sheetName = "Sheet1"; // Please set the sheet name of the destination sheet.
const excludeTexts = ["Part A:", "Part B:", "Part C:"]; // Please set the exclude texts.
// 1. Retrieve values from 1st table from Document and create an array for putting to Spreadsheet.
// const body = DocumentApp.getActiveDocument().getBody(); // If you copy and paste the script to the container-bound script of Document, you can use this line instead of "DocumentApp.openById(documentId).getBody()".
const body = DocumentApp.openById(documentId).getBody();
const table = body.getTables()[0];
let values = [];
for (let r = 0; r < table.getNumRows(); r++) {
const cell = table.getRow(r);
const row = [];
for (let c = 0; c < cell.getNumCells(); c++) {
const text = cell.getCell(c).getText().trim();
row.push(r > 0 && c == 1 ? text.split("\n").map(e => e.trim()).filter(e => !excludeTexts.includes(e)) : text);
}
values = values.concat(Array.isArray(row[1]) ? row[1].map((e, i) => i == 0 ? [row[0], e, ...row.slice(2)] : ["",e,...Array(row.slice(2).length).fill("")]) : [row]);
}
console.log(values)
// 2. Put the created array to Spreadsheet.
const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}
When above script is run for your Google Document, the sample situation at the top images is obtained.
Note:
This sample script can be used for your sample Google Document. If the structure of your Document is changed, the script might be required to be modified. So please be careful this. When you test this script, please use your sample Google Document.
References:
getRow(rowIndex)
getCell(cellIndex)
Is there a way to write a Google Apps Script in Google Docs to retrieve from Google Sheets a range limited to non-blank rows and display those rows as a table?
I'm looking for a script to copy non-blank rows of data from a Google Sheets range of cells to a table in Google Documents using Google Apps Script (which I've limited experience with).
The data to be copied seem too large for linking directly to Google Documents so the Copy-Paste action from spreadsheet to document does not prompt a choice for linking the data.
Also the number of rows is dynamic so a fixed range wouldn't resolve the problem. In the spreadsheet, I've used the SORTN function and set it to display ties so the size of the non-blank rows of the range changes.
I've started with the following code outline:
function myFunction() {
// Get Google Sheet data
var app = SpreadsheetApp;
var ss = app.openById('SHEET_ID');
var activeSheet = app.getActiveSpreadsheet();
var range = activeSheet.getRange("B4:D");
// Position to paste data in Google Docs
var doc = DocumentApp.getActiveDocument();
var body = DocumentApp.getActiveDocument().getBody();
// Build a table from the array.
body.appendTable(cells);
}
This is closest question found on SE but doesn't answer this query: Copying Sheet Data to Doc table.
You want to copy the data range from Google Spreadsheet to Google Document as the table.
You want to append the table to the Google Document.
In this case, you don't want to include the empty rows of the bottom of sheet to the values.
In your situation, you are not required to link the original Spreadsheet to the table of Document.
You want to achieve this using Google Apps Script.
I could understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Flow:
The flow of this sample script is as follows.
Retrieve the data range from Google Spreadsheet.
In this case, I used getDataRegion(dimension).
Retrieve values, backgrounds and text styles using the range.
Append new table to Google Document with the values.
Set the format of cells.
Sample script:
From your script in your question, it supposes that the script is the container-bound script of Google Document. So in order to test the script, please put the following script to the container-bound script of Google Document you shared.
function myFunction() {
// Get Google Sheet data
var ss = SpreadsheetApp.openById("###"); // Please set the Spreadsheet ID.
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getRange(4, 2, 1, 5).getDataRegion(SpreadsheetApp.Dimension.ROWS);
var values = range.getValues();
var backgroundColors = range.getBackgrounds();
var styles = range.getTextStyles();
// Position to paste data in Google Docs
var body = DocumentApp.getActiveDocument().getBody();
var table = body.appendTable(values);
table.setBorderWidth(0);
for (var i = 0; i < table.getNumRows(); i++) {
for (var j = 0; j < table.getRow(i).getNumCells(); j++) {
var obj = {};
obj[DocumentApp.Attribute.BACKGROUND_COLOR] = backgroundColors[i][j];
obj[DocumentApp.Attribute.FONT_SIZE] = styles[i][j].getFontSize();
if (styles[i][j].isBold()) {
obj[DocumentApp.Attribute.BOLD] = true;
}
table.getRow(i).getCell(j).setAttributes(obj);
}
}
}
Note:
In this sample script, the values of cells "B4:F" are retrieved from your shared Spreadsheet. So if you want to change this range, please modify above script.
References:
getDataRegion(dimension)
getValues()
getBackgrounds()
getTextStyles()
appendTable()
setAttributes(attributes)
Added:
Issue for reflecting column width from Spreadsheet to Document:
It is possible to reflect the column width. But when the column width is set to Google Document, it seems that the result is different from that of the direct copy&paste the table, even when the unit is converted from Spreadsheet to Document.
In your shared Spreadsheet, the widths of column "B" to "F" are 21, 100, 100, 100 and 100 pixels, respectively. But it was found that when the table is manually copied from Spreadsheet to Document, each column width is changed from the original size. By this, unfortunately, when the column width of table is copied by the script, the result by manual copy cannot be replicated.
Sample script:
At the following sample script, the column width of Google Spreadsheet is copied to the table of Google Document.
function myFunction() {
// Get Google Sheet data
var ss = SpreadsheetApp.openById("###"); // Please set the Spreadsheet ID.
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getRange(4, 2, 1, 5).getDataRegion(SpreadsheetApp.Dimension.ROWS);
var values = range.getValues();
var backgroundColors = range.getBackgrounds();
var styles = range.getTextStyles();
var colWidth = []; // Added
for (var col = 2; col <= 6; col++) { // Added
colWidth.push(sheet.getColumnWidth(col) * 3 / 4);
}
// Position to paste data in Google Docs
var body = DocumentApp.getActiveDocument().getBody();
var table = body.appendTable(values);
table.setBorderWidth(0);
colWidth.forEach(function(e, i) {table.setColumnWidth(i, e)}); // Added
for (var i = 0; i < table.getNumRows(); i++) {
for (var j = 0; j < table.getRow(i).getNumCells(); j++) {
var obj = {};
obj[DocumentApp.Attribute.BACKGROUND_COLOR] = backgroundColors[i][j];
obj[DocumentApp.Attribute.FONT_SIZE] = styles[i][j].getFontSize();
if (styles[i][j].isBold()) {
obj[DocumentApp.Attribute.BOLD] = true;
}
table.getRow(i).getCell(j).setAttributes(obj);
}
}
}
When you run the script, you can see the created table is different from the manually copied table. So about the width of column, in the current stage, please give the values for manually setting colWidth. Or please adjust the column width of Document side by modifying the column width of Spreadsheet side. Or please use above script. This is due to my poor skill. I deeply apologize for this.
I have a Google Apps Script that fetches the data in a specific column in a spreadsheet and pushes that into a drop down menu in a Google Form.
This all works perfectly.
However, I'm trying to sort the data via the script so that before pushing it to the form, it sorts it alphabetically (A --> Z).
The data in the spreadsheet is not sorted, and I cannot just sort it in the spreadsheet because data is constantly being added.
Here is the Google Apps Script that works, except for the sorting:
function updateClientForm(){
// call your form and connect to the drop-down item
var form = FormApp.openById("1qszM48QILtnf-2QZa078ypqhjYHdB-VK2c0VMJDrsXo");
//Inspect the element on the form to find the ID value
var clientnamesList = form.getItemById("449574637").asListItem();
// identify the sheet where the data resides needed to populate the drop-down
var ss = SpreadsheetApp.getActive();
var clientnames = ss.getSheetByName("Client Names with ID");
// grab the values in the first column of the sheet - use 2 to skip header row
var namesValues = clientnames.getRange(2, 1, clientnames.getMaxRows() - 1).getValues();
var customerNames = [];
// convert the array ignoring empty cells
for(var i = 0; i < namesValues.length; i++)
if(namesValues[i][0] != "")
customerNames[i] = namesValues[i][0];
// populate the drop-down with the array data
clientnamesList.setChoiceValues(customerNames);
}
Any ideas? Thanks in advance!
Google Apps Script is based on javascript, so you have access to pretty much everything you can do in javascript.
namesValues is an array and javascript arrays come with a built-in sort function
sortedNamesValues = namesValues.sort();