Like pretty much every programming language, the first thing I ever learned how to do with JavaScript was create a "Hello World" program. I followed a tutorial I found on the Oracle website which looked like this.

JavaScript Hello World

alert("Hello World!");

21 characters to write "Hello World" in JavaScript. You could even shave it down to 20 if your moral compass will allow you to leave off the semicolon, and you drop the exclamation point. If that doesn't speak volumes about how easy it is to write apps with JavaScript, I'm just not sure what does.

I learned an important lesson that day: JavaScript alerts are AMAZING!.

Alert Abuse

The ONLY thing I took from that tutorial was that I could create a modal window in JavaScript with virtually zero effort on my part. What transpired next was several years of flagrant "alert abuse". I put alerts everywhere. Alerts, prompts, confirms - you name it. Debugging, validation, errors, warnings, success; I had an alert for every occasion. I even created alerts to tell you that I was about to alert you. I turned the JavaScript alert into an art form.

I wasn't the only one though! Remember days when you would end up on a website and you would literally be held hostage by alerts? One right after the other blocking the entire browser UI. They were always oddly phrased questions asking you in a reverse way if you wanted a toolbar extension. No matter how I answered, I always ended up with a toolbar extension. I had a lot of toolbar extensions.

Over the years, we've realized that JavaScript alerts really just don't have a good place in modern applications. Several browser vendors have even gone so far as to curtail alerts completely. Consider Google Chrome who allows the end user to block all alerts after the first one.

Alerts can be dangerous if overused. Additionally, they are not going to win you any design awards. However, they do have a place. There was outrage earlier this year when Apple either intentionally or inadvertently removed alerts from Home Screen webapps in iOS 7.

The problem is that alerts are incredibly obtrusive. They lock the entire browser demanding your attention. You cannot ignore them. If an alert is opened on a an inactive tab, it will immediately come to the front and you will not be doing anything else until you actively dismiss it. This is commonly seen with banking websites which have a session timeout period and is generally referred to as "stealing the focus". This is one of the most disruptive things you can do to a user.

So what do you do when you need to give the user an alert? Sometimes you do need to stop your user and give them a message; let them know that they have been logged out, or that some other critical action has taken place. It is possible to do it though without being a jerk?

The First Rule Of Alerts Is:

Don't use a JavaScript alert if you can avoid it.

That means that you pick some other method of feedback. For instance, if you are a bank and a user's session expires, there is no need to alert them that you are about to log them out. They have no choice in the matter, so just get on with it already. It would be nice if you put a message on the login screen explaining that they have been logged out for their own safety. There is no reason to steal their focus. They will see the message when they come back to the tab to resume their banking activities.

But If You Must Alert, Remember:

Don't use a JavaScript alert if you can avoid it.

If you find that you must have an alert, there is a still a strong argument to be made that you shouldn't use the built-in JavaScript one. An alternative is to create your own alert using a JavaScript UI framework and modal window.

Nearly every JavaScript UI framework includes a modal window of some sort. These windows use div overlays to block interaction with the page. There are several reasons why these widgets are better than the browser's native alert...

  1. They do not lock the entire browser, only preventing interaction with the viewport
  2. They are far more customizable
  3. They are (generally) much nicer looking

Many jQuery libraries offer a modal window, including Kendo UI, Telerik HTML5 and JavaScript framework. One trick that you can use with Kendo UI is to create a modal window on the fly. This means that you don't actually have to have an element in the page to turn into an alert. You can do this, but you have to be very careful with it, and I'll explain why in a moment.

Disclaimer: Do not do this. This is bad. Make sure you read why bad.

On The Fly Kendo UI Window: BAD

// attach kendoAlert to the window
window.kendoAlert = function(msg) {

  // create modal window on the fly
  var win = $("<div>").kendoWindow({
    modal: true 
  }).getKendoWindow();

  // set the content
  win.content(msg);

  // center it and open it
  win.center().open();
};

$(function() {
  // call the alert on button click
  $("#open").on("click", function() {
    kendoAlert("Hey Now!");
  });
});

