Copying Multiple Slides from a Master Slide Desk using Google Apps Script - javascript

I have created a code which replaces placeholders on google slides. The starting point of this project is a google form. Once the google form has been submitted - then the relevant data from google form is entered on the google slides template. See below code. I am looking to create a question on the form where people will be able to select multiple slides to be included (2 Credential slides for example out of 10)
function PoD() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("A-PoD").activate();
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow()
for (var i =2;i<lr;i++){
if(ss.getRange(i, 1).getValue()){
//Make a copy of the template file
var documentId = DriveApp.getFileById('1REHMrl6kfzXbgSipvBDkNitkfsM8tJsUSAICggxNsHw').makeCopy().getId();
var Name_of_programme = ss.getRange(i, 2).getValue();
DriveApp.getFileById(documentId).setName("PwC's Academy_"+Name_of_client+"_"+Name_of_programme+"_"+Month);
var FileName = Name_of_programme;
//Get the document body as a variable
var body = SlidesApp.openById(documentId);
body.replaceAllText('{Name of programme}', Name_of_programme);
var lastSlide = body.getSlides();
lastSlide[5].remove();
I am looking to continue the script to include a function to select multiple slides. I saw the below script to copy one slide but have not been able to figure out how to copy multiple slides easily.
var srcPresentationId = "### source fileId ###";
var copysrcSlideIndex = 0; // 0 means page 1.
var copydstSlideIndex = 0; // 0 means page 1.
var src = SlidesApp.openById(srcPresentationId).getSlides()[copysrcSlideIndex];
SlidesApp.getActivePresentation().insertSlide(copydstSlideIndex, src);
I want to give people the choice to select which slides to include on the google form as multiple choice.
At the back end of the script, would I need to map the names of the slides with slide numbers? or can have include a unique reference in a text box on each slide and then select the relevant slide? Thinking out loud here. Any guidance would be appreciated.

You want to copy the 5, 7, and 9 pages (indexes of 4, 6 and 8) in the master Google Slides to other Google Slides.
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:
Retrieve all slides from the master Google Slides.
Copy the required slide to the destination Google Slides in the loop.
Pattern 1:
Sample script:
Before you run the script, please set the variables.
function myFunction() {
var copyPageNumbers = [5, 7, 9]; // Please set the page number. This is not the index. So the 1st page is 1.
var masterGoogleSlidesId = "###"; // Please set the master Google Slides ID.
var destinationGoogleSlidesId = "###"; // Please set the destination Google Slides ID.
var offset = 1;
var src = SlidesApp.openById(masterGoogleSlidesId);
var dst = SlidesApp.openById(destinationGoogleSlidesId);
var slides = src.getSlides();
var page = 0;
slides.forEach(function(slide, i) {
if (copyPageNumbers.indexOf(i + 1) != -1) {
dst.insertSlide(offset + page, slide);
page++;
}
});
}
Pattern 2:
Sample script:
function myFunction() {
var copyPageNumbers = [5, 7, 9]; // Please set the page number. This is not the index. So the 1st page is 1.
var masterGoogleSlidesId = "###"; // Please set the master Google Slides ID.
var destinationGoogleSlidesId = "###"; // Please set the destination Google Slides ID.
var offset = 1;
var src = SlidesApp.openById(masterGoogleSlidesId);
var dst = SlidesApp.openById(destinationGoogleSlidesId);
var slides = src.getSlides();
copyPageNumbers.forEach(function(p, i) {
dst.insertSlide(offset + i, slides[p - 1]);
});
}
Note:
In both patterns, the pages of 5, 7 and 9 of the master Google Slides are copied from 2nd page in the destination Google Slides.
When var offset = 0 is used, the pages of 5, 7 and 9 of the master Google Slides are copied from 1st page in the destination Google Slides.
Reference:
insertSlide(insertionIndex, slide)

Thanks, #Tanaike, for the solutions!
With your code as a base, I was able to build a script to add slides to multiple slide decks in a single folder. I wanted to share for those who may need it. Code below...
function copySlides() {
// Array of slide numbers to grab [1, 2, 3,...]
var copyPageNumbers = [1]; // Please set the page number. This is not the index. So the 1st page is 1.
// Which deck contains the slides to copy
var masterGoogleSlidesId = '###'; // Please set the master Google Slides ID.
// Folder containing Slides to copy to
var folderID = '###';
var folderToCopyTo = DriveApp.getFolderById(folderID);
// Slide files in folder
var slidesInFolder = folderToCopyTo.getFilesByType(MimeType.GOOGLE_SLIDES);
var counter = 0;
var total = 0;
while (slidesInFolder.hasNext()) {
var file = slidesInFolder.next();
var destinationGoogleSlidesId = file.getId(); // Please set the destination Google Slides ID.
var offset = 0;
try {
var src = SlidesApp.openById(masterGoogleSlidesId);
var dst = SlidesApp.openById(destinationGoogleSlidesId);
var slides = src.getSlides();
copyPageNumbers.forEach(function (p, i) {
dst.insertSlide(offset + i, slides[p - 1]);
});
counter++;
}
catch (e) {
console.log(destinationGoogleSlidesId);
console.log(e);
}
total++;
}
console.log(counter + ' of ' + total + ' Slide Decks Updated');
}

Related

Copy data from one spreadsheet to another on edit

I already try everthing but I cant make this work =/
I'm trying to copy data from one spreadsheet to other using setValues(), because link doesn't work for me. I also need to keep the trigger on edit.
So, I create one fuction called AddConvocacao, and always when have any change the script run.
function addConvocacao(e){
var linha = e.range.getRow(); //get the number of the line, where have edit
var nome = e.source.getActiveSheet().getRange(linha,2).getValue(); //get the value of the field
var targetSheet = SpreadsheetApp.openById('1iQbZ7iB9ddc-HwLK9vG0eVEeWWqXKJZ0ry7U_Hm4SkQ') //open the other spreedsheet
var targetName = targetSheet.getSheetByName('Pac'); //open the tab
var lastRow = targetName.getLastRow(); //count the last row in this tab
lastRow = lastRow+1; //add 1
targetName.getRange(lastRow, 2).setValue(nome); // set the value
// targetName.getRange(lastRow, 3).setValue(valorCol7);
// targetName.getRange(lastRow, 5).setValue(dose);
// targetName.getRange(lastRow, 6).setValue(diagnostico);
// targetName.getRange(lastRow, 7).setValue(medico);
}
why dosen't work when I use on edit?
Thanks so much! =)
I did it a little different I think. I put checkboxes in column one and capture the value from column 2 and sent it to the other spreadsheet to the bottom of column 2
function onMyEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
//Logger.log(JSON.stringify(e));
if (sh.getName() == 'Sheet1' && e.range.columnStart==1 && e.value=="TRUE") {
//e.source.toast('cond');
const v = sh.getRange(e.range.rowStart, 2).getValue();
var tss = SpreadsheetApp.openById(getGlobal('targetid'));
var tsh = tss.getSheetByName('Sheet1');
tsh.getRange(tsh.getLastRow() + 1, 2).setValue(v);
e.range.setValue("FALSE");
}
}
You must use an installable trigger to us openById();
getGlobal(targetid) just gets a spreadsheet id you can replace that with the id
Also I limited the action to only one sheet and only when I set the checkbox to true. I reset it back to false in the code.
You'll need to modify a few things to get it to work for you because when I'm doing the examples I do it my way.

