views:

825

answers:

6

Remember the little div that shows up at the top of the page to notify us of things (like new badges)?

I would like to implement something like that as well and am looking for some best practices or patterns.

My site is an ASP.NET MVC app as well. Ideally the answers would include specifics like "put this in the master page" and "do this in the controllers".

Just to save you from having to look yourself, this is the code I see from the welcome message you get when not logged in at stackoverflow.

<div class="notify" style="">
  <span>
    First time at Stack Overflow? Check out the
    <a href="/messages/mark-as-read?returnurl=%2ffaq">FAQ</a>!
  </span>
  <a class="close-notify" onclick="notify.close(true)" title="dismiss this notification">×</a>
</div>

<script type="text/javascript">

  $().ready(function() {
    notify.show();
  });

</script>

I'd like to add that I understand this perfectly and also understand the jquery involvement. I'm just interested in who puts the code into the markup and when ("who" as in which entities within an ASP.NET MVC app).

Thanks!

+4  A: 

Though these are by no means official, the common practices that I follow would result in something like this:

  • Create the element that will act as the notification container in the markup, but hide it by default (this can be done numerous ways - JavaScript, external CSS, or inline styles).
  • Keep the scripts responsible for the behavior of the notification outside of the markup. In the example above, you can see there is an onclick as well as another function that fires on page load contained in the markup. Though it works, I see this as mixing presentation and behavior.
  • Keep the notification message's presentation contained in an external stylesheet.

Again, these are just my common practices stated in the context of your question. The thing with web development, as the nature of your question already shows, is that there are so many ways to do the same thing with the same results.

Tom
I'd also like to add: Put all the notification JavaScript code in one external .JS file. You'll likely have quite a bit of it there, so it's good that the users can cache it. Plus it will serve well for code organization.
Vilx-
If I may add to that. Don't forget to put that .js include at the bottom of your structure so it doesn't block downloading the rest of the page until it's needed, as javascript block parallel downloads of other external resources.
Kit Sunde
+2  A: 

StackOverflow uses jQuery - the JS code you posted from SO is a jQuery call. It'll do exactly what you want with almost no code. Highly recommended.

Mike Scott
+9  A: 

This answer has a complete solution.

Copy-pasting:

This is the markup, initially hidden so we can fade it in:

<div id='message' style="display: none;">
    <span>Hey, This is my Message.</span>
    <a href="#" class="close-notify">X</a>
</div>

Here are the styles applied:

#message {
    font-family:Arial,Helvetica,sans-serif;
    position:fixed;
    top:0px;
    left:0px;
    width:100%;
    z-index:105;
    text-align:center;
    font-weight:bold;
    font-size:100%;
    color:white;
    padding:10px 0px 10px 0px;
    background-color:#8E1609;
}

#message span {
    text-align: center;
    width: 95%;
    float:left;
}

.close-notify {
    white-space: nowrap;
    float:right;
    margin-right:10px;
    color:#fff;
    text-decoration:none;
    border:2px #fff solid;
    padding-left:3px;
    padding-right:3px
}

.close-notify a {
    color: #fff;
}

And this is javascript (using jQuery):

$(document).ready(function() {
    $("#message").fadeIn("slow");
    $("#message a.close-notify").click(function() {
        $("#message").fadeOut("slow");
        return false;
    });
});

And voila. Depending on your page setup you might also want to edit the body margin-top on display.

Here is a demo of it in action.

itsadok
there is a lot more to stackoverflow's notification system than that example. See the de-minified javascript code provided by Picflight or use ySlow's "beautified js" feature to see the client code. There's server side code involved as well...
ckarbass
+3  A: 

I see the following jQuery function? I beleive that injects the html into the div with id notify-container.

I don't understand how this JS is used and called based on certain events, perhaps someone can explain.

