Tutorial: Building the Simplest JS Notification Library

Tutorial: Building the Simplest JS Notification Library

Few days ago I was asked to create a solution to work with JS Notification for a web app in the same way apps like WhatsApp web does. So, I went to the docs, read it and got quite surprised how easy it is to use the native API. For a little while I thought my work was already done and, even better, without any dependences from frameworks, only pure Javascript.

Wrong.

Before I talk about the issues on my Notifications project, let’s see how use it.

That’s simplest example of notification:

Try it yourself

Pretty cool, eh?

In the example above we are only printing the attribute title of the notification. There are other attributes we can declare to have a better experience with our notification and, yay, those are almost working in the same way at the main browsers (except for IE family, of course. But we are talking about real browsers, aren’t we? But don’t worry, we’ll create a way to give a fallback to them).

The following attributes are stable to use:

body

As the name suggests, it’s the body of the message. You only can use plain text here, no HTML allowed.

tag

Tag is the ‘unique name’ of the notification. If you call a notification and you already have a visible  one with the same tag, the new call will close the previous notification and recreate it with the new content.

icon

Any image you want to show with you notification.

So, if declare something like that

Try it yourself

you will see a fine notification at the corner. Yeah, that’s all, we have that fancy cool thing with very little effort!

But wait… What happens if we try to print two notifications at the same time?

At Chrome you’ll have results, but Firefox, Safari and Opera up to now won’t do anything (not even return an error). After some tries, I discovered those browsers demand a interval between the messages, something around 50-60 milliseconds. And that’s not the only trouble.

The second issue I found is about the use of alert sounds: at the specs we already have an audio option but, unfortunately, no browser has implemented it yet.

And, wait, there’s more! There are a few differences between the focus behavior across the browsers when you click at the notifications. When you click at the notification, Firefox always focuses on the page which called the notification while Chrome and Opera don’t. The same is true for the close event, every browser has a different response.

Managing multiple notifications

The main problem here is the fact the Notification API is not totally reliable when an application demands multiple asynchronous notifications.

The simplest way I came up to work with it was generating a forced delay between the messages.

To do that we need:

  • A way to create the messages and store them in a stack;
  • A function to print the messages one by one removing them of the stack when the action is done and;
  • The manager who insert the delay between the messages.

Ok, let’s create the structure of our lib. First, we need to define how we want to call our messages and what attributes we need. I intend to invoke our notification in two ways: one by string and another by using a configuration object.

So, having that in mind, we can provide the necessary support with something like that.

Looking at the code above, you’ll notice we already have the ‘notifications repository’, the array called ‘Notify.stack’. Every time a new notification is created, we’ll save it here. And every time the notification is printed, it’ll be removed from that.

Now, we need to have something to support this process so, I present you with the heart of our code, the observer:

The ‘Observer’ will call itself recursively, printing all the messages in the stack until this length reach 0, always respecting an interval of 200 milliseconds between prints.

Now, we need a way to ask permission to the browser to print the messages. We can use that code in the beginning of this text but, c’mon, we don’t want to ask permission for every new notification. So, we’ll create a way to test once and also configure the expected behavior for both cases: permission granted or not.

The ‘ask function’ ensures the code will test the permission only once, properly configure the ‘create function’ and start the ‘observer’. If the permission wasn’t granted or the browser doesn’t support notifications, our code will try to use ‘options.fallback’ to give some feedback to user. ‘Options.fallback’, besides being the feedback for non granted permission, is also the standard response for Internet Explorer, so I suggest you build a nicer alternative than just an alert. Or not, after all, Internet Explorer users deserves nothing but pain and suffering and…No, wait, be nice with them, some of them aren’t bad people.

That covers already everything we need in our lib. Now, let’s add an alert sound. The idea is to provide a default sound to every notification printed, but also allow to use customized sounds.

So, we need to add an audio attribute to the Notify constructor and create an Audio object which will preload our sound. Of course, our audio attribute always asks if we want to use a different sound and, in case we don’t, it’ll follow its way and use the default one.

Now, we put the sound call at the createNotify function:

Aaaaand here it is: the complete code:

Try it yourself

And that’s all, folks, we are now able to use notifications in every browser without problems.

Have you got questions or suggestions to improve this article? Leave us a comment.