Customizing Bootstrap’s jQuery alert plugin

The alert plugin, as we have seen, is exceedingly simple. The alert is rendered on the page, displaying a message, and the only functionality it has is the ability to close and disappear when a user clicks on a certain element.

To demonstrate how to customize or extend a plugin, in this case, alert we will keep it very simple. We will add an extra bit of functionality—when a user clicks on a certain element, the alert will minimize. Similarly, we also want to give the user the ability to expand the alert when it is in its minimized state. To do this, we need to extend both the JavaScript and the styling of alert.

Before we get to the coding of the plugin functionality and styling, let’s put together the markup for an alert on the MyPhoto page.

1. The markup

As an example use case, let’s display an alert informing the user of a special offer. We will add our alert above the unsupported browser alert:

<div class=”alert alert-info” style=”position: fixed; margin-top:

4em; width: 90%;margin-left: 4em;”>

<a href=”#” class=”close” data-dismiss=”alert”

aria-label=”close”>&times;</a>

<strong><i class=”fa fa-exclamation”></i> Special Offer –

</strong>

2 FOR 1 PRINTS TODAY ONLY WITH PROMO CODE <span style=”font-

style: italic”>BOOTSTRAP</span>

</div>

We’re using Bootstrap’s contextual information class, alert-info, to style the alert box, and we’re following the same pattern as the unsupported browser alert. The special offer alert has inline styles applied, and the unsupported browser alert has styles linked to its alert-myphoto class. Before we go any further, let’s extract that out into a single class in myphoto.css for reusability and maintainability. Remove the .alert-myphoto rules and add the following:

.alert-position {

position: fixed;

margin-top: 4em;

width: 50%;

margin-left: 25%;

z-index:   10;

}

#unsupported-browser-alert {

display:none;

}

We’ve made some slight changes here. The alert will now have a hard-set width of 50% of the viewport and will be rendered 25% from the left. To ensure that the alert is always rendered above any other content on the page, we set z-index to 10. As long as no other elements have a higher z-index, the alert will always be visible. Now, we remove the inline styles on the alert elements and add the alert-position class. We extend the class slightly for elements with the unsupported-browser-alert ID to ensure that it isn’t displayed. Update the alert elements with the alert-position class, and add id=”unsupported-browser-alert” to the unsupported browser alert root:

<div class=”alert alert-info alert-position”>

</div>

<div class=”alert alert-danger alert-dismissible fixed-top” id=”unsupported-browser-alert”>

</div>

Take a look at the following screenshot for our new alert:

Figure 6.1: A modified alert used to display special promotions; unlike the default alert, this alert has its width hard-set to 50% of the viewport and will be rendered 25% from the left (example01.html)

Now that we have our special offers alert, we can add our minimize and expand elements. We want these elements to function and display similar to the close element, so we can use the close element as a template. Observe the following code:

<a href=”#” class=”close” data-dismiss=”alert”

aria-label=”close”>&times;</a>

<a href=”#” class=”close minimize” data-minimize=”alert”

aria-label=”minimize”>_</a>

<a href=”#” class=”close expand” data-expand=”alert”

aria-label=”expand”>+</a>

We have replicated the close element twice. We have added a minimize and an expand class, while retaining the close element, as we want to inherit everything the close class includes. We have added new data attributes—instead of data-dismiss, we have data- minimize and data-expand. These are the data attributes that the plugin will listen to. We then updated the aria-label with the appropriate names, and applied appropriate content inside the element—an underscore ( _ ) to indicate minimization and a plus (+) to indicate expansion (refer to Figure 6.2). Take a look at the following screenshot:

Figure 6.2: Our custom promotion alert with the expand and minimize functionalities (example01.html)

Besides the close button, we now have the expand and minimize buttons. We don’t want to show the expand button when the alert is already expanded, and we don’t want to show the minimize button when the alert is already minimized. As the alert is expanded by default, we ‘ll add a d-none class to the expand element. Recall that d-none hides a given element for all viewports; d-none is the equivalent of hide in Bootstrap 3. Observe the following code:

<a href=”#” class=”close” data-dismiss=”alert”

aria-label=”close”>&times;</a>

<a href=”#” class=”close minimize” data-minimize=”alert”

aria-label=”minimize”>_</a>

<a href=”#” class=”close expand d-none” data-expand=”alert”

aria-label=”expand”>+</a>

Take a look at figure 6.3—the expand control will now be hidden:

Figure 6.3: Our custom promotion alert with the expand element hidden (example02.html)