var notify = function() {
var d = false;
var e = 0;
var c = -1;
var f = "m";
var a = function(h) {
    if (!d) {
        $("#notify-container").append('<table id="notify-table"></table>');
        d = true
    }
    var g = "<tr" + (h.messageTypeId ? ' id="notify-' + h.messageTypeId + '"' : "");
    g += ' class="notify" style="display:none"><td class="notify">' + h.text;
    if (h.showProfile) {
        var i = escape("/users/" + h.userId);
        g += ' See your <a href="/messages/mark-as-read?messagetypeid=' + h.messageTypeId + "&returnurl=" + i + '">profile</a>.'
    }
    g += '</td><td class="notify-close"><a title="dismiss this notification" onclick="notify.close(';
    g += (h.messageTypeId ? h.messageTypeId : "") + ')">&times;</a></td></tr>';
    $("#notify-table").append(g)
};
var b = function() {
    $.cookie("m", "-1", {
        expires: 90,
        path: "/"
    })
};
return {
    showFirstTime: function() {
        if ($.cookie("new")) {
            $.cookie("new", "0", {
                expires: -1,
                path: "/"
            });
            b()
        }
        if ($.cookie("m")) {
            return
        }
        $("body").css("margin-top", "2.5em");
        a({
            messageTypeId: c,
            text: 'First time here? Check out the <a onclick="notify.closeFirstTime()">FAQ</a>!'
        });
        $(".notify").fadeIn("slow")
    },
    showMessages: function(g) {
        for (var h = 0; h < g.length; h++) {
            a(g[h])
        }
        $(".notify").fadeIn("slow");
        e = g.length
    },
    show: function(g) {
        $("body").css("margin-top", "2.5em");
        a({
            text: g
        });
        $(".notify").fadeIn("slow")
    },
    close: function(g) {
        var i;
        var h = 0;
        if (g && g != c) {
            $.post("/messages/mark-as-read", {
                messagetypeid: g
            });
            i = $("#notify-" + g);
            if (e > 1) {
                h = parseInt($("body").css("margin-top").match(/\d+/));
                h = h - (h / e)
            }
        } else {
            if (g && g == c) {
                b()
            }
            i = $(".notify")
        }
        i.children("td").css("border-bottom", "none").end().fadeOut("fast", function() {
            $("body").css("margin-top", h + "px");
            i.remove()
        })
    },
    closeFirstTime: function() {
        b();
        document.location = "/faq"
    }
 }
} ();
Picflight
+4  A: 

After snooping around the code a bit, here's a guess:

The following notification container is always in the view markup:

<div id="notify-container"> </div>

That notification container is hidden by default, and is populated by javascript given certain circumstances. It can contain any number of messages.

If the user is not logged in

Persistence: Cookies are used to keep track of whether a message is shown or not.

Server side generated code in the view: I think stackoverflow only shows one message if you aren't logged in. The following code is injected into the view:

<script type="text/javascript">
    $(function() { notify.showFirstTime(); });
</script>

The showFirstTime() javascript method just determines whether to show the "Is this your first time here?" message based on whether a cookie has been set or not. If there is no cookie, the message is shown. If the user takes action, the cookie is set, and the message won't be show in the future. The nofity.showFirstTime() function handles checking for the cookie.

If the user is logged in

Persistence: The database is used to keep track of whether a message has been shown or not.

Server side generated code in the view: When a page is requested, the server side code checks the database to see what messages need to be displayed. The server side code then injects messages in json format into the view and puts a javascript call to showMessages().

For example, if I am logged into a view, I see the following in the markup at SO:

    <script type="text/javascript">
1
2 var msgArray = [{"id":49611,"messageTypeId":8,"text":"Welcome to Super User! Visit your \u003ca href=\"/users/00000?tab=accounts\"\u003eaccounts tab\u003c/a\u003e to associate with our other websites!","userId":00000,"showProfile":false}];
3 $(function() { notify.showMessages(msgArray); });
4
</script>

So the server side code either injects code to call the "showFirstTime" method if the user is not logged in or it injects messages and calls "showMessages" for a logged in user.

More about the client side code

The other key component is the "notify" JavaScript module Picflight has de-minified (you can do the same using yslow for firebug). The notify module handles the populating of the notification div based on the server side generated javascript.

Not logged in, client side

If the user is not logged in, then the module handles events when the user X's out the notification or goes to the FAQ by creating a cookie. It also determines whether to display the first time message by checking for a cookie.

Logged in, client side

If the user is logged in, the notify module adds all the messages generated by the server into the notification div. It also most likely uses ajax to update the database when a user dismisses a message.

ckarbass
A: 

Also note you can poke around easily in this code using:

-Firebug for Firefox
-Chrome- Right click, "inspect element"
-IE - press f12, select the arrow icon, click on the element to inspect

boomhauer