Question

Is it possible to add/remove slides while a presentation is running with reveal.js? To be precise, is there an API for that or maybe some dirty workaround?

Was it helpful?

Solution

I was curious about this as well for an upcoming project; looked around and couldn't find anything so I wrote something for my own project, appended at the end. Adding a slide after your current slide is pretty straightforward. Just append a section element to '.slides', and make sure the section has class 'future'. Also, if you are on the last slide, you need to add class 'enabled' to '.navigate-right'. Adding something before the current slide messes up the numbering, so you need to add it with class 'past', and then move to the next slide.

Same would go for removing a slide, if you remove a '.past' slide, that messes up your numbering. I haven't tested my code well (yet), so if you use it as is test well.

        Reveal.addEventListener( 'ready', function( event ) {
            Reveal.add = function( content = '',index = -1 ){ 
                dom = {},

                dom.slides = document.querySelector( '.reveal .slides' );
                var newSlide = document.createElement( 'section' );
                if( index === -1 ) { //adding slide to end
                    newSlide.classList.add( 'future' );
                    dom.slides.appendChild(newSlide);
                    document.querySelector( '.navigate-right' ).classList.add( 'enabled' ); //just enable it, even if it is
                } else if( index > Reveal.getIndices().h ) {
                    newSlide.classList.add( 'future' );
                    dom.slides.insertBefore(newSlide,dom.slides.querySelectorAll('section:nth-child('+(index+1)+')')[0]);
                } else if( index <= Reveal.getIndices().h ) {
                    newSlide.classList.add( 'past' );
                    dom.slides.insertBefore(newSlide,dom.slides.querySelectorAll('section:nth-child('+(index+1)+')')[0]);
                    Reveal.next();
                }
                newSlide.innerHTML = content;
            };
            Reveal.remove = function( index = -1 ){ 
                dom = {},

                dom.wrapper = document.querySelector( '.reveal' );
                dom.slides = document.querySelector( '.reveal .slides' );
                var target = (dom.wrapper.querySelectorAll('.slides > section:nth-child('+(index+1)+')')[0]) ? dom.wrapper.querySelectorAll('.slides > section:nth-child('+(index+1)+')')[0] : false;

                if( index === -1 ) {
                    if (Reveal.isLastSlide()) Reveal.prev();
                    dom.slides.removeChild(dom.wrapper.querySelectorAll('.slides > section')[dom.wrapper.querySelectorAll('.slides > section').length-1]);
                    if (Reveal.isLastSlide()) document.querySelector( '.navigate-right' ).classList.remove( 'enabled' );
                } else if( index > Reveal.getIndices().h && target ) {
                    dom.slides.removeChild(target);
                    if (Reveal.getIndices().h == dom.wrapper.querySelectorAll('.slides > section').length-1) document.querySelector( '.navigate-right' ).classList.remove( 'enabled' );
                } else if( index < Reveal.getIndices().h && target ) {
                    dom.slides.removeChild(target);
                    location.hash = '/'+parseInt(Reveal.getIndices().h-1);
                } else if( index == Reveal.getIndices().h && target ) {
                    if (index == 0) {
                        Reveal.next();
                        document.querySelector( '.navigate-left' ).classList.remove( 'enabled' );
                    } else Reveal.prev();
                    dom.slides.removeChild(target);
                    if( dom.wrapper.querySelectorAll('.slides > section').length == index) document.querySelector( '.navigate-right' ).classList.remove( 'enabled' );
                }
            };
        } );

If you want to use this, add it after Reveal.initialize({...});

Call it with Reveal.add(content,index), or Reveal.remove(index).

Reveal.add('<h3>Slide title</h3>') 

would add that as the last slide,

Reveal.add('<h3>Slide title</h3>',0) 

at the beginning.

Reveal.add('<h3>Slide title</h3>',3) 

would add it in the 3rd location.

Reveal.remove() removes the last slide, Reveal.remove(n) any other (if it exists).

OTHER TIPS

Reveal.sync() is the king.

You can dynamically remove slides.

Here is the full example: CollaboFramework

Here is an example of removing all slides:

  var presentation = $('#presentation');
  var slides = $('#presentation .slides');
  slides.empty();

Here is an example of adding a new slide

// slide 1
  var section = $("<section></section>");
  slides.append(section);
  section.attr('data-markdown', '');

  var script = $("<script></script>");
  section.append(script);
  script.attr('type', 'text/template');

  var slideContent =
  "and here is the image\r\n" +
  "<img src='https://cdn.psychologytoday.com/sites/default/files/field_blog_entry_images/flower-887443_960_720.jpg' width='200px' height='200px'>\r\n" +
  "and here is the list\r\n" +
  "+ hopa\r\n" +
  "+ cupa\r\n" +
  "+ and some intended links\r\n" +
  " + [CS link](http://www.CollaboScience.com)\r\n" +
  " + [CA link](http://www.CollaboArte.com)\r\n" +
  " + [CF link](https://github.com/Cha-OS/KnAllEdge/)\r\n";

  script.html(slideContent);

It is a Markdown slide, but it is similar for HTML, and here you have generic slide creation

Of course, at the real github code you will see that it makes sense to provide some delay to wait tags to get created before confirming task finished (with callback).

Finally, you need to update Reveal, which appart of rerendering with markdown plugin is just using Reveal.sync().

This will do all class juggling for you, recounting slide numbers, etc. The only other important thing is to do Reveal.slide(0) to be sure that you are not at slide 7 out of 5 :) in the case you removed 2 slides.

My workaround for this was to:

  1. Initialize reveal with an empty section tag.

    HTML

    <div class="reveal">
      <div class="slides">
        <section>Single Horizontal Slide</section>
        <section id="blank"></section><!-- Blank slug -->
      </div>
     </div>
    

    Javascript

    Reveal.initialize();
    
    //slide deck wrapper
    deck = $('#blank').parent();
    
  2. Store this tag then remove it from the DOM.

    // a blank is initialized and stored as a variable
    wrap = $('#blank').clone()
                      .attr('id',null)
                      .prop('outerHTML');
    // remove the blank
    $('#blank').remove();
    
  3. Lastly a new element is added to deck and wrapped in the empty tag.

      $('<h1>Slide added</h1>').appendTo(deck)
                      .wrap( wrap );
    

Here is a demo. I haven't tried this technique with any complicated configurations, but for a simple presentation this suffices.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top