cml cml - 5 months ago 8
HTML Question

How to render Backbone.js view properly

I am trying to learn backbone.js on my own.
I have created a simple view and would like to toggle the visibility of two different DIV elements.

I can't work out how to use Backbone to render it correctly.

Hopefully someone can help to point out what was wrong with my code. Thanks.

Here is the HTML code:

<!DOCTYPE html>
<html>
<head>
<title>Backbone view test</title>
<style type="text/css">
#leftpanel {float:left; height:300px; width:300px; border:1px solid; border- radius:5px;}
#rightpanel {position:relative; left:20px; float:left; height: 300px; width:300px; border:1px solid; border-radius:5px;}
#controlpanel {position:absolute; top:400px;}
</style>
<body>
<div id="container"></div>
<div id="leftpanel">this is left panel</div>
<div id="rightpanel">this is right panel</div>
<div id="controlpanel">
<button id='LeftButton' style="float: left; width: auto;">Hide Left Panel</button>
<button id='RightButton' style="float: left; width: auto;">Hide Right Panel</button>
</div>
<script src="json2.js"></script>
<script src="jquery-1.10.1.min.js"></script>
<script src="underscore-min.js"></script>
<script src="backbone-min.js"></script>
<script src="backbone.localStorage.js"></script>
<script src="1.js"></script>
</body>
</html>


Here is the js code

$(function(){
var token = '';

var appview = Backbone.View.extend({
el: $("#container"),

initialize: function(){
this.lp = this.$("#leftpanel");
this.rp = this.$("#rightpanel");
_.bindAll(this, 'render', 'toggleLeft', 'toggleRight');
this.render();
},

events: {
"click #LeftButton" : "toggleLeft",
"click #RightButton" : "toggleRight"
},

toggleLeft: function(){
token = "left";
this.render(token);
},

toggleRight: function(){
token = "right";
this.render(token);
},

render: function(e) {
if (e === "left") {
this.lp.hide();
this.rp.show();
} else {
this.rp.hide();
this.lp.show();
}
}
});

var app = new appview();
});





So this is the working version html code and java script



HTML

<!DOCTYPE html>
<html>
<head>
<title>Backbone view test</title>
<link href="el.css" rel="stylesheet"></link>
<body>
<div id="container"></div>
<script src="json2.js"></script>
<script src="jquery-1.10.1.min.js"></script>
<script src="underscore-min.js"></script>
<script src="backbone-min.js"></script>
<script src="backbone.localStorage.js"></script>
<script src="1.js"></script>
</body>
</html>


JavaScript

$(function(){
var appview = Backbone.View.extend({
el: "#container",

initialize: function(){
var lp = this.$(".rightpanel");
_.bindAll(this, 'render', 'toggleLeft', 'toggleRight');
this.render();
},

events: {
"click .LeftButton" : "toggleLeft",
"click .RightButton" : "toggleRight"
},

toggleLeft: function(){
this.$(".leftpanel").hide();
this.$(".rightpanel").show();

},

toggleRight: function(){
this.$(".rightpanel").hide();
this.$(".leftpanel").show();
},

render: function(e) {
var viewHtml = '<div class="leftpanel">this is left panel</div>'
viewHtml += '<div class="rightpanel">this is right panel</div>'
viewHtml += '<div class="controlpanel">'
viewHtml += '<button class="LeftButton" style="float: left; width: auto;">Hide Left Panel</button>'
viewHtml += '<button class="RightButton" style="float: left; width: auto;">Hide Right Panel</button>'
viewHtml += '</div>'
this.$el.empty().append(viewHtml);
}
});

var app = new appview();
});


Now let say I already have the necessary plugin for jquery UI and would like to use the theme to create "button with icon on the left", how do I apply it on above code and make it work for the same thing?

Appreciated if any experts can guide me on this. Thanks in advance.

Answer

You need to create the HTML for the view in your render function, not have it sitting in the HTML page like you have currently. Then you can control the hiding and showing of the elements in the relevant toggle functions in your view.

So here is what to do:

1) Delete the following from your HTML

<div id="leftpanel">this is left panel</div>
<div id="rightpanel">this is right panel</div>
<div id="controlpanel">
<button id='LeftButton' style="float: left; width: auto;">Hide Left Panel</button>
<button id='RightButton' style="float: left; width: auto;">Hide Right Panel</button>
</div>

2) Modify your render function to be as follows:

render: function(e) {
    var viewHtml = '<div class="leftpanel">this is left panel</div>'
    viewHtml += '<div class="rightpanel">this is right panel</div>'
    viewHtml += '<div class="controlpanel">'
    viewHtml += '<button class='LeftButton' style="float: left; width: auto;">Hide Left Panel</button>'
    viewHtml += '<button class='RightButton' style="float: left; width: auto;">Hide Right Panel</button>'
    viewHtml += '</div>'
    this.$el.empty().append(viewHtml);
}

3) Change your events to use classes, instead of ids:

events: {
    "click .LeftButton" : "toggleLeft",
    "click .RightButton" : "toggleRight"
},

4) Change your toggle left and toggle right functions:

toggleLeft: function(){
    this.$(".leftpanel").hide();
    this.$(".rightpanel").show();
},

toggleRight: function(){
    this.$(".rightpanel").hide();
    this.$(".leftpanel").show();
},

Note that I changed your id attributes to class attributes, this is generally better as it means you can reuse the view in more than one location. Its not a problem as they are scoped to the view when you select them by doing this: this.$(".leftpanel"). Note that you'll have to amend your CSS to reflect this change too.

Also, the way I have placed the HTML to render as a string in your render function is not the best way to handle this. It would be better to use a templating library. There are planty out there and there is one that ships with Backbone as well. using a templating library will allow you to reuse your HTML snippets better and not pollute your views with ugly strings.