Book Image

Bootstrap 4 ??? Responsive Web Design

By : Silvio Moreto, Matt Lambert, Benjamin Jakobus, Jason Marah
Book Image

Bootstrap 4 ??? Responsive Web Design

By: Silvio Moreto, Matt Lambert, Benjamin Jakobus, Jason Marah

Overview of this book

Bootstrap framework's ease-of-use (along with its cross-browser compatibility, support for mobile user interfaces, and responsive web design capabilities) makes it an essential building block for any modern web application. With the first module, plunge into the Bootstrap frontend framework with the help of examples that will illustrate the use of each element and component in a proper way. You will get a better understanding of what is happening and where you want to reach. Also, you will gain confidence with the framework and develop some very common examples using Bootstrap. All these examples are explained step by step and in depth. The second module is a comprehensive tutorial; we'll teach you everything that you need to know to start building websites with Bootstrap 4 in a practical way. You'll learn about build tools such as Node, Grunt, and many others. You'll also discover the principles of mobile-first design in order to ensure that your pages can fit any screen size and meet responsive requirements. Learn Bootstrap's grid system and base CSS to ensure that your designs are robust and that your development process is speedy and efficient. Right from the first chapter of the third module, you'll delve into building a customized Bootstrap website from scratch. Get to grips with Bootstrap's key features and quickly discover the various ways in which Bootstrap can help you develop web interfaces. Once you reach the final pages of this book, you should have mastered the framework's ins and outs, and should be building highly customizable and optimized web interfaces. The course will enable you to rapidly build elegant, powerful, and responsive interfaces for professional-level web pages using Bootstrap 4. This Learning Path combines some of the best that Packt has to offer in one complete, curated package. It includes content from the following Packt products: ? Bootstrap by Example – by Silvio Moreto ? Learning Bootstrap 4, Second Edition – by Matt Lambert ? Mastering Bootstrap 4 – by Benjamin Jakobus and Jason Marah
Table of Contents (6 chapters)

Chapter 8. Working with JavaScript

The whole Internet would not have been the same without JavaScript, and so is Bootstrap. The JavaScript plugins from Bootstrap account for a chunk of Bootstrap's success. By having them, Bootstrap has allowed all of us to use modals, alerts, tooltips, and other plugins out of the box.

Therefore, the main focus of this chapter is to explain the main Bootstrap JavaScript plugins by using them in our web application. In the previous chapters, we used a few plugins. The purpose of this chapter is to go deep into this subject. The key points that we will cover now are:

  • General usage of Bootstrap JavaScript plugins
  • Data attributes
  • Modals
  • Tooltips
  • Popover
  • Affix

Understanding JavaScript plugins

As I said, Bootstrap offers a lot of JavaScript plugins. They all come together when we download the framework, and all of them are ready for use when the bootstrap.js file is loaded in HTML, although each plugin can be downloaded individually as well from the Bootstrap website.

Tip

Minifying JavaScript

In the production stage, you can use the minified version of Bootstrap JavaScript. We are not using that right now for learning purposes, but it is recommended that you use the minimal version when you go live.

The library dependencies

While we were setting up our development environment, we spoke about the need to import the jQuery library. Actually, jQuery is now the only required external dependency for Bootstrap.

Check out the bower.json file in the Bootstrap repository for further information about dependencies.

Tip

Bower

Bower is a package management control system for client-side components. To use Bower, you must have both Node and npm installed. Bower was developed by the developers of Twitter.

Data attributes

HTML5 introduced the idea of adding custom attributes to document tags in order to store custom information. Therefore, you can add an attribute to a tag with the data-* prefix, retrieve the information in JavaScript, and not get started with some plugin in your browser. An overwhelming majority of web browsers do support the use of custom data attributes.

With that ideology, Bootstrap implemented all the plugins to be used with just data attributes. This goes towards the framework idea to increase the speed of development and prototyping. This is because you can make use of plugins without typing JavaScript code.