Need help shortening down function that creates a lot of elements in array

I have a file with 170 images. These images are displayed on my website and the user can slide to see different pictures. This code works but I'm looking for a more efficient way to do what I did below.
var imgCo2 = new Array(); //create new array containing all elements below
imgCo2[0] = 'co2_model/0.jpg'; //string is this element of the array. string goes to local image located in file co2_model
imgCo2[1] = 'co2_model/1.jpg';
imgCo2[2] = 'co2_model/2.jpg';
imgCo2[3] = 'co2_model/3.jpg';
imgCo2[4] = 'co2_model/4.jpg';
imgCo2[5] = 'co2_model/5.jpg';
imgCo2[6] = 'co2_model/6.jpg';
imgCo2[7] = 'co2_model/7.jpg';
imgCo2[8] = 'co2_model/8.jpg';
imgCo2[9] = 'co2_model/9.jpg';
This repeats up to 171 and then I have a similar array with different images that goes to 150. This code is used for a an img slider. The slider code is below.
$(document).on('input change', '#slider', function() {//listen to slider changes
var v=$(this).val();//getting slider val
$('#sliderStatus').html( $(this).val() );
$("#imgTemp").prop("src", imageTemp[v]);
});
if you image name is not changing did you consider doing something like this
$(document).on('input change', '#slider', function() {//listen to slider changes
var v=$(this).val();//getting slider val
$('#sliderStatus').html( $(this).val() );
$("#imgTemp").prop("src", `co2_model/${v}.jpg`);
});
in this case you will not need an array at all
Question not closed yet so I'll put the code below. Wasn't as hard as I thought
var imgCo2 = new Array();
var i;
for (i= 0; i!=172; i++){ //the 172 is manually put(amount of images in the file starting from 0)
imgCo2[i]= 'co2_model/'+i+'.jpg'
}

