Backbonejs collection not populated, but fetch works - javascript

Heres what I've been working on: http://jsfiddle.net/leapin_leprechaun/29aysou5/3/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Results App Training</title>
<script src="js/libs/jquery.js"></script>
<script src="js/libs/underscore.js"></script>
<script src="js/libs/backbone.js"></script>
<script type="text/javascript">
$( document ).ready(function() {
/*
***********
Models
***********
*/
var MatchInfo = Backbone.Model.extend({
defaults: {
season:"1415"
}
});//model class
var matchInfo = new MatchInfo(); //model instance
/*
***********
Collections
***********
*/
var Matches = Backbone.Collection.extend({
model: MatchInfo, //note this references the model class, not the model instance
url : "http://www.hookhockey.com/index.php/temp-gillian/",
sync : function(method, collection, options) {
// By setting the dataType to "jsonp", jQuery creates a function
// and adds it as a callback parameter to the request, e.g.:
// [url]&callback=jQuery19104472605645155031_1373700330157&q=bananarama
// If you want another name for the callback, also specify the
// jsonpCallback option.
// After this function is called (by the JSONP response), the script tag
// is removed and the parse method is called, just as it would be
// when AJAX was used.
//console.log('sync');
options.dataType = "jsonp";
return Backbone.sync(method, collection, options);
},
parse : function(response) {
// console.log(response.matches);
//.matches is what the json at http://www.hookhockey.com/index.php/temp-gillian/ is putting out
return response.matches;
}
}); //collection class
var matches = new Matches(); //collection instance
matches.bind("sync", matches.render, matches);
matches.fetch({
success : function(collection, response, options) {
/* notes: calling these outside of the success listener meant that nothing got returned. This is because they fire before the fetch returns http://stackoverflow.com/questions/9431673/load-data-into-a-backbone-collection-from-json-file
the alternative is to call them within the success function or to call them like so:
.complete(function() {
console.log(matches);
console.log('length: ' + matches.length);
});
..after the fetch call.
*/
console.log('in collection instance fetch success: ' + matches.length);
return response;
},
error : function(collection, response, options) {
console.log(response.statusText);
},
// A timeout is the only way to get an error event for JSONP calls!
timeout : 5000
});
/*
***********
Views
***********
*/
var MatchModelView = Backbone.View.extend({
// template: _.template( $("#matchTemplate").html() ), // removed because template was not being found - uses underscore and the content from index.html script tag with the id of matchElement that contains the template tags
id : 'someID',
className: 'someClassName',
initialize: function () {
_.bindAll(this, "render");
this.collection.bind("reset", this.render);
},
render: function() {
//var matchTemplate = this.template(this.model.toJSON()); //passes in all of the model data (using this.model.toJSON()) into the template (this.template) so that info is available to the template tags
var matchTemplate = '<p>' + this.model.get('title') + '</p>';
this.$el.html(matchTemplate); //pass the templated info into the el element and return it for render
return this;
}
}); //model view class
//var matchModelView = new MatchModelView({model:matchInfo}); //model view instance
//console.log(matchModelView.render().el);
var MatchesModelView = Backbone.View.extend({
id: 'somethingelse',
initialize: function () {
_.bindAll(this, "render");
this.collection.bind("reset", this.render);
},
render: function(){
console.log('collection length in view:' + this.collection.length); //returns 0
this.collection.each(this.oneMatch, this);
return this;
},
oneMatch: function (aMatch){
console.log(aMatch);
var matchView = new MatchModelView ({ model: aMatch });
this.$el.append(MatchView.render().el);
}
}); //collection view class
var matchesModelView = new MatchesModelView({collection: matches });
$("#allMatches").html(matchesModelView.render().el);
/*
***********
Routers
***********
*/
}); //end doc ready
</script>
</head>
<body>
<div class="site">
<div id="allMatches">adasdasd</div>
<div id="copy"></div>
</div>
<script id="matchTemplate" type="text/template">
<%= title %>
</script>
</body>
</html>
I've just put 2 alerts in there to show where I think my issue is. I can see that the call to json is working and returning items. But at the time the view kicks in I suspect the call hasn't gone through fully.
Is it bad practice to call a view from within the .fetch success callback? Am I losing the whole modularity advantage of backbone by doing that? Or am I missing something to get the returned objects into the collection?
I'm new to Backbone so you can ignore all my comments within the code, just trying to keep track!! :) I realise they should all be separated out into different js files too, am just getting to grips with things first.
Thanks for your time!