View Demo

This will give you a modal window on the fly with your message as the content. That div is created by jQuery, appended to the body and then the modal window is displayed. It all sounds wonderful until you realize that everytime you click the button, a new <div> with markup gets added to the page. Yikes! You don't need a new window everytime, you just want to reuse the same one.

Window Re-use With Closures

You should instead create the window once and then use the same one over and over again. This can be done by using a closure. The concept of closures can easily get you super confused. A closure is when you use an outer function to lock in the state for an inner function. To avoid sending you down the rabbit hole and for the sake of what we're going to do here, let’s put it like this: Let’s say function A creates function B – function B has access to all the variables/state that were around when function A created B… even if function A returns function B to something else and that something else invokes it later.

What we'll do is create that outer function which executes itself (IIFE). When it executes it will create the modal window and store a reference to it. It will then return a function which sets the content, and then opens the window. This inner/outer function relationship is the closure.

Closure

// attach kendoAlert to the window
window.kendoAlert = (function() {

  // this function is executed as soon as
  // it is loaded into the browser

  // create modal window on the fly and 
  // store it in a variable
  var win = $("<div>").kendoWindow({
    modal: true 
  }).getKendoWindow();

  // returning a function will set kendoAlert to a function
  return function(msg) {

    // anything inside this function has access to the `win`
    // variable which contains the Kendo UI Window.  Even WAY
    // after the outer function was run and this object was created

    // set the content
    win.content(msg);

    // center it and open it
    win.center().open();
  };

}());

$(function() {
  // open the window on button click
  $("#open").on("click", function() {
    kendoAlert("Hey Now!");
  });
});

If you're rather new to JavaScript and the above concept is incredibly confusing, don't for one second feel bad. It IS incredibly confusing, but after you get used to leveraging closures to encapsulate your code, it will start to feel very natural. It's actually quite a powerful concept, but it's a brain bender the first time you try and soak it in.

Asynchronous-icity

One of the nice things about the built-in JavaScript alert is that - unlike virtually anything else in JavaScript - it's synchronous. It's completely blocking, and no other code will execute until it's been dismissed. Once you begin to use a JavaScript modal window replacement, you lose this incredibly valuable pause in execution.

In our current implementation of the Kendo UI Window, any code that occurs after a call to kendoAlert will get executed immediately. The browser could care less if our custom modal window is open or closed, dead or alive. It's going to execute the code to open the window and then go right on processing any subsequent JavaScript. If we want some action to occur after the user has dismissed the alert, we need to handle that ourselves.

But how on earth do you turn asynchronous code into a syncronous operation? We have two options here...

  1. Callbacks
  2. Promises

Callbacks

Callbacks are the oldest trick in the book for making two operations synchronous. The concept plays out like this...

  1. You call Operation 1 and send it a function you want executed on completion of Operation 1
  2. Operation 1 fires an event when it is finished
  3. Operation 1 finished event calls the function you passed in - the callback

In the case of the modal window, Kendo UI Windows will call a deactivate event when they have been dismissed and have finished their closing animation. What we want to do is specify a function for that Kendo UI Window to call when it's deactivated event is fired. Since we are reusing the same window over and over again, we have to bind to the deactivate event at the time we call kendoAlert.

// attach kendoAlert to the window
window.kendoAlert = (function() {

  // create modal window on the fly
  var win = $("<div>").kendoWindow({
    modal: true 
  }).getKendoWindow();

  return function(msg, deactivate) {

    // set the content
    win.content(msg);

    // if a deactivate function was passed
    if (deactivate) {
      win.bind("deactivate", deactivate);
    }
    // otherwise unbind the deactivate event
    else {
      win.unbind("deactivate", deactivate);
    }

    // center it and open it
    win.center().open();
  };

}());

$(function() {
  $("#open").on("click", function() {
    // open the alert
    kendoAlert("Hey Now!", function() {
      // change the body background color after
      // the alert is dismissed
      $("body").css("background-color", "salmon");
    });
  });
});

