Making The Web Growl Using jQuery

I really like how the Growl application for the Mac works. It provides a notification framework that all applications can use. I often find my self needing to display notifications to the user in my web applications. For instance, when the user incorrectly fills out a form. Here is a screen shot of a simple ‘growl notification’.

imageThis is not complicated to add to an application. In the vein of “Don’t Repeat Yourself” I have put created a ‘growl package’ that can be downloaded below. For a live example check out the demo.

Demo Download

Growl Code

The download for the growl code consists of a JavaScript file and a CSS file. The JavaScript file contains the following code:

// Can't growl until the document is ready
var isGrowlReady = false;
$(document).ready(function () {
    isGrowlReady = true;
});

var growlMask;
var growlWrap;
var growlTitle;
var growlContent;
var isGrowlVisible = false;
function growl(title, msg) {
    // Recursively call growl until doc is ready
    while (!isGrowlReady) {
        setTimeout("growl('" + title + "', '" + msg + "')", 100);
        return;
    }

    // Ensure the growl HTML is in place and the events
    //  are hooked up. This code executes once.
    initGrowl();

    // Size the mask and growl window.
    sizeGrowl(true);

    // Animate the growl.
    growlMask
        .fadeTo("fast", 0.75, function () {
            isGrowlVisible = true;
            var scrollTop = $(document).scrollTop();
            growlTitle.html(title);
            growlContent.html(msg);
            growlWrap.show().animate({ "marginTop": scrollTop + 10 + "px" }, 500);
        });
}

function initGrowl() {
    if ($("#growl-mask").length == 0) {
        // Append growl HTML to body
        var growl = "<div id='growl-mask'></div><div id='growl-wrap'><h6 id='growl-title'></h6><div id='growl-content'></div></div>";
        $("body").append(growl);

        // Initialize global variables
        growlMask = $("#growl-mask");
        growlWrap = $("#growl-wrap");
        growlContent = $("#growl-content");
        growlTitle = $("#growl-title");

        // Hide growl on click event to the mask
        growlMask.click(function () {
            isGrowlVisible = false;
            growlWrap.fadeOut();
            growlMask.fadeOut();
        });
        // Reposition the growl if window is sized or scrolled
        $(window).resize(function () {
            if (isGrowlVisible) {
                growlMask.stop();
                growlWrap.stop();
                sizeGrowl(false);
            }
        });
        $(window).scroll(function () {
            if (isGrowlVisible) {
                growlMask.stop();
                growlWrap.stop();
                sizeGrowl(false);
            }
        });
    }
}

function sizeGrowl(hide) {
    // Collect some measurements
    var scrollLeft = $(document).scrollLeft();
    var scrollTop = $(document).scrollTop();
    var growlWidth = growlWrap.outerWidth();
    var growlHeight = growlWrap.outerHeight();
    var winWidth = $(window).width();
    var docHeight = $(document).height();
    var docWidth = $(document).width();

    // Calculate the notification position.
    var growlTop = hide ? scrollTop - growlHeight : scrollTop + 10;
    var growlLeft = scrollLeft + (winWidth - growlWidth) / 2;

    // Size and position the mask and the notification
    growlMask.css({ "width": docWidth + "px", "height": docHeight + "px" });
    growlWrap.css({ "margin-top": growlTop + "px", "left": growlLeft + "px" });
}

The first bit of JavaScript leverages the jQuery document ‘ready’ event to set a flag indicating the application is ready to support growls. This hook is necessary to support growls that originate in server side code (see ASP.NET MVC below for example).

There are two supporting functions in the JavaScript: ‘initGrowl’ and ‘sizeGrowl’. The ‘initGrowl’ function injects the necessary HTML to support the growl into the document, collects some quick references to the elements for use by other functions, and hooks up events. The windows ‘resize’ and ‘scroll’ events are used to keep the notification window positioned. The ‘sizeGrowl’ function takes a few measurements of the document and then sizes and positions the growl mask and notification window.

/* Growl
----------------------------------------------------------*/
#growl-mask
{
    background-color: #000;
    position: absolute;
    display: block;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    display: none;
}
#growl-wrap
{
    background-color: #fff;
    color: #000;
    min-width: 400px;
    margin: 0;
    display: none;
    position: absolute;
    top: 0;
    left: 0;
}
#growl-title
{
    text-align: center;
    color: #000;
}
#growl-content
{
    margin: 10px;
    border: 1px solid #333;
    padding: 30px;
}
#growl-content p
{
    margin-bottom: 10px;
}

The CSS above adds a bit of style. This will certainly need a touch up to blend into the application.

JavaScript Growls

To create a ‘growl’ notification using JavaScript simply include a link to the growl CSS and JavaScript then call the ‘growl’ function. Here is an example for validating a form:

<script type="text/javascript">
    $("#submit").click(function(){
        var msg = "";
        if($("#first").val()==""){
            msg += "<li><strong>First Name</strong> is required</li>"
        }
        if($("#last").val()==""){
            msg += "<li><strong>Last Name</strong> is required</li>"
        }
        if(msg != ""){
            msg = "<p>Please fix the following:</p><ul>" + msg + "</ul>";
            growl("Form Error", msg);
            return false;
        }
        return true;
    })
</script>

ASP.NET MVC Growls

Adding growl notifications to an ASP.NET MVC application involves a couple of steps. First add growl support to your controller base class (create one if you don’t have one).

public abstract class BaseController : Controller
{
    public void Growl(string title, string message)
    {
        TempData["Growl"] = title + "t" + message;
    }
}

Notice that ‘TempData’ is used instead of ‘ViewData’. This allows growl notifications to live through redirects. Any controller that needs growl support should inherit from this base class.

public ActionResult Index()
{
    Growl("Test", "This is a test");

    return View();
}

Modify your Master Page to include links to the growl CSS and JavaScript. Finally add the following to your Master Page:

<% if(TempData.ContainsKey("Growl")) {
    string growl = (string)TempData["Growl"];
    string[] parts = growl.Split('t');
%>
<script type="text/javascript">
    growl('<%= parts[0] %>', '<%= parts[1] %>');
</script>
<% } %>

This will add a JavaScript call to the ‘growl’ function if a growl is present.

Summary

This is a pretty simple library. There are more features that can be added. If you give it a test drive, let me know how you like it.

Tags:
Comments
  1. Todd

Leave a Reply

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

*