I see a lot of good things, here. You're embracing the Backbone event-driven model (by rendering on sync, for example) and you're off to a good start.
Your problem is that you're calling render on the collection, and not the view, in your sync callback.
matches.bind("sync", matches.render, matches);
You want to move
matches.bind("sync", matches.render, matches);
matches.fetch({ ... });
until after you've instantiated your view. So, you'd do:
var matchesModelView = new MatchesModelView({collection: matches });
matches.bind("sync", matchesModelView.render, matches);
matches.fetch({ ... });
and notice that I replaced matches.render with matchesModelView.render as the callback of the sync event.

Related

Backbone JS Button to open a new view, save values in form

Im new to backbone and I'm looking to a very simple 2 view configuration page usig backbone.
I have the following code;
define(
["backbone","...","..."],
function(Backbone, ... , ... ) {
var PopupView = Backbone.View.extend({
initialize: function initialize() {
Backbone.View.prototype.initialize.apply(this,arguments);
},
events: {
"click .save_conf_button": "save_conf",
},
render: function() {
this.el.innerHTML = this.get_popup_template();
return this;
},
save:conf: function save_conf() {
//get the field values from popup_template
//var items = jquery(....);
});
var ExampleView = Backbone.View.extend({
//Starting view
initialize: function initialize() {
Backbone.View.prototype.initialize.apply(this, arguments);
},
events: {
"click .setup_button": "trigger_setup", //Triggers final setup
"click .create_conf_button": "trigger_popup_setup", //This is the conf popup
},
render: function() {
this.el.innerHTML = this.get_start_html();
return this;
},
trigger_popup_setup: function trigger_popup_setup() {
console.log("Pop up");
//this.el.innerHTML = this.get_popup_template();
PopupView.render();
...
},
}); //End of exampleView
return ExampleView;
} // end of require asynch
); // end of require
E.g. The ExampleView is the starting view with a couple of fields and 2 buttons; create popup and save. Upon pressing the create_conf_button I want to render the popup view, however this does not seem to work as I expected. (Uncaught TypeError: PopupView.render is not a function)
I'm not sure how to proceed and additionally what the "best practice" is for generating these types of dialogs?
Additionally, keeping the values filled in on the previous page after returning from the popupview would be preferential.
Thanks for any help
try
new PopupView.render()
you have to create an instance to call the methods this way
#ashish is correct, you have to instantiate an instance of the PopupView before calling its render method. Currently, you have defined a blueprint for a view called PopupView, which will act as a constructor for newly created PopupView view instances. In order to use this defined view I would suggest storing it in ExampleView's render or initialize method:
// Example View's initialize method
initialize: function initialize() {
this.popUpView = new PopupView();
Backbone.View.prototype.initialize.apply(this, arguments);
},
then referencing it in your trigger_popup_setup function as follows:
trigger_popup_setup: function trigger_popup_setup() {
console.log("Pop up");
//this.el.innerHTML = this.get_popup_template();
this.popUpView.render();
...
},
As for storing state Backbone models are used for that :)
In general to nest subviews within a master view in Backbone you can do the following:
initialize : function () {
//...
},
render : function () {
this.$el.empty();
this.innerView1 = new Subview({options});
this.innerView2 = new Subview({options});
this.$('.inner-view-container')
.append(this.innerView1.el)
.append(this.innerView2.el);
}
In this example the master view is creating instances of it's subviews within its render method and attaching them to a corresponding DOM element.

Backbone.js: Populating my collection and then appending it to the page