To control that methodology, Bootstrap implemented an API so that you can access all plugins through only data attributes. Sometimes, however, you may want to turn off access through the API. To do so, insert the following command at the beginning of your JavaScript code:

$(document).off('.data-api');

To disable the API for some specific plugins, prepend the plugin namespace. For instance, to disable the alerts API, type this:

$(document).off('.alert.data-api');

Bootstrap JavaScript events

There is a set of events that Bootstrap produces for each plugin. They are triggered usually before and after the event starts. To exemplify this, let's say that we have a Bootstrap modal (you will learn about using modals in this chapter; don't worry) and we will call it to open by JavaScript:

$('#some-modal').modal();

When this happens, Bootstrap triggers the events called show.bs.modal and shown.bs.modal. The first one is called before the open modal call and the other is called after the action. Let's say we want to customize our modal before it is shown. To do this, we must use the first event:

$('#some-modal').on('shown.bs.modal', function(e) {
  // do some customization before shown
});

The events can be used for all plugins. Just change the namespace (in this case, .modal is the namespace) to achieve the result.

Awesome Bootstrap modals

It's time to learn how to use modals! Modals are really present nowadays in web development and Bootstrap plugins, for that is really complete and easy to use. To use it, let's go back to our main web application page, the one containing the feeds.

First, we add the .hide helper class to the div.alert that we created at the #main column. We will play with alerts later. Now, go to the #tweet button on the navigation bar. We want to open a modal for tweets when clicking on this button. So, add the markup to the element:

<!-- modal launch button -->
<button id="tweet" class="btn btn-default pull-right visible-xs-block" data-toggle="modal" data-target="#tweet-modal">
  <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
  Tweet
</button>

What we did is the call to open a modal, recognized by the #tweet-modal ID and the data-toggle="modal" data attribute. We could also have done that via JavaScript with this code:

$('#tweet-modal').modal();

Create the modal by adding the next HTML code. We have created all the modals at the end of our HTML code, outside of all Bootstrap elements and right before the loading of the JavaScript libraries:

<div class="modal fade" id="tweet-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        Modal content
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
        <button type="button" class="btn btn-primary">
          Save changes
        </button>
      </div>
    </div>
  </div>
</div>

Reload the web application, click on the Tweet button and see the magic happen! This code is a little more complex, so let's explain each part separately. The following screenshot shows what the first draft of our modal looks like. Now let's understand what we did.

Awesome Bootstrap modals

Modal general and content

The first tag used to initiate a modal is a <div> with the .modal class. Note that we also added the .fade class to create the effect of fade in and fade out when the modal appears and disappears.

Inside the .modal element, we created two more nested tags. The first one is .modal-dialog, which will wrap all of the modal dialog. Inside it, we created .modal-content, which will hold the content of the modal itself.

The modal header

Next, inside .modal-content we have the .modal-header element. In the modal header, we can add some title information about the modal. In our example, we have also added a close button that hides the modal using a data-dismiss="modal" data attribute.

The modal body

The modal body is where you should place the main content of the modal. A cool feature inside the modal is the ability to use scaffolding.

To use the grid system inside the modal body, you do not need to create a container. Just create a .row inside .modal-body and start adding columns, as shown in the following example in bold:

<div class="modal fade" id="tweet-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <div class="row">
          <div class="col-sm-2">Use</div>
          <div class="col-sm-4">the</div>
          <div class="col-sm-6">grid system</div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
        <button type="button" class="btn btn-primary">
          Save changes
        </button>
      </div>
    </div>
  </div>
</div>

The modal footer

At the end of the modal, you can create a .modal-footer element to place some other components, such as buttons, as we did in the previous example.

Modal general and content

The first tag used to initiate a modal is a <div> with the .modal class. Note that we also added the .fade class to create the effect of fade in and fade out when the modal appears and disappears.

Inside the .modal element, we created two more nested tags. The first one is .modal-dialog, which will wrap all of the modal dialog. Inside it, we created .modal-content, which will hold the content of the modal itself.

