Dropdowns, Modals and Carousels¶
Our topic for the next class is learning how to do some very common tasks on websites: dropdown menus, modals, and carousel (also called image galleries or slideshows). You'll use dropdown menus and modals in your final project.
There are many solutions for these problems, including fancy transitions between slides and much more. We're going to keep it fairly basic, though.
Furthermore, since we are using Bootstrap 4 in this course, we'll take advantage of the features that Bootstrap provides. If you're curious about how it could be done by hand, we'll cover that as well.
General Outline:
- BS4 Dropdowns
- BS4 Modals
- BS4 Carousels
- By Hand Dropdowns
- By Hand Slideshows
Note that all of the Bootstrap features require JavaScript, so the
head
of our HTML will have to load three Bootstrap JavaScript files
along with the Bootstrap CSS. Like this:
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.js"></script>
</head>
Bootstrap Dropdowns¶
Take a minute to read the W3Schools tutorial on BS4 Dropdowns. Just the first section is sufficient.
The menu options are clickable, allowing you to trigger some JavaScript. Clicking anywhere else on the page closes the dropdown. A simple dropdown example should suffice.
There's no JavaScript that you have to write; Bootstrap provides all the code. All you have to do is set up the HTML. Here's the HTML for that example:
<div class="btn-group">
<button type="button" class="btn btn-primary">Apple</button>
<button type="button" class="btn btn-primary">Samsung</button>
<div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
Sony
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Tablet</a>
<a class="dropdown-item" href="#">Smartphone</a>
</div>
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
Platforms
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" id="os-linux">Linux</a>
<a class="dropdown-item" href="#" id="os-mac">Mac</a>
<a class="dropdown-item" href="#" id="os-windows">Windows</a>
<button class="dropdown-item" id="os-android">Android</button>
<button class="dropdown-item" id="os-ios">IOS</button>
</div>
</div>
</div>
Things to note:
- The dropdowns are created by the CSS class
dropdown-toggle
and thedata-toggle="dropdown"
attribute. - The CSS
dropdown-menu
class builds the dropdown menu. - Add the
dropdown-item
class to each menu item - For the menu items, you can use either hyperlinks
<a href="#">
or buttons<button type="button">
.
I prefer using button
because the hyperlinks end up with a #
in
the URL, which I find ugly, and they mess up the "back" button,
because clicking "back" returns you to the page without the #
in the
URL, instead of to the previous page (this one). Try it!
- Visit the example, click on "Linux" and then click the back button.
- Visit the example, click on "Android" and then click the back button.
Of course, if you want the dropdown to have hyperlinks in it, say to
other parts of your multi-page site or even external links, then <a>
is the way to go. Plus, if you want to use hyperlinks but just to
trigger JavaScript, you can use the event.preventDefault()
that we
learned. So my preference is not the only way to go.
Adding JavaScript¶
In the example above, I added id
attributes to the items on the
"Platforms" menu, which allows me to trigger some JavaScript event
handlers. I added some simple demo behaviors like this:
// These event handlers are not necessary for the dropdowns to work. They show that you can
// add your own event handlers to the buttons above to do whatever you want.
$("#os-linux").click(function (evt) {
console.log('I see you are a Linux fan! Bravo!');
});
$("#os-mac").click(() => console.log('Oh ho! Another Apple aficionado!'));
$("#os-windows").click(() => console.log('Interesting! a Windows maverick on a Mac-centric campus!'));
$("#os-android").click(() => console.log('Nice! Will you learn how to program apps on your phone?'));
$("#os-ios").click(() => console.log("I'm told these are best for privacy. True?"));
Try them and look in the JS console.
Note that I didn't add my bounds
plug-in to check that I had spelled
the selectors correctly, which I immediately regretted because I
didn't spell them all correctly. My bounds plugin does work with the
jQuery that's loaded by Bootstrap, so you could do that. Just add the
following to the head, after we load jQuery:
<script src="https://cs.wellesley.edu/~anderson/js/bounds/bounds-plugin.js"></script>
Bootstrap 4 Modal¶
A modal is a pop-up dialog box. It's very intrusive, so you wouldn't want to use it all the time, but sometimes it's the right thing to do.
Take a minute to read the first section of the W3Schools BS4 Modal.
Here's an example
In that example, the modal is an order form. If you click the red "close" button, the modal closes with no harm done. You can also close it by clicking anywhere outside it.
Modals allow a more extended interaction with the user than just a dropdown menu.
Here, we might want to trigger some JavaScript if the user clicks the "place order" button (which is, in fact, an ordinary button not a submit button). The JS is pretty straightforward:
// Demo of how to add an event handler to the modal order form.
$("#place_order").click(function (evt) {
console.log('order for',
$('[name=name]').val(),
$('[name=size]').val(),
$('[name=crop]').val());
$('form')[0].reset();
$('#myModal').modal('hide');
});
Note, though, that we explicitly have to hide the modal when we are done, using:
$('#myModal').modal('hide');
Carousels¶
Carousels is what the Bootstrap developers call this feature. Other people might call them slideshows or image galleries. The markup is a bit more complex than the earlier features.
Please read the first section of the W3Schools BS4 Carousel.
Here's a slideshow example using some pictures of Harry Potter actors.
I won't go into the details of the markup, but I'd be happy to talk to you about it if you need help.
Dropdowns and Carousels By Hand¶
The following sections discuss how to do dropdowns and carousels "by hand" (meaning not using Bootstrap).
Rather than write up how to do this, I'm going to defer to two descriptions that are on W3Schools, using the links below.
Clickable Dropdowns¶
We want to be mobile-friendly and old-fashioned dropdown menus typically dropdown when the mouse is hovered over them. But we can't "hover" on a touch-screen device. Instead, we will click to open/close a dropdown menu. Here's one way:
Clickable dropdowns are useful in general, and we will use them in the final project, so they are worth learning.
That code is good but has some flaws, which I will address in class. Let's build up to that.
Slideshows¶
A slideshow displays one of a set of images, rotating through them. It has arrows to advance the slideshow or move it backwards, little buttons to indicate where we are in the set and lots of other eye candy.
Again, the W3Schools code is good but has some flaws, which I'll address in class and below.
Automatic Slideshows¶
To have a slideshow automatically advance, it's sufficient to have a
function that will manually advance the slideshow, and then have the
browser invoke that function every few seconds. That's easily done with
the built-in JavaScript setInterval
function.
Learn more about setInterval
from MDN: setInterval
The W3Schools example uses setTimeout
, but I think setInterval
is
superior, because it separates the code that advances the slideshow
from the automatic advance behavior. That allows us additional
flexibility. For example, the W3Schools code doesn't allow us to turn
the automatic slideshow off, because the return value from
setTimeout
is buried in the showSlides
function. That return value
would allow us to cancel the event.
Turning a Slideshow on/off¶
Both setTimeout
and setInterval
return a numeric code or id
for that event, allowing us to cancel the event. It's just a small
integer with no meaning other than identifying which future event this
is, a meaning that is known only to the browser. So our code just
stores it and, if we want to cancel the event, passes the ID to
clearTimeout
or clearInterval
.
Here's code that would allow us to turn an automatic slideshow on/off:
<button id="startSlideshow">start slideshow</button>
<button id="stopSlideshow">stop slideshow</button>
// global variable holding the code to cancel the slideshow.
var intervalId;
$("#startSlideShow").click(function () { intervalId = setInterval(nextSlide, 1000) });
$("#stopSlideShow").click(function () { clearInterval(intervalId) });
To be fair, the W3Schools code could be modified to store the ID in a
variable, allowing us to stop the slideshow, but I still like the
setInterval
modularity better, because we can easily switch between
automatic and manual mode slideshows.
Conclusion¶
The Bootstrap features are relatively simple to use and come with thoroughly debugged JavaScript, so those are a couple of huge points in their favor. Furthermore, the Bootstrap features have thought about accessibility, such as being able to use the dropdowns with the keyboard (tab key, arrows keys, the enter key) for those who can't use a mouse or prefer not to (I'm sometimes in the latter camp). So that's another huge point in its favor.
A small downside is having to load the JavaScript files: not just
jQuery, but popper.js
and bootstrap.js
. Slimming those down is
part of the goal of Bootstrap version 5. But that's a minor point, and
chances are your browser already has those in cache. Furthermore, if
you're already using Bootstrap JavaScript, there's no additional
penalty to using these features.
Finally, while Bootstrap is pretty flexible, it's not as flexible as raw CSS and JavaScript, so it might feel confining. You may want slightly different behavior, in which case you should know that it's not magic; it's just JavaScript, which you are capable of figuring out and modifying (or replacing) if you choose.