Welcome!
Everything is fine.

Dropdowns and Slideshows

Today, we'll look at some fun and useful techniques. It won't be a lot of JavaScript, but it'll interact with the HTML and CSS, so you have to pay attention to all the pieces.

Plan

  1. Announcements
  2. Bootstrap features: dropdowns, modals, and carousels
  3. Dropdowns recap
  4. Slideshows recap
  5. Answer your questions
  6. Breakout

Of the two, dropdowns are more important because you'll use them in the final project.

Announcements

  1. Grading status: I'm a bit behind; sorry. I'll catch up soon

Jelly Blob Hints

  • Jelly Blobs is fun, but hard. Allocate enough time for it.
  • Your jQuery work will almost always be working with just the one DOM element corresponding to a particular blob, which you will have saved in an instance variable. So:
    • $(this.domElt).css(...) rather than
    • $("div").css(...)
  • Updating location is tricky. Let's discuss and I'll demo how that example should work.

Your Questions

I'll answer your questions

Bootstrap Features

  • It's perfectly okay to use the Bootstrap features if you like them.
  • Just know that they aren't magical; you could implement them yourself given a little time for testing and debugging.

Clickable Dropdowns

The main ideas are these:

  • the dropdown menu is positioned using absolute positioning so that it can overlap other content
  • the z-index is used to make sure it's in front of other content
  • the dropdown is hidden
  • the dropdown is shown by clicking on some kind of header
  • clicking anywhere closes the dropdown (though nested dropdowns are more complex)

The JS code toggles whether the dropdown is shown or not.

We add a click handler to the window that catches every click that bubbles up to it. Unless the target is the header (.dropbtn), the handler closes every dropdown.

W3 Schools clickable dropdown

Slideshows

The essential ideas are these:

  • all the images are there in the HTML when the page loads
  • all the images but one are hidden
  • there are buttons/icons/arrows that have click handlers to change to next/prev slide
  • the JS changes which image is shown, hiding all the rest
  • there are buttons/icons/dots that have click handlers to jump to that particular slide

The CSS ensures that there is a container that all the slides, buttons and other stuff are positioned relative to.

W3Schools Code

We'll spend some time walking through this code

slideshow

Criticisms

I like the W3Schools example. It looks nice, the code is reasonably clear, and it works. I have a few objections to the JS code:

First, modern practice is to separate the JS code from the HTML, so avoid onclick="jscode" in favor of attaching the event handler from the .js file:

<a class="prev" onclick="plusSlides(-1)">&#10094;</a>

becomes

<a class="prev">&#10094;</a>

with this JS/JQ:

$("a.prev").click(function () { plusSlides(-1); });

(BTW, the &#10094; is the html entity for a heavy left-pointing angle quotation mark), which looks like ❮

W3Schools has a list of arrows and such

I'm sure they used inline JavaScript because they wanted to reduce the number of different pieces of code for you to look at, which is a fair pedagogical reason.

Second, I dislike code that has side-effects in arguments:

var slideIndex;

function plusSlides(n) {
    showSlides( slideIndex += n );
}

I'd rather see:

var slideIndex;

function plusSlides(n) {
    slideIndex += n;
    showSlides( slideIndex );
}

But I don't feel that strongly about it, and I've used side-effects in arguments in my own code, sparingly.

Third, they use global variables, so you can't have multiple slideshows on one page. (But this makes the code simpler and clearer for exposition, and we've used lots of global variables this semester.)

Fourth, they did it in raw JS instead of JQ.

None of these are fatal flaws, just minor objections.

Alternatives

Here's another way to do the slideshow, in which all the slides are arranged left to right within a container that is only big enough to show one at a time. By sliding the whole ensemble to the left, you can advance the slides in a nice way:

cs110 f15 animation slideshow

There are dozens of JS libraries to do slideshows. Web-search for one and see what you like. Now that you understand the basic principles, you can teach yourself other slideshow or gallery implementations.

Automatic Slideshows

Given a function like nextSlide, we can just invoke it every time interval:

var intervalId = setInterval(nextSlide, 2000);  // every 2 seconds

The returned value, which I stored in intervalId, can be used to stop the slideshow using clearInterval() function.

The MDN page on setInterval discusses the problem with this, which arrow functions can solve.