The modal header

Next, inside .modal-content we have the .modal-header element. In the modal header, we can add some title information about the modal. In our example, we have also added a close button that hides the modal using a data-dismiss="modal" data attribute.

The modal body

The modal body is where you should place the main content of the modal. A cool feature inside the modal is the ability to use scaffolding.

To use the grid system inside the modal body, you do not need to create a container. Just create a .row inside .modal-body and start adding columns, as shown in the following example in bold:

<div class="modal fade" id="tweet-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <div class="row">
          <div class="col-sm-2">Use</div>
          <div class="col-sm-4">the</div>
          <div class="col-sm-6">grid system</div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
        <button type="button" class="btn btn-primary">
          Save changes
        </button>
      </div>
    </div>
  </div>
</div>

The modal footer

At the end of the modal, you can create a .modal-footer element to place some other components, such as buttons, as we did in the previous example.

The modal header

Next, inside .modal-content we have the .modal-header element. In the modal header, we can add some title information about the modal. In our example, we have also added a close button that hides the modal using a data-dismiss="modal" data attribute.

The modal body

The modal body is where you should place the main content of the modal. A cool feature inside the modal is the ability to use scaffolding.

To use the grid system inside the modal body, you do not need to create a container. Just create a .row inside .modal-body and start adding columns, as shown in the following example in bold:

<div class="modal fade" id="tweet-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <div class="row">
          <div class="col-sm-2">Use</div>
          <div class="col-sm-4">the</div>
          <div class="col-sm-6">grid system</div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
        <button type="button" class="btn btn-primary">
          Save changes
        </button>
      </div>
    </div>
  </div>
</div>

The modal footer

At the end of the modal, you can create a .modal-footer element to place some other components, such as buttons, as we did in the previous example.

The modal body

The modal body is where you should place the main content of the modal. A cool feature inside the modal is the ability to use scaffolding.

To use the grid system inside the modal body, you do not need to create a container. Just create a .row inside .modal-body and start adding columns, as shown in the following example in bold:

<div class="modal fade" id="tweet-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <div class="row">
          <div class="col-sm-2">Use</div>
          <div class="col-sm-4">the</div>
          <div class="col-sm-6">grid system</div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
        <button type="button" class="btn btn-primary">
          Save changes
        </button>
      </div>
    </div>
  </div>
</div>

The modal footer

At the end of the modal, you can create a .modal-footer element to place some other components, such as buttons, as we did in the previous example.

The modal footer

At the end of the modal, you can create a .modal-footer element to place some other components, such as buttons, as we did in the previous example.

Creating our custom modal

Now that you have learned how to use a Bootstrap modal, let's customize it for our example. First, let's add some content inside our .modal-body and edit .modal-header and .modal-footer a little:

<div class="modal fade" id="tweet-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Dog a new tweet</h4>
      </div>
      <div class="modal-body">
        <textarea class="form-control" rows="4" placeholder="What you want to bark?" maxlength="140"></textarea>
      </div>
      <div class="modal-footer">
        <span class="char-count pull-left" data-max="140">140</span>
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
        <button type="button" class="btn btn-primary">
          Tweet
        </button>
      </div>
    </div>
  </div>
</div>

Here, we added a heading to .modal-header, a textarea in .modal-body and a <span> element with the .char-count class in the footer.

The goal here is to type a tweet inside the textarea element and update the character count in the footer to show how many characters are left for the user to enter.

For styling, go to the CSS and add a style rule for .char-count:

#tweet-modal .char-count {
  padding: 0.7rem 0;
}

Refresh the web browser and see the result of the tweet modal, as shown in the following screenshot. Now, we need to add some JavaScript to count the number of remaining characters to tweet.

Creating our custom modal

So, for the JavaScript for the character count, open (or create it if you do not have it yet) the main.js file. Ensure that you have the document ready to create the script, by having the following code in your file:

$(document).ready(function() {
    // add code here
});

Then, we must create a function that updates the remaining characters each time a letter is typed. Therefore, let's create an event handler for keyup.

The keyup event came from jQuery, which has a lot of event handlers that are triggered on different actions. There are also other events such as click, hover, and so on. In this case, keyup will trigger when you release a key that you pressed.

The basic usage to create a bind event is from a selector, call the .on function passing at the first argument of the event type (in this case, keyup), followed by the handler (in our case, a function). Here, we have presented the JavaScript code, and the event handler is in bold so as to highlight the usage:

$(document).ready(function() {
    var $charCount, maxCharCount;

    $charCount = $('#tweet-modal .char-count')
    maxCharCount = parseInt($charCount.data('max'), 10);

    $('#tweet-modal textarea').on('keyup', function(e) {
        var tweetLength = $(e.currentTarget).val().length;

        $charCount.html(maxCharCount - tweetLength);
  });
});

Note

We used the keyup event handler to trigger the event after the key is released and the character is typed. Therefore, the new length of textarea is already computed when we make a comparison.

A tool for your tip

Tooltips are a very useful component for describing in detail an element or a web page. For example, when you have an image and want to describe it further, you add a tooltip. When users hover over the image, they see further information.

In our case, we will use tooltips for the buttons present in every tweet, such as Reply, Retweet, and Start. This Bootstrap plugin component is pretty simple and useful in many cases. To start it, just add the markup in bold to the tweets in the middle column (<li> in the ul#feed element):

<ul id="feed" class="list-unstyled">
  <li>
    <img src="imgs/doge.jpg" class="feed-avatar img-circle">
    <div class="feed-post">
      <h5>Doge <small>@dogeoficial - 3h</small></h5>
      <p>You can't hold a dog down without staying down with him!</p>
    </div>
    <div class="action-list">
      <a href="#" data-toggle="tooltip" data-placement="bottom" title="Reply">
        <span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span>
      </a>
      <a href="#" data-toggle="tooltip" data-placement="bottom" title="Retweet">
        <span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
        <span class="retweet-count">6</span>
      </a>
      <a href="#" data-toggle="tooltip" data-placement="bottom" title="Start">
        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
      </a>
    </div>
  </li>

  <li>
    <img src="imgs/laika.jpg" class="feed-avatar img-circle">
    <div class="feed-post">
      <h5>Laika <small>@spacesog - 4h</small></h5>
      <p>That's one small step for a dog, one giant leap for giant</p>
    </div>
    <div class="action-list">
      <a href="#" data-toggle="tooltip" data-placement="bottom" title="Reply">
        <span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span>
      </a>
      <a href="#" data-toggle="tooltip" data-placement="bottom" title="Retweet">
        <span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
        <span class="retweet-count">6</span>
      </a>
      <a href="#" data-toggle="tooltip" data-placement="bottom" title="Star">
        <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
      </a>
    </div>
  </li>
</ul>

As you can notice, by using data attributes, you just need to add three of them to make a tooltip. The first one is data-toggle, which says the type of toggle. In our case, it is tooltip. The data-placement attribute is concerned with the placement of the tooltip (obviously). In this case, we set it to appear at the bottom, but we can set it to left, top, bottom, right, or auto. Finally, we add the title attribute, which is not a data attribute, because HTML already has the attribute title, so we can call it by this attribute.

Refresh the web app in the browser, hover the icon and you will see that… nothing happens! Unlike the other plugins, the tooltip and popover Bootstrap plugins cannot be activated simply through data attributes. They did this because of some issues, so it must be initialized through a JavaScript command. Therefore, add the following line to the main.js file:

$(document).ready(function() {
    ... // to rest of the code
    $('[data-toggle="tooltip"]').tooltip();
});

The [data-toggle="tooltip"] selector will retrieve all the tooltip elements and start it. You can also pass some options inside while calling the .tooltip() start function. The next table shows some main options (to see all of them, refer to the official documentation of Bootstrap) that can be passed through JavaScript or data attributes:

Option

Type

Default

Description

animation

Boolean

true

This adds fade in and fade out animation to a tooltip.

placement

String or function

top

This is the placement position of the tooltip. The options are the same as those mentioned for the usage with data attributes (top, bottom, left, right, and auto). You can pass auto with another option, such as auto left, which will always show the tooltip on the left as long as it is possible, and then show it on the right.

selector

String

false

If you provide a selector, the tooltip will be delegated to the specified target.

trigger

String

hover focus

The trigger to the tooltip will be shown. The options are click, hover, focus, and manual. You can pass multiple options for trigger, unless you use manual, in which case you need to write a function to activate the plugin.

The tooltip plugin also has some useful methods for doing things such as showing all tooltips. You can call them using the .tooltip() method. As mentioned, if you want to show all tooltips, just use $('.tooltip-selector').tooltip('show'). The other options are hide, toggle, and destroy.

Pop it all over

In some cases, you may want to show more information that does not fit in a simple tooltip component. For that, Bootstrap has created popovers, which are components that create small overlays of content to show detailed secondary information.

The popover plugin is an extension of the tooltip plugin, so if you are using separate plugins, you must load both to make it work. Also, just like tooltips, popovers cannot be activated simply through data attributes. You must call them via JavaScript to make them work.

Let's use a popover in our web app example, on the right-hand-side column, the one identified by div#who-follow. We will add the popover to the Follow buttons, and for that, we need to do two things. The first one is to change the <button> element to an <a> element and then add the popover markup.

Tip

Why do we need to change buttons to links in popover?

Actually, we don't have to change the buttons' markup; we will do that just because of cross-browser compatibility. There are some browsers that do not support all the functionalities, such as the click Dismiss option present in the popover.

First, about the <buttons> inside the div#who-follow element. Change them to <a> elements in the HTML. Also add the role="button" and tabindex="-1" attributes to the links to fix the issue of cross-browser compatibility:

<div id="who-follow" class="card">
  <div class="card-header">
    Who to follow
  </div>
  <div class="card-block">
    <ul class="list-unstyled">
      <li>
        <img src="imgs/cat.jpg" class="img-rounded">
        <div class="info">
          <strong>Crazy cats</strong>
          <a href="#" role="button" tabindex="-1" class="btn btn-default">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Follow
          </a>
        </div>
      </li>
      <li>
        <img src="imgs/ration.jpg" class="img-rounded">
        <div class="info">
          <strong>Free ration alert</strong>
          <a href="#" role="button" tabindex="-1" class="btn btn-default">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Follow
          </a>
        </div>
      </li>
    </ul>
  </div>

The code in bold refers to the changes from button to link. Now, we must add the popover markup. It is pretty simple and follows most of the data attributes presented in the tooltip plugin:

<div id="who-follow" class="card">
  <div class="card-header">
    Who to follow
  </div>
  <div class="card-block">
    <ul class="list-unstyled">
      <li>
        <img src="imgs/cat.jpg" class="img-rounded">
        <div class="info">
          <strong>Crazy cats</strong>
          <a href="#" role="button" tabindex="-1" class="btn btn-default" data-toggle="popover" data-trigger="focus" title="You may want to follow">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Follow
          </a>
        </div>
      </li>
      <li>
        <img src="imgs/ration.jpg" class="img-rounded">
        <div class="info">
          <strong>Free ration alert</strong>
          <a href="#" role="button" tabindex="-1" class="btn btn-default" data-toggle="popover" data-trigger="focus" title="You may want to follow">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Follow
          </a>
        </div>
      </li>
    </ul>
  </div>

Just like the popover, add the following line to the JavaScript code to make popovers appear:

$(document).ready(function() {
    … // the rest of the JavaScript
    $('[data-toggle="popover"]').popover();
});

Refresh the web browser, click on the Follow button and see the popover appearing to the right of the button. Now we will make some changes using the options to customize it. First of all, let's create the content that will appear inside the popover and change its placement in JavaScript:

$(document).ready(function() {
    … // rest of the JavaScript
    var popoverContentTemplate = '' +
        '<img src="imgs/breed.jpg" class="img-rounded">' +
        '<div class="info">' +
            '<strong>Dog Breeds</strong>' +
            '<a href="#" class="btn btn-default">' +
                '<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>' +
                'Follow' +
            '</a>' +
        '</div>';

    $('[data-toggle="popover"]').popover({
        placement: 'bottom',
        html: true,
        content: function() {
            return popoverContentTemplate;
        }
    });
});

In the preceding code, we changed the placement of the popover to bottom and set the content that will appear inside the popover to be HTML with the html: true option. The content was provided by a function that simply returned the popoverContentTemplate variable.

For instance, we could have used the template in very different ways that are more optimized, but we did this to show the method of adding HTML content onto a popover via JavaScript and using a function for that. We could have called and used some options of the target clicked button inside the function by accessing the current scope in the this variable.

Popover events

Popovers and tooltips provide some nice events. As was said before, Bootstrap triggers some events when plugin elements appear, hide, and are inserted. To play with these, let's use the show.bs.popover event, which is an event that is fired immediately when the popover is show. In this case, we want to create an action before the popover is show. We want to change the text of the Follow button that we clicked on to Following, while changing the icon next to the text from a plus sign to an okay sign. We can take advantage of the show.bs.popover Bootstrap event to make these changes. In the JavaScript file, insert the following delegation to the popovers:

$(document).ready(function() {
    … // the rest of the JavaScript code
    $('[data-toggle="popover"]').on('show.bs.popover', function() {
        var $icon = $(this).find('span.glyphicon');

        $icon.removeClass('glyphicon-plus').addClass('glyphicon-ok');
        $(this).append('ing');
    });
});

The scope of this event is the element of data-toggle, which is the Follow button. We query the icon inside the button, and change it from glyphicon-plus to glyphicon-ok. Finally, we append the infinitive ing to Follow, which means that we are now following Crazy cats or Free ration alert suggestions:

To add a cherry to the pie, let's change the color of the icon from blue to green when the okay icon appears:

div#who-follow li .info .glyphicon-ok {
  color: #5cb85c;
}

