Ember JS Flash Message Alerts

There are lots of ways to do this and some plugins out there (eg aexmachina’s ember-notify and poteto’s ember-cli-flash) but here is my take* on Rails style flash messages for Ember as seen in the Open PHACTS Explorer 2.

Use a simple array controller to keep track of the current messages, a model to hold the message and what type of alert it is, a view with an action to remove the alert and a template to show it on the page.

The page needs a template containing the flash messages.

<script type="text/x-handlebars">
    {{#each flashMessage in controllers.flash.content}}
        {{view "flash" contentBinding="flashMessage"}}
    {{/each}}
</script>

It also needs a template for the flash message.

<script type='text/x-handlebars' id='flash'>
    {{#if flashMessage.isNotice}}
    <div class="alert notice">
        {{flashMessage.message}}
        <button type="button" class="right" {{action "click" flashMessage target=view}}><span>×</span></button>
    </div>
    {{/if}}
    {{#if flashMessage.isSuccess}}
    <div class="alert success">
        <button type="button" class="right" {{action "click" flashMessage target=view}}><span>×</span></button>
        {{flashMessage.message}}
    </div>
    {{/if}}
    {{#if flashMessage.isError}}
    <div class="alert error">
        <button type="button" class="right" {{action "click" flashMessage target=view}}><span>×</span></button>
        {{flashMessage.message}}
    </div>
    {{/if}}
</script>

We need a controller to keep track of all the flash messages

App.FlashController = Ember.ArrayController.extend({
    createFlash: function(options) {
        if (options.type !== null && options.message !== null) {
            this.pushObject(this.get('store').createRecord(
                "flashMessage", {
                    type: options.type,
                    message: options.message
                }
            ));
        }
    }
});

We also need model for a flash message.

App.FlashMessage = DS.Model.extend({
    type: DS.attr('string'),
    message: DS.attr('string'),
    isNotice: function() {
        return this.get("type") === "notice";
    }.property("type"),
    isSuccess: function() {
        return this.get("type") === "success";
    }.property("type"),
    isError: function() {
        return this.get("type") === "error";
    }.property("type")
});

If a controller wants to create a flash message then it ‘needs’ the Flash controller. Here the Application controller creates a flash message in response to an action.

App.ApplicationController = Ember.Controller.extend({
    needs: ['flash'],
    actions: {
        createFlashNotice: function() {
            this.get('controllers.flash').createFlash({
                type: "notice",
                message: "I'm a flash notice."
            });
        },
        createFlashError: function() {
            this.get('controllers.flash').createFlash({
                type: "error",
                message: "I'm a flash error."
            });
        },
        createFlashSuccess: function() {
            this.get('controllers.flash').createFlash({
                type: "success",
                message: "I'm a flash success."
            });
        }
    }
});

We need a view for a flash messages which can remove it in response to a user action.

App.FlashView = Ember.View.extend({
    templateName: 'flash',
    classNames: ['hide'],
    didInsertElement: function() {
        this.$().fadeIn(1000);
    },
    actions: {
        click: function(alert) {
            this.get('controller').get(
                'controllers.flash').removeObject(
                this.get('content'));
            this.destroy();
        }
    }
});

JS Bin example. Click on one of the buttons to create a flash message and remove it by clicking on the ‘x’.

Thanks to Eric Berry for the ‘flash’ of inspiration.

* I originally wrote this for the Ember guides cookbook but they are moving away from this format and relying on blog posts etc instead.