Material Design Lite Snackbar, a promise and Angular

Serve a MDL-Snackbar to the User via Angular

Material Design Lite

For a recent Angular project I tried out google's Material Design Lite Package. There already exists a Angular MDL Package, but it misses the Snackbar Module. So I build myself a little Helper Factory to implement the MDL-Snackbar.

MDL - Material Design Lite

This Layout-Framework provided by google is quite a lightweight and I liked it's simple approach — and of course its flexbox support. One of the provided MDL Modules is the Snackbar which can be used to show the User a dialog modal — https://getmdl.io/components/index.html#snackbar-section

Problem

I want a Angular Service which should be able to resolve a JS-promise, based on the User response of the displayed MDL-Snackbar. The Snackbar should be added and removed from the DOM after it has done its job.

Angluar Snackbar Animation

Solution

The first part of this example is just basis stuff to illustrate the idea. Create a new Angular Module and add a simple controller, which should resolve the Click on a Button with a Javascript promise.

The controller calls the mdl.snackbar() method with the standard MSL-Snackbar parameters. If the User does nothing the promise gets resolved after the timeout period. Should the User Click the provided actionText, the promise will not be resolved.

app = angular.module('app', []);

app.controller('controller', ['mdl', function{

$scope.button = function (){
mdl.snackbar({
'message': 'Luke, I\'m your father!',
'timeout': 4000,
'actionText': 'Noooo'

}).then( function( ) {
console.log('Joining the dark Side')
})
.catch( function() {
console.log('Let go!')
});
});
}
}]);

MDL Factory

Here is the Angular Factory which will provide the MDL-Snackbar Service to our Controller.

The factory will need a few Angular Components $q and $timeout. Furthermore I use the $templateCache to load a HTML Snippet which provides the default MDL-Snackbar code.

app.factory('mdl', ['$templateCache', '$q', '$timeout', function(){

return {

'snackbar' : function( options){

var template = $templateCache.get('../frontend/components/layout/layoutSnackbar.html');

var defer = $q.defer();

angular.element( document.querySelector('body') ).append( angular.element( template ) );

// Essential for Material-Design lite with dynamic DOM
// http://getmdl.io/started/index.html#dynamic
componentHandler.upgradeAllRegistered();

options.actionHandler = function ( ) {
var snackbarEl = document.getElementById('snackbar');
snackbarEl.classList.remove('mdl-snackbar--active');
angular.element( snackbarEl ).remove();
return defer.reject();
};

document.querySelector('.mdl-js-snackbar').MaterialSnackbar.showSnackbar( options );

var resolve_timer = $timeout(function () {
angular.element( document.getElementById('snackbar') ).remove();
defer.resolve();
}, options.timeout + 10);

return defer.promise;

}
};
}]);

How does this work

The template snippet gets appended to the <body> tag.

The $q component is called to create a promise, which we then can return to the Controller.

When working with MDL and a Framework with dynamic DOM, you need to re-register the componentHandler.

The options.actionHanlder is a default MDL-Snackbar option, to handle the User Click on the Snackbar "Noooo" Button.
It removes the MDL CSS class mdl-snackbar--active to close the Snackbar and returns a rejected promise to the Controller. Do not oversee to return the promise from the closure!

Next we start the MDL-Snackbar with our provides options.

In case the User let the given timeout pass, we remove the Snackbar from the DOM and return a resolved promise.

Conclusion

I think maybe this will fit better in a Angular Directive, I quite like the promise possibility it brings to the Controller.