Now that the alert has the desired appearance, we are ready to customize the styling of the alert plugin.

2. Extending alert’s style sheets

As we mentioned earlier, it is bad practice to modify Bootstrap’s Sass files directly, due to maintenance issues. Instead, we will create our own style sheet—styles/alerts.css.

Before we create any new classes, we should extract any alert-related CSS from myphoto.css into this new style sheet in order to improve code maintainability. The only classes we have so far are alert-danger and alert-position. Place them into our new alert-specific style sheet, and include the stylesheet in our HTML. Ensure that you include it after bootstrap.min.css and myphoto.css to ensure that the style rules in alert.css take priority. Observe the following code:

<link rel=”stylesheet” href=”node_modules/bootstrap/dist/css

/bootstrap.min.css” />

<link rel=”stylesheet” href=”styles/myphoto.css” />

<link rel=”stylesheet” href=”styles/alert.css” />

To create the ability to minimize and expand an alert, we actually do not need many style rules at all. In fact, we will use just one new class—alert-minimize. When a user clicks on the minimize button, the alert-minimize class will be applied to the root alert element. To expand it, the alert-minimize class will simply be removed.

Update alert.css with the following rules:

.alert-minimize {

width: 100px;

}

.alert-minimize * {

display: none;

}

.alert-minimize.close {

display: block;

}

The alert-minimize class will force a 100px element width. All descendants of the alert-minimize class will be given the display value of none so that they do not appear on screen. To ensure that the functional buttons are still visible, any element with the close class (remember that we retained the close class for all our functional buttons in the alert) will be given the display value of block. Let’s manually apply alert-minimize to our alert to see how it renders. Take a look at this screenshot:

Figure 6.4: Our minimized custom promotion alert

Next up, let’s remove the alert-minimize class and extend the alert plugin JavaScript to apply and remove the class dynamically.

3. Extending alert’s functionality with JavaScript

As with extending the styles, to extend the JavaScript, we can modify Bootstrap’s alert.js directly, but again, that is a bad idea in terms of maintainability. Instead, we will create a js directory in our project, and a file called alert.js. Include this file in your HTML, after bootstrap.min.js:

<script

src=”node_modules/bootstrap/dist/js/bootstrap.min.js”>

</script>

<script src=”js/alert.js”></script>

The first thing we will do is to create an immediately invoked function and add the function to the jQuery object:

+function ($) {

‘use strict’;

var Alert = $.fn.alert.Constructor;

}(jQuery);

The function assigns an Alert variable to the alert plugins prototype—which as we saw earlier, is made available through the Constructor property.

With this reference to the Alert prototype, we can add our own functions to the prototype to handle minimizing and expanding an alert. Taking the close function we studied earlier, and with a few changes, let’s create a function to minimize the alert:

Alert.prototype.minimize = function (e) {

var $this = $(this)

var selector = $this.attr(‘data-minimize’) if (!selector) {

selector = $this.attr(‘href’)

selector = selector && selector.replace(/.*(?=#[^\s]*$)/,

”)

// strip for ie7

}

$this.addClass(‘d-none’)

$this.siblings(‘.expand’).removeClass(‘d-none’)

var $parent = $(selector)

if (e) e.preventDefault()

if (!$parent.length) {

$parent = $this.closest(‘.alert’)

}

$parent.trigger(e = $.Event(‘minimize.bs.alert’))

if (e.isDefaultPrevented())

return $parent.addClass(‘alert-minimize’)

}

The function is quite similar to the close function, so we will highlight the important differences. Line 15 and 16 handle hiding the minimize button and showing the expand button, adding the d-none class to the element that triggered the event, and removing the d-none class from any sibling element with the expand class. Line 30 adds the alert- minimize class, which handles the shrinking of the Alert element, to the parent of the element that triggered the event. Essentially, the minimize function will shrink the alert, hide the minimize button, and show the expand button. Let’s hook up a listener to this function.

We do this in the same way as the Bootstrap alert plugin links the data—dismiss the click event to the close function, adding the following to alert.js below the minimize function definition:

$(document).on(‘click.bs.alert.data-api’,

‘[data- minimize=”alert”]’, Alert.prototype.minimize)

Now, an element with the data-minimize attribute with an “alert” value will call the Alert.prototype.minimize function on a click event. The minimize element in our special offers alert has this attribute. Open up MyPhoto and click on the minimize button. Take a look at the screenshot in figure 6.5:

Figure 6.5: Our minimized custom promotion alert—note the expand and close buttons (example02.html)

That’s excellent. Our minimize button and functionality are wired up correctly to shrink our special offers alert and replace the minimize button with an expand button when clicked on.

The last thing we need to do now is ensure that the user can expand the alert when they click on the expand button. To do this, we follow the same steps as we did for the minimize functionality. Let’s add an expand function to the Alert prototype:

Alert.prototype.expand = function (e) {

var $this = $(this)

var selector = $this.attr(‘data-expand’)

if (!selector) {

selector = $this.attr(‘href’)

selector = selector && selector.replace(/.*(?=#[^\s]*$)/,

”)

// strip for ie7

}

$this.addClass(‘d-none’)

$this.siblings(‘.minimize’).removeClass(‘d-none’)

var $parent = $(selector)

if (e) e.preventDefault()

if (!$parent.length) {

$parent = $this.closest(‘.alert’)

}

$parent.trigger(e = $.Event(‘expand.bs.alert’))

if (e.isDefaultPrevented())

return $parent.removeClass(‘alert-minimize’)

}

The differences between the expand and minimize functions are very small, so small that it probably makes sense for them to be encapsulated into one function. However, for the sake of simplicity, we will keep the two functions separate. Essentially, the actions of minimize are reversed. The d-none class is again applied to the element triggering the event, the d-none class is removed from any sibling with the minimize class, and the alert-minimize class is removed from the parent element. This is simple and effective. Now, we just need to hook up a click event on an element with the data-expand attribute set to alert to the expand method. Observe the following code:

$(document).on(‘click.bs.alert.data-api’, ‘[data-expand=”alert”]’,

Alert.prototype.expand)

That’s it. With our extension to the alert plugin, when a user clicks on expand in the minimized state, the alert reverts to its initial expanded state, and the expand button is replaced by the minimize button. Our users now have the ability to reduce the screen real estate our alert covers but are still able to retrieve the information from the alert at a later stage if needed.

While these alert customizations are relatively simple, they do provide a strong example of how to extend a plugin’s functionality and teach principles that can be applied to more complex extensions.

In summary, our complete code is as follows:

+ function($) {

‘use strict’;

var Alert = $.fn.alert.Constructor;

Alert.prototype.minimize = function(e) {

var $this = $(this)

var selector = $this.attr(‘data-minimize’)

if (!selector) {

selector = $this.attr(‘href’)

selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ”)

// strip for ie7

}

$this.addClass(‘d-none’)

$this.siblings(‘.expand’).removeClass(‘d-none’)

var $parent = $(selector)

if (e) e.preventDefault()

if (!$parent.length) {

$parent = $this.closest(‘.alert’)

}

$parent.trigger(e = $.Event(‘minimize.bs.alert’))

if (e.isDefaultPrevented()) return $parent.addClass(‘alert-

minimize’)

}

Alert.prototype.expand = function(e) {

var $this = $(this)

var selector = $this.attr(‘data-expand’)

if (!selector) {

selector = $this.attr(‘href’)

selector = selector && selector.replace(/.*(?=#[^\s]*$)/,

”) // strip for ie7

}

$this.addClass(‘d-none’)

$this.siblings(‘.minimize’).removeClass(‘d-none’)

var $parent = $(selector)

if (e) e.preventDefault()

if (!$parent.length) {

$parent = $this.closest(‘.alert’)

}

$parent.trigger(e = $.Event(‘expand.bs.alert’))

if (e.isDefaultPrevented()) return $parent.removeClass(‘alert- minimize’)

}

$(document).on(‘click.bs.alert.data-api’, ‘[data- minimize=”alert”]’, Alert.prototype.minimize)

$(document).on(‘click.bs.alert.data-api’, ‘[data-expand=”alert”]’, Alert.prototype.expand)

}(jQuery);

The accompanying markup is this:

<div class=”alert alert-info alert-position”>

<a href=”#” class=”close” data-dismiss=”alert”

aria- label=”close”>&times;</a>

<strong><i class=”fa fa-exclamation”></i> Special Offer -</strong>

2 FOR 1 PRINTS TODAY ONLY WITH PROMO CODE

<span style=”font-style: italic”>BOOTSTRAP</span>

</div>

Source: Jakobus Benjamin, Marah Jason (2018), Mastering Bootstrap 4: Master the latest version of Bootstrap 4 to build highly customized responsive web apps, Packt Publishing; 2nd Revised edition.

Leave a Reply

Your email address will not be published. Required fields are marked *