Callbacks have been around for a very long time. Since JavaScript is rather functional in nature, we can pass functions around like this and it's perfectly acceptable. That is at least, until it's not.

There are a few implementation problems with callbacks in our paticular scenario. For starters, we have to check each and every time kendoAlert gets called. Then we have to bind or unbind to the Kendo UI Window deactivate event each and every time based on whether or not we passed a function for the deactivate parameter. And really, we should be checking for whether or not deactivate even IS a function before we try and execute it. This is very manual and kind of gross. We can make this better by using a concept that jQuery already has implemented for us.

Promises

A new specification has emerged in the past few years and has been implemented nearly everywhere, including Windows 8 HTML/JS apps. Promises. The whole point of promises is to make dealing with callbacks cleaner, easier, safer, and more reliable.

The theory works like this...

  • You call a function and in return you get back a promise which represents the operation you just requested via your function call.
  • That promise gives you several methods that you can use to handle the result of the otherwise asynchronous operation.

Promises are not magic or new language functionality, they are simply a pattern for helping us get out of "callback hell". jQuery implements promises in the form of something called a "Deferred". There is a lot of argument and debate about whether or not jQuery implements the promises specification correctly. I am not here to weigh in on that debate in any form. Rather, we are going to use Deferred's as jQuery implements them (right or wrong) to use a promise instead of dealing with a callback and all the manual logic that comes with it.

Promise In Lieu Of Callback

// attach kendoAlert to the window
window.kendoAlert = (function() {

  var dfrd;

  // create modal window on the fly
  var win = $("<div>").kendoWindow({
    modal: true,
    deactivate: function() {
      // when the deactivate event fires,
      // resolve the promise
      dfrd.resolve();
    }
  }).getKendoWindow();

  return function(msg) {

    // create a new deferred
    dfrd = $.Deferred();

    // set the content
    win.content(msg);

    // center it and open it
    win.center().open();

    // return the deferred object
    return dfrd;
  };

}());

$(function() {
  $("#open").on("click", function() {
    // open the alert
    kendoAlert("Hey Now!").then(function() {
      // change the body background color after
      // the alert is dismissed
      $("body").css("background-color", "salmon");
    });
  });
});

You can see from the above code what the Deferred buys us here. We still have to pass a callback, but we no longer have to babysit that callback all the way through to it's execution. Instead, our kendoAlert call returns the Deferred object which has a then method. We simply call this method and pass in the function we want executed. The window will resolve the Deferred promise in the deactivated event, which I specified in the window initialization code. And what happens if we don't specify an action to occur on deactivate? Nothing. No checking or logic required on our part.

Any subsequent kendoAlert calls are ignored if they are made while a kendoAlert is still open. That's why you would want to use the then method to make sure your alerts aren't stepping on each other.

Customization

I mentioned earlier that we could customize these modal windows much much more than a standard JavaScript alert. Here is an example of one I created that alllow you to set the title, gives it a bit of style, replicates the "ok" button in a standard alert, and alters the animation some too.

It's remarkable how many concepts a simple UI element like an alert can combine. In that last example you will find closures, templating, promises and event delegation. It's fun to build these simple reusable components since you learn so much in the process!

Make It Better!

See anything I missed? Can you improve on this code? What about adding "OK" and "Cancel" buttons and handling those events as well? What about collecting user input? JavaScript provides us with the alert, confirm and prompt to handle all of these scenarios. Download your copy of Kendo UI and see if you can't expand on this sample to create a reusable and robust alert/confirm/prompt component that won't steal your user's sunshine.


Burke Holland is the Director of Developer Relations at Telerik
About the Author

Burke Holland

Burke Holland is a web developer living in Nashville, TN and the Director of Developer Relations at Telerik. He enjoys working with and meeting developers who are building mobile apps with jQuery / HTML5 and loves to hack on social API's. Burke works for Telerik as a Developer Advocate focusing on Kendo UI.

Related Posts

Comments

Comments are disabled in preview mode.