Clickable Dropdowns

(This section is a bit more complicated; but it'll be useful for the project.)

I noticed some problems with the W3 Schools dropdowns if you use their technique for multiple dropdowns.

  • clicking on the head of a dropdown closes that dropdown, but not others.
  • if the drop content opens something like a form, you can't click in the form without closing the form. Eeek!

Try those operations:

drop menus

I solved it like this:

drop click

Basic Idea:

  • enclose the dropdown material with .dropClickContent instead of .dropContent
  • in the handler for window click, check to see if the click is inside a .dropClickContent
  • if so, ignore it

Also, to allow other headers to close the dropcontent, I switched from toggleClass to closeAll and then addClass

Here's what the HTML for dropdowns looks like. Notice the class dropClick

<li><button class="dropBtn" type="button">Brave</button>
    <ul class="dropContent">
        <li><button id="btnHarry" type="button">Harry</button></li>
        <li><button id="btnRon" type="button">Ron</button></li>
        <li><button id="btnHermione" type="button">Hermione</button></li>
    </ul>
</li>

As you can see, the hidden stuff is marked with dropContent and the toggles are dropBtn.

Here's the HTML for the drop-down form. Notice the class dropClickContent

<li><button class="dropBtn" type="button">Form</button>
            <div class="dropClickContent">
                <form>
                    <p><label>What is your name?
                            <input type="text" name="name"></label></p>
                    <p><label for="quest">What is your quest?</label></p>
                    <textarea id="quest" name="quest" rows=5 cols=60></textarea>
                    <p>
                    <label>What is your favorite color?
                        <select name="color">
                            <option>blue</option>
                            <option>yellow</option>
                        </select>
                    </label></p>
                </form>
            </div>
        </li>

DropClick JavaScript Code

The JS/JQ code is like this. It uses a delegated handler, so it covers every .dropBtn on the page with just one handler nav element.

It works as follows:

  • finds the sibling element (which is the hidden one)
  • hides everything
  • shows the sibling if it wasn't already
$("nav").on('click',
            ".dropBtn",
            function (evt) {
                console.log("clicked on "+$(evt.target).text());
                let sib = $(evt.target).next().one();
                let shown = sib.hasClass('show');
                closeAllDropDowns();
               // open our dropdown, if not shown
               if(!shown) {
                  sib.addClass('show');
               }
});


function closeAllDropDowns() {
    console.log("closing all dropdowns");
    $(".dropContent,.dropClickContent").removeClass('show');
}

Finally, to allow clicking anywhere outside the dropContent to close any open dropdowns. It works as follows:

  • determines if there is a .dropClickContent ancestor
  • if not and the target is not a .dropBtn, close all dropdowns
// This closes all dropdowns if you 
// click anywhere outside the dropContent
// Same effect as W3 Schools, but 
// uses jQuery for brevity
// Also checks that we are not 
// in a dropClickContent element

$(window).click(function (evt) { 
    var dcc = $(evt.target).closest(".dropClickContent");
    var inDcc = (dcc.length === 1);
    if (!evt.target.matches('.dropBtn') &&
        !inDcc) {
       closeAllDropDowns();
    }
});

Performance

In our slideshow implementation we had all the IMG tags in the source, so they all load when the page loads. That can slow down page loading if there are many images or they are big or both. So, this technique doesn't necessarily scale. However, there are ways to deal with that, such as having just the first few images in the source and having a Javascript element at the end of the page that adds the extra ones, or even having fancy code that pre-loads upcoming images when an earlier one is clicked on (for example, loading the N+2nd image when the Nth is shown).

Summary

Galleries, Slideshows, and clickable dropdown menus are common and the menus are particularly useful. The ottergram from Chapter 6 is a nice gallery.

They are based on hiding an element and revealing it later, triggered by some event, such as a click or a

Clickable dropdowns are the modern way because of touch-screen devices.

Exercise

Copy the folder for today:

cp -r ~cs204/pub/downloads/slideshows slideshows
cd slideshows

Using the start.html file, do some of these:

  • Add a dropdown menu going to three places
  • Create a slideshow.
  • Create an automatic slideshow.

my solution

That has some useful abstractions that are worth looking at. We'll do that next time.