Monday, December 1, 2014

Create Your Own Angular Confirm Dialog


Modal dialogs have always been kind of iffy to use in regards to UX.  This goes 1000000x for web dialogs.  While most browsers somewhat support showModalDialog, it definitely isn't recommended to use for a lot of reasons.    I do believe that dialogs like other maligned things still have their place if used properly.

Loud Noises!
The type of dialogs I am referring to on the web are typically not traditional dialogs, but a transparent div of height/width of 100%.  You can find these types of dialogs all over the internet for all kinds of various things.  Even as I create this blog post blogger had a custom dialog to insert an image, and a hyperlink.
Blogception
So I wanted to create something that I could reuse and style easily as well as incorporate in my work.  An angular directive seemed like the right approach for this.  I ended up creating a simple confirm dialog that you could set the text for the title, detail, and buttons, as well as the confirm and cancel button callbacks.  

The first thing I started out with was the HTML for the dialog.  It should be pretty straightforward,  one container to take the entire page, one div that is centered in the middle of the page and is the height and width of whatever we desire it to be, the title, the detail, and the buttons.  Here is what that looks like: 
      
    <div class='confirm' ng-hide='!showPrompt'> 
        <div class='confirmContainer'>
            <div class='confirm-title'>{{confirmTitle}}</div> 
            <div class='confirm-detail'>{{detailText}}</div> 
            <div class='confirm-actions'>
                <button class='ok' btn' ng-click='ok()'>{{okText || 'OK'}}</button>
                <button class='cancel btn' ng-click='cancel()'>{{cancelText || 'Cancel'}}</button> 
            </div> 
      </div>
</div>

Next lets add some basic CSS for this dialog to center everything, and set the height/width appropriately.  We want the dialog to take the entire height & width of the page with a transparent background.  To center the container vertically we put the top at 50% and then set a negative margin top to move it back up.  We then put the buttons container to the bottom right of the confirmContainer.   
      
.confirm{
    height:100%;
    width:100%;
    position: fixed;
    top:0;
    opacity: 1;
    left:0;
    background-color: rgba(3, 3, 3, .25);
    z-index: 1000;
}

.confirm .confirmContainer{
    position: relative;
    top:50%;
    width:50%;
    margin: 0 auto;
    height:200px;
    margin-top: -50px;
    background-color: rgba(255, 255, 255, 1);
}

.confirm .confirm-actions{
    position: absolute;
    bottom:10px;
    right:10px;
}

Finally lets get to the directive code.  We are going to use an isolated scope to bind whatever properties we want as well as the 2 functions we want to call.  We will also bind a showDialog property on the scope that will show the dialog when it is set to true.  When we want it to hide we will then set it back to false in our button code.  Pretty easy.  Here is the whole directive:

 
.directive('confirm', function(){
    var template ="<div class="confirm" ng-hide="!showPrompt">
" + 
        "<br />
<div class="confirmContainer">
" + 
            "<br />
<div class="confirm-title">
{{confirmTitle}}</div>
" + 
            "<br />
<div class="confirm-detail">
{{detailText}}</div>
" + 
            "<br />
<div class="confirm-actions">
"+
                "<button btn="" class="ok" ng-click="ok()">{{okText || 'OK'}}</button>"+
                "<button class="cancel btn" ng-click="cancel()">{{cancelText || 'Cancel'}}</button>" + 
            "</div>
" + 
        "</div>
</div>
";
    
    function link(scope){
        scope.cancel = function cancelFunc(){
            scope.showPrompt = false;
            scope.cancelFunction();
        };
        
        scope.ok = function okFunc(){
            scope.showPrompt = false;
            scope.okFunction();
        };
    }
    
    
    return {
        template: template,
        link:link,
        scope:{
            confirmTitle: '=',
            detailText: '=',
            cancelText: '=',
            okText: '=',
            okFunction: '&',
            cancelFunction: '&',
            showPrompt: '='
        },
        restrict : "E"
    };
});

Now the dialogs in action:




Some next steps for this would be to create an even more generic dialog using ng-transclude so you can have your own picture upload dialog.  Likewise, another way I thought of using this confirm dialog was to use this in conjunction with a dialog service that had access to the rootScope.  That way you could have 1 dialog in your root page and have your service open/close that one as necessary.  

No comments:

Post a Comment