Google Apps Script is Not Detecting the Current Row

I created a function that's tied to a custom menu item in a google spreadsheet and is meant to detect the current row and perform some checking. The issue is that every time i run the menu item > script it always detect row 1 and not the current script. here's the code for reference:
function updateCalendarItems(){
//this function detects the current row and updates the main and follow up calendar events
//Get the current row
var ss = SpreadsheetApp.openById('<deleted>');
var sheet = ss.getSheetByName('db_clientvisit');
Logger.log('Sheet Name: '+sheet.getName()); //this logs the correct sheet name
// var range = sheet.getActiveCell();
var rowNum = sheet.getActiveCell().getRow();
Logger.log(rowNum); //always logs 1
var range = sheet.getRange(rowNum, 1, 1, 13).getValues(); //always returns the first row
Logger.log(range);
var ui = SpreadsheetApp.getUi();
ui.alert('Row Num is :'+rowNum+' Column Num is: '+sheet.getActiveCell().getColumn());
return;
var range = sheet.getRange(rowNum, 1, 1, 13);
var row = range.getValues()[0];
Logger.log(row);
//open the calendar
var calendarID = 'loveyourself.ph_umvj5k6vo45ei0mbh423g97ebg#group.calendar.google.com';
var calendar = CalendarApp.getCalendarById(calendarID);
//update the calendar...
}
Use var ss = SpreadsheetApp.getActive().
When you use SpreadsheetApp.openById('<deleted>'), you're essentially opening up a new session of the spreadsheet instead of your active session. So Apps Script isn't able to get the "active" ranges.
Similarly, you may also want to try using SpreadsheetApp.getCurrentCell().
function updateCalendarItems() {
var currentCell = SpreadsheetApp.getCurrentCell();
var rowNum = currentCell.getRow();
var ui = SpreadsheetApp.getUi();
ui.alert('Row Num is :'+rowNum+' Column Num is: '+currentCell.getColumn());
return;
}

Multiple JSON parses + parsing top 10 games from Twitch API

