Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Angular Material Design, $mdToast, and HTTP Interceptors

DZone's Guide to

Angular Material Design, $mdToast, and HTTP Interceptors

One of the services added by the Angular Material modules is the $mdToast service, which provides an easy way to display small pop-up notifications ("toasts") in response to events.

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Recently I've been playing around with the current beta distribution (0.8.3) of Angular Material Design: a set of Angular modules and resources that apply the "Material Design" style and behaviors used in Android 5.0 to an Angular website.

One of the services added by the Angular Material modules is the $mdToast service,  which provides an easy way to display small pop-up notifications ("toasts") in response to events (a common behavioral convention on mobile devices).  I wanted to use the $mdToast service in my httpInterceptor service function for handling HTTP response errors so that I could display a toast message if the server returned a nasty 500 HTTP status code.

But I ran into a problem:  when I tried to inject $mdToast into my interceptor service factory using standard Angular dependency injection, I got a "circular dependency found" error message when I loaded my Angular app.  The same thing happened when I tried injecting $mdToast into a service module of my own creation - toastService - and injecting that into my interceptor service factory.

The solution to the problem offered on the "ngmaterial" Google Group forum was to manually inject $mdToast into the service factory via $injector:


function httpInterceptors( $rootScope, $q, $injector, sessionService ) {
    var service = {
        responseError: responseError
    };

    var $mdToast = $injector.get("$mdToast");

While that did work, I came to realize that I didn't want my toast configuration and behavior logic stuck inside my interceptor method:  I did in fact want a separate toastService module to handle all toast messages.

So to get around the circular dependency problem, I coded my interceptor to broadcast an "httpError" event containing the desired message text.  I then created a listener for the broadcast in the run() method of my main application module that would invoke the proper function of the toastService and display the toast.

interceptorService.js:


'use strict';

angular.module( 'mdApp.services' )

    .config( [ '$httpProvider', function ( $httpProvider ) {
        $httpProvider.interceptors.push( 'httpInterceptors' );
    }] )

    .factory( 'httpInterceptors', httpInterceptors );

function httpInterceptors( $rootScope, $q ) {

    var service = {
        responseError: responseError
    };

    return service;

    function responseError( response ) {

        switch ( response.status ) {
            //...can handle different error codes differently
            case 500:
                $rootScope.$broadcast( 'httpError', { message: 'An unexpected error has occurred. Please try again.' } );
                break;
        }

        return $q.reject( response );
    }

}

httpInterceptors.$inject = [ '$rootScope', '$q' ];

 

app.js:


'use strict';

angular.module( 'mdApp.controllers', [] );
angular.module( 'mdApp.services', [] );

angular.module( 'mdApp', [
    'mdApp.controllers',
    'mdApp.services',
    'ngRoute',
    'ngAria',
    'ngMaterial'
])

    .run( runApp );

function runApp( $rootScope, toastService ) {

    $rootScope.$on( 'httpError', function( event, eventData ) {
        toastService.serverError( eventData.message );
    })

}

runApp.$inject = [ '$rootScope', 'toastService' ];

 

toastService.js:


'use strict';

angular.module( 'mdApp.services' )

    .factory( 'toastService', toastService );

function toastService ( $mdToast ) {

    var service = {
        message: '',
        serverError: serverError
    };

    return service;

    function serverError( errorMessage ) {
        //The toastController gets an instance of toastService, so the error message is exposed
        //via the message property and the controller provides it to the toast.html view
        this.message = errorMessage;

        $mdToast.show( {
            controller: 'toastController',
            controllerAs: 'vm',
            templateUrl: 'views/toast.html',
            hideDelay: 0,
            position: 'bottom left'
        });

    }
}
toastService.$inject = [ '$mdToast' ];

The end result is the toast message pictured below, styled with a mix of Angular Material theming and regular CSS:

mdToast example

Hopefully the circular dependency issue will be addressed in a future release of Angular Material so this kind of workaround becomes unnecessary (I don't see any mention of this issue in the release notes for version 0.9.0).

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
angular ,angular material design ,mdtoast

Published at DZone with permission of Brian Swartzfager, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}