Refresh the web browser and click on the Follow button. You should see something similar to this screenshot:

Popover events

There are many other places where the Bootstrap events can be used. This is a nice example where we want to change the element that we are interacting with. Keep in mind to change it whenever you need some related interaction.

Popover events

Popovers and tooltips provide some nice events. As was said before, Bootstrap triggers some events when plugin elements appear, hide, and are inserted. To play with these, let's use the show.bs.popover event, which is an event that is fired immediately when the popover is show. In this case, we want to create an action before the popover is show. We want to change the text of the Follow button that we clicked on to Following, while changing the icon next to the text from a plus sign to an okay sign. We can take advantage of the show.bs.popover Bootstrap event to make these changes. In the JavaScript file, insert the following delegation to the popovers:

$(document).ready(function() {
    … // the rest of the JavaScript code
    $('[data-toggle="popover"]').on('show.bs.popover', function() {
        var $icon = $(this).find('span.glyphicon');

        $icon.removeClass('glyphicon-plus').addClass('glyphicon-ok');
        $(this).append('ing');
    });
});

The scope of this event is the element of data-toggle, which is the Follow button. We query the icon inside the button, and change it from glyphicon-plus to glyphicon-ok. Finally, we append the infinitive ing to Follow, which means that we are now following Crazy cats or Free ration alert suggestions:

To add a cherry to the pie, let's change the color of the icon from blue to green when the okay icon appears:

div#who-follow li .info .glyphicon-ok {
  color: #5cb85c;
}

Refresh the web browser and click on the Follow button. You should see something similar to this screenshot:

Popover events

There are many other places where the Bootstrap events can be used. This is a nice example where we want to change the element that we are interacting with. Keep in mind to change it whenever you need some related interaction.

Making the menu affix

The affix plugin is present only in version 3 of Bootstrap (it was removed in version 4), and it aims to toggle the position of an element between fixed and relative, emulating the effect of position: sticky, which is not present in all browsers.

We will apply the sticky effect the left #profile element although we do not have enough elements to make a scroll on our web page. Therefore, to make it simple, replicate the <li> in ul#feed to increase the number of items in the list. Do this three times or more to make a scroll in your web browser.

In div#profile, add the markup related to affix:

<div id="profile" class="col-md-3 hidden-sm hidden-xs" data-spy="affix" data-offset-top="0">
    …
    // rest of the profile HTML
</div>

Refresh the web browser. You will see that the affix is not working yet. Since we are making the left column with a fixed position with the affix plugin, it is removing the entire column from the grid, making the columns glitch from left to right.

So, we need a workaround for that. We must create some piece of JavaScript code using the events triggered for the plugin.