I am working in backbone.js. In the following code I am making a call to the Nutritionix API in order to populate my collection with the JSON response. I am having trouble populating my collection and appending the result as a list. I am doing this in order to test if my collection has been properly populated and in order to test that it will append to the page. However when I test the code out in the browser I don't see the field[brand_name] attribute appended to the page. Is my collection properly populated? How can I see the aformentioned attribute appended to the page? What is wrong with my code?
Here is my Javascript:
$(function(){
var SearchList = Backbone.Collection.extend({
url: "https://api.nutritionix.com/v1_1/search/taco?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=26952a04&appKey=78e2b31849de080049d26dc6cf4f338c",
initialize: function(){
this.bind("reset", function(model, options){
console.log("Inside event");
console.log(model);
});
}
});
var terms = new SearchList();
terms.fetch({
success: function(response,xhr) {
console.log("Inside success");
console.log(response.toJSON());
},
ERROR: function (errorResponse) {
console.log(errorResponse)
}
});
// The main view of the application
var App = Backbone.View.extend({
// Base the view on an existing element
el: $('.container'),
initialize: function(){
this.listenTo(this.model, 'sync', this.render);
// Cache these selectors
// this.total = $('#total span');
this.list = $('#listing');
},
render: function(){
// Calculate the total order amount by agregating
// the prices of only the checked elements
terms.each(function(term){
this.list.append("<li>"+ term.get('field[brand_name]')+"</li>");
}, this);
}
});
});
Here is my HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Interactive Food Guide</h1>
<div>
<input type="text" id="searchBox"> <br/><br/>
</div>
<ul id="listing"></ul>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Backbone and Underscore -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.1/backbone-min.js"></script>
<!-- apps functionality -->
<script src="js/app.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
I can see some errors in the code:
JSON returned by url is an object, and what you should charge in the collection is the array "hits" that is inside the object. The logic of this process is defined in the method "parse" the collection.
The collection was declared out of view. When indicated in view to listen to your collection, you will have problems because the fetch method call before the view can be instantiated, so the view does not realize when the fetch is executed
Here is your code with comments.
$(function(){
var SearchList = Backbone.Collection.extend({
url: "https://api.nutritionix.com/v1_1/search/taco?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=26952a04&appKey=78e2b31849de080049d26dc6cf4f338c",
initialize: function(){
},
//** 1. Function "parse" is a Backbone function to parse the response properly
parse:function(response){
//** return the array inside response, when returning the array
//** we left to Backone populate this collection
return response.hits;
}
});
// The main view of the application
var App = Backbone.View.extend({
// Base the view on an existing element
el: $('.container'),
initialize: function(){
//** 2. the view must listen to an object inside in the view
//** so we create a new instance of SearchList and save it into model var of the view
this.model = new SearchList();
this.model.fetch();
this.listenTo(this.model, 'sync', this.render);
// Cache these selectors
// this.total = $('#total span');
this.list = $('#listing');
},
render: function(){
//** 2. Continue
var terms = this.model;
// Calculate the total order amount by agregating
// the prices of only the checked elements
terms.each(function(term){
this.list.append("<li>"+ term.get('fields')["brand_name"]+"</li>");
}, this);
}
});
//** Create an instance of the view to start the program
var foo = new App();
});
Regards
I think the main issue here is that you forgot to instantiate your app:
new App();
Secondly you need to refer to your data with the correct structure:
term.get('hits')
As term is the model, which contains an array of hits
Lastly, you need your collection in your view, and listen for the sync on your views collection:
this.listenTo(this.collection, 'sync', this.render);
I updated your app.js like so:
$(function(){
var SearchList = Backbone.Collection.extend({
url: "https://api.nutritionix.com/v1_1/search/taco?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=26952a04&appKey=78e2b31849de080049d26dc6cf4f338c",
initialize: function(){
this.bind("reset", function(model, options){
console.log("Inside event");
console.log(model);
});
}
});
// The main view of the application
var App = Backbone.View.extend({
// Base the view on an existing element
el: $('.container'),
initialize: function () {
this.collection = new SearchList();
this.collection.fetch({
success: function (response, xhr) {
console.log("Inside success");
console.log(response.toJSON());
},
ERROR: function (errorResponse) {
console.log(errorResponse)
}
});
this.listenTo(this.collection, 'sync', this.render);
// Cache these selectors
// this.total = $('#total span');
this.list = $('#listing');
},
render: function(){
var context = this;
this.collection.each(function (term) {
_.each(term.get('hits'), function (item) {
context.list.append("<li>" + item.fields.brand_name + "</li>");
});
}, this);
}
});
new App();
});
The correct way is not to use var context = this; but an element on your view. I just wanted to point you in the right direction :-)