Alright. So the following code fetches only the first channel from the list, I want it to be fetching all the streams from the JSON. ( Bonus question: How can I format all the fetched streams into a nice row-per-row grid which features three streams in each row )
<script>
var twitchApi = "https://api.twitch.tv/kraken/streams";
$.getJSON(twitchApi, function (json) {
var streamGame = json.streams[0].game;
var streamThumb = json.streams[0].preview;
var streamVideo = json.streams[0].name;
$('#twitch').append('<li><iframe src="http://player.twitch.tv/?channel=' + streamVideo + '"></iframe></li>');
}
);
</script>
And the second thing I need help with is how to create a script which fetches the top 10 games from this JSON : https://api.twitch.tv/kraken/games/top .. Should be quite similar to the one above but my brain is frozen and I need to finish this.
You can get what you need to get done with a combination of loops and inline-block elements. Here, I used jQuery to create rows of three cells each.
var twitchApi = "https://api.twitch.tv/kraken/streams";
$.getJSON(twitchApi, function (json) {
var streamRow = $("<div class='stream-row'></div>").appendTo("#twitch"); // Create first row.
var streamCell;
var streamVideo;
for (var i = 0; i < json.streams.length; i++)
{
if (i % 3 == 0 && i > 0)
{
// Create a new row every multiple of 3.
streamRow = $("<div class='stream-row'></div>");
$("#twitch").append(streamRow);
}
// Create a cell with a video and add it to the row.
streamVideo = json.streams[i].channel.name;
streamCell = $("<div>", {
css: {
"class": "stream-cell",
"display": "inline-block"
}
});
streamCell.append('<iframe src="http://player.twitch.tv/?channel=' + streamVideo + '"></iframe>');
streamRow.append(streamCell);
}
});
You use another loop for the top ten thing. The API already returns 10 games, so I used the length instead of hard-coding 10.
var twitchApi = "https://api.twitch.tv/kraken/games/top";
$.getJSON(twitchApi, function (json) {
for (var i = 0; i < json.top.length; i++)
{
// Do whatever you need here with the info from the JSON.
console.log(json.top[i].game.name)
}
});
For fetching more than one stream at same time with the same data you can use a for loop.
Fixed your streamVideo variable, ".channel" was missing before ".name"(I recommed using a JSON viewer to get a clear vision of the structure, like Online JSON Viewer
And made the script so 10 iframes are displayed(also grabbed the embed code from twitch, your embed was so small).
The styling I let it to your own, I know nothing about styling iframes, you can try setting 30% width for each, so there are 3 per row, and the others go in the bottom row.
var twitchApi = "https://api.twitch.tv/kraken/streams";
$.getJSON(twitchApi, function(json) {
for (i = 0; i < 10; i++) {
var streamGame = json.streams[i].game;
var streamThumb = json.streams[i].preview;
var streamVideo = json.streams[i].channel.name;
$('#twitch').append('<li><iframe src="https://player.twitch.tv/?channel=' + streamVideo + '" frameborder="0" scrolling="no" height="378" width="620"></iframe><li>');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Trying to call Javascript Function when SharePoint List View Web Part is filtered

I have some JavaScript that will colour row in a SharePoint list View web part depending on values in certain column.
This part works fine and the rows are coloured correctly upon page load.
The issue I have is that when the List is filtered (if you click on any of the column headers and arrange by Ascending or Descending order) the formatting is lost and the colours disappear.
I'm looking for a way for the formatting to stay or be reapplied after the filter action has completed.
If the page is refreshed, the Filter that was selected will remain in place and the colours will return.
I need a way for the colours to be reapplied once a filter has been applied instead of just on Page Load.
Thanks in advance.
Here is my current JS:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function(ctx) {
var rows = ctx.ListData.Row;
for (var i=0;i<rows.length;i++)
{
var trimmed = rows[i]["Age"]
var final = trimmed.replace(",", "");
var oneWeek = final < 7;
var oneToTwo = final >= 7 && final <= 14;
var twoOrMore = final > 14;
if (oneWeek)
{
var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
var tr = document.getElementById(rowElementId);
tr.style.backgroundColor = "#CCFFCC";
}
else if (oneToTwo)
{
var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
var tr = document.getElementById(rowElementId);
tr.style.backgroundColor = "#FFEECC";
}
else if (twoOrMore)
{
var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
var tr = document.getElementById(rowElementId);
tr.style.backgroundColor = "#FFCCCC";
}
}
}
}
);
So after a ton of investigation, it turns out my formatting was being overwritten at the last second after a sort or filter had taken place.
The solution was to add this to the end of the code:
ctx.skipNextAnimation = true;
This skipped the animation that shows all of the rows falling into place and allows my formatting to take effect as it should.
I would recommend to check the jquery.tablesorter.js out, this will hold your styles.
The ordering is on client side in your case, so you have to solve it there.
You can apply it for simple tables, and add a short js:
$(document).ready(function()
{
$("#myTable").tablesorter();
}
);

Categories