Let's use the affix.bs.affix event, which is an event fired just before the affixing of the element:

$(document).ready(function() {
    … // rest of the JavaScript code

    $('#profile').on('affix.bs.affix', function() {
        $(this).width($(this).width() - 1);
        $('#main').addClass('col-md-offset-3');
    }).on('affix-top.bs.affix', function() {
        $(this).css('width', '');
        $('#main').removeClass('col-md-offset-3');
    });
});

Thus, we have played with some tricks in the preceding JavaScript code.

In the first delegated event, .on('affix.bs.affix', handler),when the element switches to position: fixed, we keep the width of the left column. It would change the width because the .col-md-3 class does not have a fixed width; it uses a percentage width.

We also added the offset to the middle column, corresponding to the detached left column, the .col-md-offset-3 class.

The affix-top.bs.affix event does the opposite action, firing when the element returns to the original top position and removing the custom width and the offset class in the middle column.

To remove the fixed width and return to the .col-md-3 percentage width, just add the $(this).css('width', '') line. Also remove the .col-md-offset-3 class from the #main content.

Refresh the web browser, scroll the page, and see the result, exemplified in the next screenshot. Note that the profile is fixed on the left while the rest of the content scrolls with the page:

Making the menu affix

Finishing the web app

To finish the web application example, we just need to create another modal when we click on the Messages link at the navigation bar.

To create it, we will use the same methodology used to create the modal for the Tweet button. So, add the data attributes' markups to the Messages link in .nav.navbar-nav, as follows:

<ul class="nav navbar-nav">
  <li class="active">
    <a href="#">
      <span class="glyphicon glyphicon-home" aria-hidden="true"></span>
      Home
    </a>
  </li>
  <li>
    <a href="#">
      <span class="badge">5</span>
      <span class="glyphicon glyphicon-bell" aria-hidden="true"></span>
      Notifications
    </a>
  </li>
  <li>
    <a href="#" role="button" data-toggle="modal" data-target="#messages-modal">
      <span class="glyphicon glyphicon-envelope" aria-hidden="true"></span>
      Messages
    </a>
  </li>
  <li class="visible-xs-inline">
    <a href="#">
      <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
      Profile
    </a>
  </li>
  <li class="visible-xs-inline">
    <a href="#">
      <span class="glyphicon glyphicon-off" aria-hidden="true"></span>
      Logout
    </a>
  </li>
</ul>

The highlighted code says that this link plays the role button, toggling a modal identified by the #messages-modal ID. Create the base of this modal at the end of the HTML code, just after #tweet-modal:

<div id="messages-modal" class="modal fade" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Dog messages</h4>
        <button type="button" class="btn btn-primary btn-message">New message</button>
      </div>
      <div class="modal-body">
      </div>
    </div>
  </div>
</div>

