Reputation: 6622
I am learning Backbone using a tutorial I found on YouTube. I have had trouble rendering Backbone Views. My html file looks like this and I get no error but the TweetsView
does not show up:
This is a form,this part works like it is supposed to:
<form id="new-tweet">
<label>Author</label><input type="text" id="author-name" name="author-name"/>
<label>Status</label><input type="text" id="status-update" name="status-update"/>
<button>Post</button>
</form>
<hr/>
Then I added the following div
to put all the fake tweets in:
<div id="tweets-container"></div>
I added the 3 dependency libraries:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript" src="scripts/lib/underscore.min.js"></script>
<script type="text/javascript" src="scripts/lib/backbone.min.js"></script>
Tweet and TweetsList do work,I have used them with .toJSON(); to get the object returned successfully:
(function($){
//use model to define a Bean
var Tweet=Backbone.Model.extend({
//pass some defaults in,just in case
defaults:function()
{
return {
//author:'jdorsey',
//status:'And on the eighth day god started learning web design using twitter like applications'
author:'',
status:''
}
}
});
//a group of model-objects collected together
var TweetsList=Backbone.Collection.extend({
//all the models in the collection are of type Tweet
model:Tweet
});
These Views do not seem to be working:
//In Backbone Views are more like Controllers...they allow us to render stuff on the screen...in order to create a view first create a template
//this View represents a single tweet
//creating a new view to use a template:
var TweetView=Backbone.View.extend({
model:new Tweet(),
tagName:'div'/*generating a new DOM element for each tweet*/,
initialize:function(){
this.template=_.template($('#tweet-template').html());
},
render:function(){
//replace the place-holders in the template with the attributes from the model...and the content is going to be
//inserted into the element representing this template...
this.$el.html(this.template(this.model.toJSON()));//bind the model to the template...
return this;//default implementation
}
});
var tweets=new TweetsList();
var TweetsView=Backbone.View.extend({
model:tweets,
el:$('#tweets-container'),
initialize:function(){
this.model.on('add',this.render,this);//pass the context in as the third argument...
},
render:function(){
var self=this;
_.each(this.model.toArray(),function(i){
self.$el.html('');
self.$el.append(new TweetView({model:tweet}).render().$el);
return this;
});
}
});
This is executed once the page has finished loading:
$(document).ready(function(){
$('#new-tweet').submit(function(ev){
var tweet=new Tweet({author:$('#author-name').val(),status:$('#status-update').val()});
tweets.add(tweet);
//.length gives you number of models
//.models is an array that holds all the models
//.first(n) only gives you the first n models
//.toJSON converts it and gives a regular JS object as the output...to convert to JSON,use JSON.stringify
console.log(tweets.toJSON());
return false;
});
var appView=new TweetsView();
});
})(jQuery);
This is the template I am using:
<!-- Use the same names as inside the model in between the less than percent equal and percent greater than-->
<!-- You can put the template anywhere in your HTML but using a script tag is a best practice,if you put it elsewhere,the browser might try to render it often and something stupid might happen -->
<script type="text/template" id="tweet-template">
<span class="author"><%= author %>:</span>
<span class="status-update"><%= status %>:</span>
</script>
Upvotes: 0
Views: 128
Reputation: 626
I can see a few problems.
First, the TweetView
has this line:
model:new Tweet(),
Remove that line. It creates a new instance of the Tweet
model, which you don't want to do in the definition of the TweetView
class. (You provide a model instance directly when you create each instance of TweetView
later, in TweetsView.render
.)
Second, in the _.each
block in TweetsView.render
, you have this line:
self.$el.html('');
Move that line before the _.each
loop. That line clears the entire content of TweetsView
, which you don't want to do inside the loop where you're rendering each row.
Third, in that same _.each
block you're creating a new instance of TweetView
and passing it a model
option:
self.$el.append(new TweetView({model:tweet}).render().$el);
Change the value of the model
option from tweet
to i
, which is the model instance for the current iteration of _.each
. (I don't know what tweet
is here; surprised you don't get a syntax error, but maybe it's defined in part of the file that's not shown.)
Finally, also in the _.each
block, move the return this;
line after the close of the _.each
block, so it's the return statement for the render
function itself. (No return
needed in the _.each
block.)
I think that render
function should then look like this:
render:function(){
var self=this;
self.$el.html('');
_.each(this.model.toArray(),function(i){
self.$el.append(new TweetView({model:tweet}).render().$el);
});
return this;
}
See if it works after those changes.
Upvotes: 3