Backbone JS view render not displaying [duplicate]

This question already has an answer here:
Unable to display Todo Collection on the page
(1 answer)
Closed 8 years ago.
In the below code, unable to render 'TodoList'. Seems like fetching taking time and so displaying '0' and <div id=​"demo">​</div>​ before only.
and Iam not sure why '3' and 'Descriptions' got displayed later. All I need is to display 'Descriptions List' in the page. Iam able to get data from server but somehow not able to display as soon as the data arrived. Please tell me what changes need to do in the below code?
<html>
<head>
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css">
</head>
<body>
<div id="demo"></div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<script type="text/javascript">
var TodoItem = Backbone.Model.extend({
urlRoot: 'api',
})
var TodoCollection = Backbone.Collection.extend({
model: TodoItem,
url: 'api/todos'
})
var TodoView = Backbone.View.extend({
template: _.template('<h3> ' +'<input type=checkbox ' +'<% if(status === "complete") print("checked") %>/>' +' <%= description %></h3>'),
render: function(){
this.$el.html(this.template(this.model.toJSON()))
}
})
var TodoListView = Backbone.View.extend({
initialize: function(){
this.listenTo(this.collection,'reset',this.render)
this.collection.fetch({reset:true})
},
render: function(){
console.log(this.collection.length)
this.collection.forEach(this.addOne,this)
},
addOne: function(todoItem){
console.log(todoItem.get('description'))
var todoView = new TodoView({model: todoItem})
this.$el.append(todoView.render())
}
})
var todoItem = new TodoItem()
var todoList = new TodoCollection()
var todoListView = new TodoListView({el: '#demo', collection: todoList})
todoListView.render()
console.log(todoListView.el)
</script>
</body>
</html>
Here is the CONSOLE output Iam getting:
0
<div id=​"demo">​</div>​
3
pick up cookies
Milk
Cookies
For starters you might want to take out the {reset: true} from your fetch.
A fetch wil automatically clear the model/collection anyway.
Please also use semicolons at the end of your command, not using them will let the browser interpret where the semicolon should be. This takes time and is error prone (the browser might just place it where you didn't think it would).
if this does not work you might want to do add the fetch into the render doing this:
render: function(){
var that = this;
this.collection.fetch().done(function(data) {
console.log(that.collection.length);
that.collection.forEach(that.addOne,that);
});
},
What also might work, but you need to test this, I personally always use the one above:
render: function(){
this.collection.fetch().done(function(data) {
console.log(this.collection.length);
this.collection.forEach(this.addOne,this);
}, this);
},
and Iam not sure why '3' and 'Descriptions' got displayed later - Because it the result of a async Ajax request.
now, try to change your code (watch comment):
var TodoView = Backbone.View.extend({
template: _.template('<h3> ' +'<input type=checkbox ' +'<% if(status === "complete") print("checked") %>/>' +' <%= description %></h3>'),
clearItem : function(){
this.$el.find("h3").remove();
},
render: function(){
//all DOM manipulation in view
this.$el.append(this.template(this.model.attributes));
return this;
}
})
var TodoListView = Backbone.View.extend({
initialize: function(){
// split "reset" event and "add" event
this.listenTo(this.collection,'reset',this.removeAll);
this.listenTo(this.collection,'add',this.addOne);
this.collection.fetch({reset:true});
},
removeAll : function(){
//method to remove all element from view
//your problem is that this event will fire before ajax request done
console.log("reset!");
var todoView = new TodoView();
todoView.clearItem();
},
addOne: function(todoItem){
//fire when a model in the collection change (automatic after fetch result) for each model.
console.log("add ITEM:",todoItem);
var todoView = new TodoView({model: todoItem})
todoView.render();
}
});
NOTE: Remove todoListView.render() in your code.
Sorry but, my english is too bad. I do not have time to explain better. Try if my code work
EVENTS in backbone: http://backbonejs.org/#Events
FETCH in collection: http://backbonejs.org/#Collection-fetch
RENDER a view: http://backbonejs.org/#View-render

backbone paginator multi model in a view

I have a shopping cart app made with Backbone.Paginator.Fluenced and forked with this example; https://github.com/msurguy/laravel-backbone-pagination
I made some small changes;
when you click over an item link, it opens a bootstrap modal window.
The code is below.
app.views.ItemView = Backbone.View.extend({
tagName: 'div',
className: 'col-sm-4 col-lg-4 col-md-4',
template: _.template($('#ProductItemTemplate').html()),
events: {
'click a.openModal': 'openModal'
},
initialize: function() {
this.model.bind('change', this.render, this);
this.model.bind('remove', this.remove, this);
},
render : function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
openModal : function () {
var view = new app.views.ModalView({model:this.model});
view.render();
}
});
and this is my ModalView to show product details in a modal window.
app.views.ModalView = Backbone.View.extend({
template: _.template($('#modal-bsbb').html()),
initialize: function() {
_.bind(this.render, this);
},
render: function () {
$('#myModalPop').modal({backdrop: 'static',keyboard: true});
$('#myModalPop').html(this.template({
'model':this.model.toJSON()
}));
return this;
}
});
Everything is fine for above codes.
I decided to optimize this code and wanted some improvements on this.
Firstly I am fetching all product data and send these data to modal windows.
I think i must send only main meta data and must fetch details from these window.
So i made a new Backbone Model and Collection;
app.models.ItemDetails = Backbone.Model.extend({});
app.collections.ItemDetails = Backbone.Collection.extend({
model: app.models.ItemDetails,
dataType: 'json',
url : "/api/item-details",
parse: function(response){
return response.data;
}
});
My api returns JSON :
{"data":{"id":8,"title":"Product 8","seo":"product-8","code":"p8","review":"Lorem30"}}
My problem is adding multiple models to ModalView;
I tried a lot of example and questions in blogs&forums couldnt find any solve.
I tried a lot of things ($.extend, to set model and model vs..)
to change ModalView and below codes are last position of them;
app.views.ModalView = Backbone.View.extend({
template: _.template($('#modal-bsbb').html()),
initialize: function() {
_.bind(this.render, this);
},
render: function () {
var itemDetails = new app.collections.ItemDetails(); // this is new line
var model2 = itemDetails.fetch(); // this is new line
$('#myModalPop').modal({backdrop: 'static',keyboard: true});
$('#myModalPop').html(this.template({
'model1':this.model.toJSON(),
'model2':model2.model // this is new line
}));
return this;
}
});
I want to add a second model to my underscore template. But cant!
Firstly when i run below codes on chrome developer console it gets an Object;
but couldnt convert as a new model or JSON.
var itemDetails = new app.collections.ItemDetails();
var model2 = itemDetails.fetch();
console.log(model2); // gets fetch data as an object
I am afraid I am confused about where the problem exactly is.
Sorry guys I am not a backbone expert and probably I am doing something wrong though I searched a lot about it on the forum. I read about it again and again but I could not solve the problem. Could you please help me. Thank you in advance.
SOLVE:
After searchs and by the help of below reply.
I solved my problem.
app.views.ModalView = Backbone.View.extend({
template: _.template($('#modal-bsbb').html()),
initialize: function() {
_.bind(this.render, this);
},
render: function () {
var _thisView = this;
var itemsDetails = new app.collections.ItemsDetails();
itemsDetails.fetch({
success:function(data){
$('#myModalPop').modal({backdrop: 'static',keyboard: true})
.html(_thisView.template({
'model1':_thisView.model.toJSON(),
'model2':data.at(0).toJSON()
}));
}});
}
});
Every request to server using backbone is async, it means that you will not have the returned data immediately after the request, maybe the server still processing the data.
To solve this problem you have 2 ways.
First Way: Callbacks
Inside your Model/Collection
GetSomeData:->
#fetch(
success:=(data)>
console.log data // the returned data from server will be avaiable.
)
Second way: Listen for an trigger.
This one it's more elegant using backbone because you don't write callbacks.
Inside Model
GetSomeData:->
#fecth()
Inside View
initialize:->
#model = new KindOfModel()
#model.on "sync", #render, #
backbone automatically will trigger some events for you, take a read here.
http://backbonejs.org/#Events
As you're already doing, you'll need to listen to some trigger on the collection too
var itemDetails = new app.collections.ItemDetails(); // this is new line
var model2 = itemDetails.fetch(); // here is the problem