We made some changes in comparison to #tweet-modal. Firstly, we removed .modal-footer from this modal, since we do not need these options in the modal. Like almost the entire framework, Bootstrap allows us to include or exclude elements as per our wishes.

Secondly, we created a new button, New message, in the header, identified by the .btn-message class. To present the button correctly, create the following CSS style:

#messages-modal .btn-message {
  position: absolute;
  right: 3em;
  top: 0.75em;
}

Now let's create the content inside the modal. We will add a list of messages in the modal. Check out the HTML with the content added:

<div class="modal fade" id="messages-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Dog messages</h4>
        <button type="button" class="btn btn-primary btn-message">New message</button>
      </div>
      <div class="modal-body">
        <ul class="list-unstyled">
          <li>
            <a href="#">
              <img src="imgs/laika.jpg" class="img-circle">
              <div class="msg-content">
                <h5>Laika <small>@spacesog</small></h5>
                <p>Hey Jonny, how is down there?</p>
              </div>
            </a>
          </li>
          <li>
            <a href="#">
              <img src="imgs/doge.jpg" class="img-circle">
              <div class="msg-content">
                <h5>Doge <small>@dogeoficial </small></h5>
                <p>Wow! How did I turned in to a meme?</p>
              </div>
            </a>
          </li>
          <li>
            <a href="#">
              <img src="imgs/cat.jpg" class="img-circle">
              <div class="msg-content">
                <h5>Cat <small>@crazycat</small></h5>
                <p>You will never catch me!</p>
              </div>
            </a>
          </li>
          <li>
            <a href="#">
              <img src="imgs/laika.jpg" class="img-circle">
              <div class="msg-content">
                <h5>Laika <small>@spacesog</small></h5>
                <p>I think I saw you in Jupiter! Have you been there recently?</p>
              </div>
            </a>
          </li>
        </ul>
      </div>
    </div>
  </div>
</div>

To finish our job, we just create some style in the CSS in order to display our list correctly:

#messages-modal .modal-body {
  max-height: 32rem;
  overflow: auto;
}

#messages-modal li {
  padding: 0.75rem;
  border-bottom: 0.1rem solid #E6E6E6;
}

#messages-modal li:hover {
  background-color: #E6E6E6;
}

#messages-modal li a:hover {
  text-decoration: none;
}

#messages-modal li img {
  max-width: 15%;
}

#messages-modal .msg-content {
  display: inline-block;
  color: #000;
}

#messages-modal .msg-content h5 {
  font-size: 1em;
  font-weight: bold;
}

In this CSS, we simply set a maximum height for the modal body, while adding a scroll overflow. For the list and the link, we changed the style for hover and adjusted the font weight, size, and color for display.

Refresh the web browser, click on the Messages link in the navigation bar and see your nice modal, as follows:

Finishing the web app

Summary

In this chapter, we finished our web application example. The main objective here was to learn about the Bootstrap plugins that we had not described before.

First, you learned about data attributes and how to use them with Bootstrap. After that, we saw both the possible ways to call plugins: via pure JavaScript or just through data attributes APIs.

We started and finished plugins with modals. Modals are one of the main plugins in Bootstrap because they are very versatile and customizable. Thus, they are fit for multiple contexts where you need some interaction with the user but do not want to move to another page.

In the middle of the chapter, we talked about two plugins that are closely related. They are the tooltip and the popover. Both came from the same initial plugin but with different contexts. Tooltips are used for auxiliary content, and popovers are something midway between a modal and a tooltip, so they can display more content compared to tooltips, but not too much intrusive like modals.

Creating a web application that is Twitter-like is an important kind of knowledge, since this can be replicated to different sources. Web applications have revolutionized the Web in different ways, and Bootstrap has taken the lead by helping us create faster and more beautiful web pages.

In the next chapter, we will step into an even more challenging example—we will build a dashboard web application from scratch! Just like the web application presented in this chapter, web dashboards are very popular across the Internet, and building one will place us at the same stratum as some of the best web developers. Ready for the advanced level?