nicosantangelo
nicosantangelo

Reputation: 13726

Abstracting logic in Backbone js

I'm developing a Backbone application using Marionette and I need some help to organize the logic in the code.

Currently I have a few views where I handle really similar logic, I want to abstract this to avoid repetition:

View1

onRender: function() {
    var pluginData = this.$("selector1").plugin();
    var pluginResult = this.handlePluginData(pluginData);
    this.doSomethingWithResult1(pluginResult);
}

View2

onRender: function() {
    var pluginData = this.$("selector2").plugin();
    var pluginResult = this.handlePluginData(pluginData);
    this.doSomethingWithResult2(pluginResult);
}

Etc

Note: handlePluginData do the same thing, doSomethingWithResultN it's different but can be abstracted with a few params.

So the questions are:

Thank you very much!

Upvotes: 5

Views: 1147

Answers (1)

Chickenrice
Chickenrice

Reputation: 5727

I think Backbone View class is abstract enough. All you have to do is to pass different options when you create new View instance.

And I found that you place the calculating logic in View's render method. Because Backbone is a MVC-based framework, so logic should place in Model and View register event handler which is responsible for rendering layout when Model fire event which view is interested.

In my opinion, you could add a Model which handle calculate and redefine your view.

My simple example:

1.Define a model which is respond for logic calculating:

var MathModel = Backbone.Model.extend({
    result: 0,
    initialize: function(){
        console.log("calculate target: "+this.get("selector"));
        console.log("calculate method: "+this.get("method"));
        var number = this.handlePluginData();
        this.doSomethingWithResult(number);
    },
    handlePluginData: function(){
        return $(this.get("selector")).text();
    },
    doSomethingWithResult: function(number){
        if(this.get("method")==="square"){
            this.set({result:(number*number)});
        }else{
            this.set({result:(number*number*number)});
        }

    }
});

2.Redefine the View class:

View will register a listener for model "result" data change event and render a initial layout according to the model you assigned.

var AbstractView = Backbone.View.extend({
        initialize: function(){
            this.listenTo(this.model,"change",this.onModelChange);
            this.number = this.model.get("result");
            this.render();
        },
        render: function(){
            this.$el.html(this.number); 
        },
        onModelChange: function(model){
            this.number = model.get("result");
            this.render();
        },
        plusOne:function(){
            this.model.doSomethingWithResult(this.model.handlePluginData());
        }
    });

3.Pass different options to model when you instantiate a new View.

var view1 = new AbstractView({el:"#result1",model:new MathModel({selector:".square",method:"square"})});
var view2 = new AbstractView({el:"#result2",model:new MathModel({selector:".cubic",method:"cubic"})});

4.HTML:

<div id="select-target">
    <span class="square">2</span>
    <span class="cubic">2</span>
    <button id="plus-one">+1</button>
</div>
<div id="result">
    <span id="result1"></span>
    <span id="result2"></span>
</div>

5.Plus-one button click event handler:

You could observe how View re-render it's layout when model is changed.

$("#plus-one").click(function(){
        $(".square").text(Number($(".square").text())+1);
        $(".cubic").text(Number($(".cubic").text())+1);
        view1.plusOne();
        view2.plusOne();
    });

Hope this is helpful for you.

Upvotes: 1

Related Questions