backbonejs beginners issue - fetching and displaying json data

Im new to Backbone (dont hate me) but am pulling my hair out trying to do a very simple thing.
Im loading a json file (correctly as I can see it loading in firebug) and I just want to pull some info from it purely for testing (as its my first backbone code)
However, I cant get this working and end up with one blank li tag (code below)
<ul id="phones"></ul>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.rc.1/handlebars.min.js"></script>
<script id="foo" type="text/template">
<li><%= name %></li>
</script>
<script>
var Phones = Backbone.Collection.extend({
url:'http://backbone.local/phones/phones.json'
})
var PhonesView = Backbone.View.extend({
el:'#phones',
initialize:function(){
this.collection = new Phones();
this.collection.fetch();
this.render();
},
template:_.template($('#foo').html()),
render:function(){
var foo = this.collection.toJSON();
$(this.el).html(this.template(foo));
return this;
}
})
var phonesView = new PhonesView();
</script>
Any pointers greatly appreciated.
Cheers,
UPDATE 1
I thought it may be due to fetch being async so i called render in success callback of fetch as below. The console.log fires fine but still no json data in rendered html (i also changed to using handlebars)
<script>
var Phones = Backbone.Collection.extend({
url:'http://backbone.local/phones/phones.json'
})
var PhonesView = Backbone.View.extend({
el:'#phones',
initialize:function(){
var self = this;
this.collection = new Phones();
this.collection.fetch({
success:function(){
console.log('json loaded');
self.render();
}
});
},
template: Handlebars.compile('<li>sdsadsadsadsad {{name}} dsfcdfd</li>'),
render:function(){
var foo = this.collection.toJSON();
$(this.el).html(this.template(foo));
return this;
}
})
var phonesView = new PhonesView();
</script>
With Handlebars, a collection template looks like this:
{{#items}} <li> {{name}} </li> {{/items}}
You also need to wrap your collection JSON in an items object so that the Handlebars template can reference it as above:
var foo = { items: this.collection.toJSON() };
Edit
There's actually one more issue ... collection.toJSON() doesn't convert each model to JSON. So you need to write:
this.collection.models.map(function(x) { return x.toJSON(); });
Fiddle Demo
On your view:
'initialize': function() {
this.template = _.template('<p><% model.text $></p>');
this.collection.fetch({error: function() { console.log(arguments); }, 'success': _.bind(this.onFetch,this) });
return this;
},
'onFetch': function(collection) {
this.collection.on("add", this.onAdd, this);
this.collection.each( _.bind(this.onAdd, this) );
return this;
},
'onAdd': function(model){
//do something like:
this.$el.find('.items').append(this.template({model: model}) )
);
To answer your explicit question of why you only get an empty li. You must send the template some name data. For example:
render:function(){
var firstModel = this.collection.at(0);
var firstName = firstModel.get("name");
$(this.el).html(this.template({name: firstName}));
return this;
}
Of course, the above code is only to understand what's missing, and not how a backbone application should be implemented. I really recommend that you go over the annotated TODO example linked from Backbone's website, and understand the basic patterns that are implemented there.
Update based on your comment:
Different ways of solving this. Really recommend reading: http://backbonejs.org/docs/todos.html
To continue on the "hacky path" of solving this so you can see something:
addOne: function(phone) {
this.$el.append(this.template(phone.toJSON()));
return this;
},
render: function() {
this.$el.html(); //clear everything in the view
this.collection.forEach(_.bind(this.addOne,this)); //Will call addOne for every model in the collection.
return this;
}

Categories