Sandbox for Backbone + jQuery

Sandbox for testing interplay between Backbone and jQuery libraries.

by Troy Alford

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.10/backbone-min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
<div id="sidebar">
</div>
<div id="main">
</div>

<script type="text/template" id="NrmlListItemTemplate">
    <span>${DisplayName}</span>
    <span class="close"></span>
</script>
<script type="text/template" id="NrmlDisplayTemplate">
    <div class="displayContainer">
        <div class="displayName">${DisplayName}</div>
    </div>
</script>

SCSS

$bgcolor: #268;
$bgimg: url(http://www.placekitten.com/2000/1200);
$closeBtnImg: url(http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_222222_256x240.png);
$spacing: 5px;
$sidebarWidth: 200px;

.icon-user {
    background-image: url(http://www.famfamfam.com/lab/icons/mini/icons/icon_user.gif);
    background-position: 2px center;
    background-repeat: no-repeat;
    padding: 3px 3px 3px 23px;
}

body, html {
    background: $bgcolor;
    margin: 0; padding: 0;
}
#sidebar {
    left: 0; top: 0;
    position: absolute;
    width: $sidebarWidth;
    
    >ul {
        list-style: none;
        margin: $spacing;
        
        >li {
            background-image: url(http://www.famfamfam.com/lab/icons/mini/icons/icon_user.gif);
            background-position: 2px center;
            background-repeat: no-repeat;
    
            background-color: #eee;
            border: 1px outset;
            cursor: pointer;
            position: relative;
            
            >span:first-child {
                display: block;
                margin: 0 20px;
                padding: 3px;
            }   

            >span.close {
                background: $closeBtnImg no-repeat -80px -128px;
                cursor: pointer;
                display: none;
                height: 16px; width: 16px;
                position: absolute;
                top: 4px; right: 4px;
            }
            &:hover>span.close{
                display: inline-block;
            }
        }
    }
}

#main {
    padding: 5px 5px 5px 200px;

    >div.displayContainer {
        background: #eee;
        border: 1px outset;
        display: block;
        padding: $spacing;

        >div.displayName {
            background-image: url(http://www.famfamfam.com/lab/icons/mini/icons/icon_user.gif);
            background-position: 2px center;
            background-repeat: no-repeat;
            padding: $spacing $spacing $spacing 23px;
    
           ...

JavaScript

$(function () {
    
    window.Nrml = Backbone.Model.extend({
        defaults: {    
            OwnerId: '00000000-0000-0000-0000-000000000000',
            OwnerDisplayName: '',
            
            DisplayName: '',
            Slug: '',
            Nrml: ''
        }
    });

    window.NrmlList = Backbone.Collection.extend({
        model: Nrml,
        comparator: function (nrml) {
            return nrml.get('DisplayName');
        }
    });
    
    window.NrmlListItemView = Backbone.View.extend({
        tagName: 'li', // name of (orphan) root tag in this.el
        
        events: {
            'click span.close': 'remove',
            'click span:first-child': 'display'
        },
        
        initialize: function() {
            this.template = $('#NrmlListItemTemplate');
            _.bindAll(this, 'display', 'remove', 'render', 'unrender');
            
            this.model.bind('change', this.render);
            this.model.bind('remove', this.unrender);
        },
        
        display: function() {
            var model = this.model;
            new NrmlDisplayView({model: model}).render();
        },
        remove: function() {
            this.model.destroy();
        },
        render: function() {
            var content = this.template.tmpl(this.model.toJSON());
            $(this.el).html(content);
            return this; // for chainable calls, like .render().el
        },
        unrender: function() {
            $(this.el).remove();
        }
    });
    
    window.NrmlDisplayView = Backbone.View.extend({
        el: $('#main'),
        events: { },
        
        initialize: function() {
            this.template = $('#NrmlDisplayTemplate');
            _.bindAll(this, 'render', 'unrender');
            // fixes loss of context for 'this' in methods
            // should list every function which uses 'this' as an object context
            
            this.model.bind('change', this.render);
           ...