It is not a secret that I have been playing Dungeon & Dragons with my friends for a long time and that I am passionate about it, I could roleplay more but we have a lot of fun.

I should not be wrong when I say that what is important in a game session is the ratio played time over total time, strategy meetings are ok but consulting manuals and other things should be kept out of the session.

One of the activities my Dungeon Master (Lorenzo) found to be time-sucking was planning the battle order: making a list of the warriors, getting everyone to throw a dice roll, throwing dice for the enemy, the NPC, order the list.

Pencils and paper could be replaced by a laptop but ordering a list is not that easy in a word processor, I do not know if other attempts have been made by Lorenzo but in the end we kept using pencils and papers.

And that is the main problem of today, to update elements in a list and order it when the update is done. Hmmm… if a character could be treated as a model and the company as a collection I would only need a view to display the information and a way to sort the list, I like this MV* approach so let’s see if something can be done with a SPA with Backbone.

Spoiler alert: this is not a working application written with Backbone.js, more or less is a guideline, what really matters is the problem of the view.

I definitely need a model for our heroes with names and values to order them

var Hero = Backbone.Model.extend({
    initialize: function (options) {
        this.name = options.name;
        this.value = options.value;
    }
});

and a collection to keep everyone toghether, with something that can compare model and order them.

We are reversing the order because it is default ascending. We could deal with this in the view, prepending model instead of appending but I would like to leave my view without any extra code.

var Team = Backbone.Collection.extend({
    model: Hero,
    comparator: function (model){
        return -parseInt(model.get('value'));
    }
});

Now we need a view,

var View = Backbone.View.extend({
    template: myTemplate,
    events: {
        'click #addHero': 'addPlayer',
        'click #sortTeam': 'sortHeroCollection'
    },
    initialize: function () {
        this.listenTo(this.collection, 'add', this.render);
    },
    render: function () {
        this.$el.empty();
        this.$el.html(this.template(
            this.collection.toJSON()
        ))
    },
    addPlayer: ...
    sortHeroCollection: ...
})

Ok this is not that performant or anything else, in my real work I used nested views so this will not definitely work as before.

What is important is the template I am using

<!-- this is the hero template -->
<p>
    <!-- name -->
    <span contenteditable="true" title="nome" class="nome">${nome}</span>
    <span>
        <!-- initiative -->
        <span contenteditable="true" class="single-line" title="iniziativa"> ${iniziativa} </span>
        <!-- health -->
        <span contenteditable="true" class="single-line" title="salute"> ${salute} </span>
        <!-- AC -->
        <span contenteditable="true" class="single-line" title="armatura"> ${armatura} </span>
        <!-- listen -->
        <span contenteditable="true" class="single-line" title="ascoltare"> ${ascoltare} </span>
        <!-- spot -->
        <span contenteditable="true" class="single-line" title="osservare"> ${osservare} </span>
    </span> 
    <button class="fa remove fa-remove" title="rimuovi"></button>
</p>

the property contenteditable=true of the span element make it so that I don’t have to update my view when values are updated because the content of the page has already been edited, all I need is an additional event handler attached to my view.

var View = Backbone.View.extend({
    template: myTemplate,
    events: {
        'click #addHero': 'addPlayer',
        'click #sortTeam': 'sortHeroCollection',
        'input': 'update'
    },
    initialize: function () {
        this.listenTo(this.collection, 'add', this.render);
    },
    render: function () {
        this.$el.empty();
        this.$el.html(this.template(
            this.collection.toJSON()
        ))
    },
    addPlayer: ...
    sortHeroCollection: ...
    // you have to find a way to reference models from the view, hence subviews
    update: function (e) {
        this.model.save(
            takeWhatIsUpdated(e),
            {
                patch: true
            }
        )
    }
})

In the same event handler I could wait for validation from the model and the server and update the view to display errors if needed.

I think this is a good trick that we can use, it’s an enhancement both in performance (less views updates) and user experience (less view updates), the only drawback is compatibility and telling the user that even if there is no input field on the page they can submit their changes to the application but a big (dismissable) banner on the top of the page should work.