Reusable modals with Ember JS

This Fiddle demonstrates how to build reusable modals with Ember. With CSS transition in and out.

by jkneb

HTML

<script src="http://builds.emberjs.com/handlebars-1.0.0-rc.4.js"></script>
<script src="http://builds.emberjs.com/ember-1.0.0-rc.6.1.js"></script>
<script type="text/x-handlebars" id="index">
    <button {{action showModal 'modal01'}}>show modal 01</button>
    <button {{action showModal 'modal02'}}>show modal 02</button>
    
    {{render modal01}}
    {{render modal02}}
</script>

<script type="text/x-handlebars" id="modal_layout">
    <button {{action "hideModal" target="view"}} class="modal-close">&times;</button>
    <div class="modal-body">
        {{yield}}
    </div>
</script>

<script type="text/x-handlebars" id="modal01">
    {{#view App.ModalView}}
        <p>modal01 content ooh yeah</p>
    {{/view}}
</script>

<script type="text/x-handlebars" id="modal02">
    {{#view App.ModalView}}
        <p>modal02 content omg</p>
    {{/view}}
</script>

SCSS

@mixin transition($params){
    -webkit-transition:#{$params};
       -moz-transition:#{$params};
        -ms-transition:#{$params};
            transition:#{$params};
}

/* reveal logic for the modal 
*/
.modal {
    /* v + h centering */
    position:absolute; margin:auto;
    top:0; bottom:0; left:0; right:0; 
    
    &.shown {
        opacity:1;
        @include transition( top 0ms linear 0ms, 
                             opacity 300ms ease 10ms );
    }
    &.hidden { 
        opacity:0; top:-200%;
        @include transition( opacity 300ms ease 0ms, 
                             top 0ms linear 900ms );
    }
}






/* ----------------------------------- */
/* styles for the purpose of this demo */

.modal { 
    width:250px; height:180px;
    padding:25px; 
    background:white; 
    border:1px solid #ddd; border-radius:4px;
    box-shadow:5px 5px 12px rgba(0,0,0,.1);
}
button {
    border:1px solid #ccc;
    border-radius:3px; padding:4px 10px;
    font-size:12px; cursor:pointer;
    background:#f1f1f1;
    &:hover { 
        background:#3ab6da; 
        color:white; border-color:#3ab6da; 
    }
}
.modal-close {
    position:absolute; top:5px; right:5px;
}
body { padding:25px;
    background:#f9f9f9; 
    font-family:'Helvetica Neue', Arial; 
    font-size:12px; 
}
* { 
    -webkit-box-sizing:border-box; 
    -moz-box-sizing:border-box; 
    -ms-box-sizing:border-box; 
    box-sizing:border-box; 
}

JavaScript

window.App = Em.Application.create();

App.ApplicationRoute = Em.Route.extend({
    events: {
        showModal: function(name){
            this.controllerFor(name).set('modalVisible', true);
        }
    }
});

App.ModalView = Em.View.extend({
    layoutName: 'modal_layout',
    tagName: 'div',
    classNames: ['modal', 'whatever'],
    classNameBindings: ['controller.modalVisible:shown:hidden'],
    
    hideModal: function(){
        this.get('controller').set('modalVisible', false);
    }
});