I was in need of a thing that is able to inform my users about recent activities as well as intercept any action with a modal (e.g for undo purposes)
I decided that I will go for an independent module that could be included in any project. The module contains the following:
- A directive which will show the messages to the user and handle interactions with the modals
- A controller for said directive
- A configurable provider that shall provide the logic
Further, there are 2 external files, the template and the stylesheet.
Desired procedure
Notifications
Notifications are simple. They shall pop up and disappear after n seconds. It would be nice if we had different types (e.g error, success etc.)
Interceptions
Interceptions shall show a message and provide either 1 or 2 buttons. They have to return a promise in order to decide further action.
If there is only one button specified, hitting it should resolve the promise. When there are 2, the first one should resolve while the second one should reject.
if neither one is hit, the promise should be rejected after n seconds.
Solution
"use strict";
var purr = angular.module('purr', []);
purr.controller('purrController',function($scope,purr){
$scope.notificationQueue = purr.getNotificationQueue();
$scope.interceptionQueue = purr.getInterceptionQueue();
});
purr.directive('purr',function(purr){
return{
restrict: 'EA',
scope: {},
templateUrl: "partials/assets/purr.html",
controller: 'purrController'
}
});
purr.provider('purr',function(){
var module = this;
this.options = {};
this.$get = function($timeout,$q){
var self = this;
var defer = $q.defer();
var notificationQueue = [];
var interceptionQueue = [];
var timer;
var types = {
'info': {
'icon': 'fa-info',
'class': 'purr-info',
'type': 'Information'
},
'warning': {
'icon': 'fa-warning',
'class': 'purr-warning',
'type': 'Warning'
},
'error': {
'icon': 'fa-exclamation',
'class': 'purr-error',
'type': 'Failure'
},
'success': {
'icon': 'fa-check',
'class': 'purr-success',
'type': 'Success'
}
};
var createNotification = function(msg,type){
var defaults = {
'message': "No message given. Please report this issue.",
'icon': 'fa-info'
};
var settings = {
'timeout': 5000
};
settings = angular.extend(settings, module.options);
var notification = angular.extend(types[type],{message: msg || this.defaults.message});
notificationQueue.push(notification);
$timeout(function(){
notificationQueue.length = 0;
},settings.timeout);
};
function Interception(msg,appr,decl){
this.message = msg;
this.approval = {
caption: appr,
fire: function(){
defer.resolve('yup');
interceptionQueue.length = 0;
resetPromise();
$timeout.cancel(timer);
}
};
this.decline = {
caption: decl,
fire: function(){
defer.reject('nope');
interceptionQueue.length = 0;
resetPromise();
$timeout.cancel(timer);
}
};
}
function resetPromise(){
defer = $q.defer();
}
return{
getNotificationQueue: function(){
return notificationQueue;
},
getInterceptionQueue: function(){
return interceptionQueue;
},
info: function(msg){
createNotification(msg,'info');
},
warning: function(msg){
createNotification(msg,'warning');
},
success: function(msg){
createNotification(msg,'success');
},
error: function(msg){
createNotification(msg,'error');
},
intercept: function(msg,appr,decl){
var interception = new Interception(msg,appr,decl);
interceptionQueue.push(interception);
timer = $timeout(function(){},5000);
timer
.then(function(){
if(interceptionQueue.length){
defer.reject('timeout');
interceptionQueue.length = 0;
resetPromise();
}
});
return defer.promise;
}
}
}
});
This is my solution. It is used like this:
//Interception
purr.intercept('Do you want to undo that action?','Yes','No')
.then(function(res){
//undo
})
.catch(function(res){
//do nothing
});
//notification
purr.error('fail');
I am happy with the result since it works. Yet, I feel like the code base could be improved. An issue that bothers me is the fact that I have to call both resetPromise()
and $timeout.cancel()
in redundant ways.
Further, as you may have noticed, I decided to use a class-like implementation for the interceptions while the notifications are created in a more procedural way. Are there any reasons to prefer one over the other? (Personally, I prefer the OO style)