How to fetch a single view from a backbone collection? - backbone.js

I have a simple backbone app that fetches a collection from a JSON file which works fine. But I really want to fetch a single modal from the collection. Ideally I want to fetch the model using the locale attribute.
How can I do this?
So far I have the following code,
var Item = Backbone.Model.extend({
defaults:{
"locale":"",
"name":"",
}
});
var ItemsCollection = Backbone.Collection.extend({
model: Item,
url: 'data/items.json'
});
var items = new ItemsCollection();
var itemView = new ItemView({model: items});
items.fetch({
success: function() {
itemView.render();
}
})
Json structure is this,
[
{
"locale": "gb",
"name": "British"
},
{
"locale": "de",
"name": "German"
}
]
Thanks

Related

Backgrid:render isn't being called

Backgrid is rendering
<table class="backgrid"></table>
but nothing else. Breakpoints in Backgrid:render() are not reached. I'm a Backbone newbie adapting someone else's code and so am not sure exactly what should be happening but LayoutManager:render() is called..it just never seems to get to Backgrid... The data I want to display are being fetched and look as if they are in the right format...but have to admit that it's difficult to tell once they've been wrapped up in a Backbone collection. Any pointers for how to debug/why Backgrid's render is not being called gratefully received.
Code below:
ListenView.js
define([
'backbone',
'underscore',
'backgrid',
'app/models/PersonModel',
'app/collections/PersonCollection',
'app/views/PersonListView',
'hbs!app/templates/listen_template'
],
function(
Backbone,
_,
Backgrid,
Person,
PersonCollection,
PersonListView,
listenTemplate
) {
App = window.App || {};
var ListenView = Backbone.View.extend({
template: listenTemplate,
initialize: function(params) {
//fetch the list of seen people
this.model.attributes.seenPeople.fetch( {
success: function(coll, resp) {
//console.log(coll);
}
});
},
afterRender: function() {
//initialise person view
console.log("creating Backgrid");
this.seenPeopleView = new Backgrid.Grid({
columns: [{
name: "email",
label: "Email",
cell: "string"
},{
name: "id",
label: "ID",
cell: "integer"
}, {
name: "title",
label: "Title",
cell: "string" }
],
collection: this.model.attributes.seenPeople
});
this.seenPeopleView.render();
$('#seen-people-list').append(this.seenPeopleView.el);
}
On the success method from the fetch you should call afterRender.
var self=this;
this.model.attributes.seenPeople.fetch( {
success: function(coll, resp) {
self.afterRender();
}
});
Instead of creating backgrid instance in view (this.seenPeopleView) create instance as
var grid = new Backgrid.Grid({...<your columns and collection related code>..});
Then Render the grid and attach the root to your HTML document as
$('#seen-people-list').append(grid.render().el);
Hope it will work :)

Backbone, getting parameters others than data in collection

Given the following json:
{
"admin": false,
"data": [
{
value: key,
value :key
},
{
value: key,
value :key
}
]
}
I defined my collection like this:
var myCollection = Backbone.Collections.extend({
url: myurl.com,
parse : function (response) {
return response.data;
}
});
It works like charm, it fill my collection with the data array, however, into the tamplate, I need to render some content when admin is equal true. But I cannot find a way to pass that value to the template.
Any chance any of u kind guys can point it into the right direction to solve this?
You could save the admin flag as a property of the collection in the parse method:
var myCollection = Backbone.Collection.extend({
model: myModel,
isAdmin: false,
...
parse : function (response) {
this.isAdmin = response.admin; //save admin flag from response
return response.data;
}
});
Then you could retrieve it and pass it to your template or use it in any other way in the view render method:
var myView = Backbone.View.extend({
collection: new myCollection(),
...
render: function(){
//retrieve admin flag from collection:
var isAdmin = this.collection.isAdmin;
//you could add it into the json you pass to the template
//or do anything else with the flag
}
});
You can try this fiddle with a very basic render function.

How to call a custom JSON request, then build a collection of models from that, using Backbone.js?

I'm new to Backbone.js and have been trying to understand three things:
1) How and where to call a custom JSON request?
2) How to translate that JSON request into a model?
3) How to create a collection of those models?
My JSON looks something like this:
{"flavor": "vanilla",
"message": "ok",
"count": 10,
"rows": [{"data":["this", "is", "123", "something"],
"moreData": "more stuff here",
"moreInfo": "more info here"},
{"data":["even", "more", "456", "something"],
"moreData": "even more stuff here",
"moreInfo": "even more info here"},
{"data":["it", "doesn't", "123", "end"],
"moreData": "more and more stuff here",
"moreInfo": "more and more info here"}]
}
I want to have each "data" be an Item. I want a List to contain many Items.
I have to make a custom JSON request (not via $.ajax or anything like that - it is in a separate library that has to be called via a specific function, that provides a callback option) - do I make this call in the Backbone.Model or the Backbone.View?
Basically the JSON response format that I will be getting is not within my control, hence the messy sample above. I'd like to format some of this JSON into nicer attributes as a bonus. I was hoping to do it in the Item model.
How can I translate that request into a model? If I have to modify certain attributes?
How can I create a collection of those models? So far I have
var ItemList = Backbone.Model.extend({
})
var ItemLists = Backbone.Collection.extend({
model: ItemList,
});
var ItemView = Backbone.View.extend({
el: $("#dashboard"),
template: _.template($("#item-template")),
initialize: function(){
this.render();
},
render: function(){
var item = new Item();
var content = this.template(item);
$(this.el).html(content);
}
});
Please help, any Backbone.js experts. This should be a relatively straightforward question for someone experienced!
var ItemList = Backbone.Model.extend({
parse: function(response) {
// response = {"data":["this", "is", "123", "something"],
// "moreData": "more stuff here",
// "moreInfo": "more info here"}
// You can make additional changes here
return response;
}
});
var ItemLists = Backbone.Collection.extend({
model: ItemList,
parse: function(response) {
return response.rows;
}
});
Is this what you were thinking? This takes the rows and makes each one into an ItemList. You can do other manipulation within the parse, if needed. Then you can set the url and use fetch.

backbone data view not showing

I have been having a few issue with backbone so decided to do a very simple tutorial.
After getting this working I tried to simplify it but now cannot get it working.
I think the problem is around returning the view to the screen..
here is the code
var Theater = {
Models: {},
Collections: {},
Views: {},
Templates:{}
}
Theater.Models.Movie = Backbone.Model.extend({})
Theater.Collections.Movies = Backbone.Collection.extend({
model: Theater.Models.Movie,
url: "scripts/data/movies.json",
initialize: function(){
console.log("Movies initialize")
}
});
Theater.Templates.movies = _.template($("#tmplt-Movie").html())
Theater.Views.Movies = Backbone.View.extend({
el: $("#mainContainer"),
template: Theater.Templates.movies,
//collection: new Theater.Collections.Movies(), //Not needed
initialize: function () {
_.bindAll(this, "render");
this.collection.bind("reset", this.render, this);
},
render: function () {
$(this.el).append(this.template(this.collection.toJSON())) ;
}
})
Theater.Router = Backbone.Router.extend({
routes: {
"": "defaultRoute"
},
defaultRoute: function () {
Theater.movies = new Theater.Collections.Movies()
new Theater.Views.Movies({ collection: Theater.movies });
Theater.movies.fetch();
}
})
var appRouter = new Theater.Router();
Backbone.history.start();
and here is the very basic html
<div id="mainContainer"></div>
<script type="text/template" id="tmplt-Movie">
<div><%=name %> </div>
</script>
thanks
this.collection.toJSON()) converts collection into a json, so trying to access name on it in the template won't give you anything.
You can write your render method like this:
render : function() {
var _view = this;
this.collection.each(function(model) {
$(_view.el).append(_view.template(model.toJSON())); // assuming model has 'name' attribute which is accessed in the template code
});
}
This should work.
You have an incorrect template
template: Theater.Templates.movies,
In the render function use
var template = _.template( $("#tmplt-Movie").html(), this.collection.toJSON() );
this.$el.html( template );
Try that. If it fails. Try some console to log to check that fetch is being called, the collection is being populated and that render is being called. If render is being called then it just a matter of correcting a small mistake that will probably be related to dom selection.
It seems that you want to provide a collection to the template, and that the template should loop through the collection and present the values. You can provide a collection to a template, but that’s probably not the best way.
The primary problem seems that you are using a colleciton where you should be using an model. In the render function you are passing a collection to the template. The template should take Models Json.
This is where sub views can be used. So you would want a primary view that takes a collection and that primary view will call a subview that will accept a model.
I did provide an example on jsFiddle.net. It’s somewhat of an hack. Instead of passing a colleciton into the template, I passed an individual item from the collection. This will only render 1 model. Since Routing can be confusing, I went ahead and removed it.
Example on jsFiddle.net. I sometime have problems with IE and jsFiddle.net. I recommend using the Chrome Browser.
this.$el.append(this.template(this.collection.at(0).toJSON()));
Just this month I did started creating more simple tutorials on Backbone.js. This list of tutorial is located at the bottom of this page:
More Simple Backbone.js Examples
Hopefully soon, I will have the time create a simple tutorial on rendering colletion.
Here's the complete code
<div id="mainContainer"></div>
var Theater = {
Models: {},
Collections: {},
Views: {},
Templates: {}
};
Theater.Models.Movie = Backbone.Model.extend({});
Theater.Collections.Movies = Backbone.Collection.extend({
model: Theater.Models.Movie,
//url: "scripts/data/movies.json",
initialize: function() {
console.log("Movies initialize")
}
});
Theater.Templates.movies = _.template($("#tmplt-Movie").html());
Theater.Views.Movies = Backbone.View.extend({
el: $("#mainContainer"),
template: Theater.Templates.movies,
//collection: new Theater.Collections.Movies(), //Not needed
initialize: function() {
_.bindAll(this, "render");
this.collection.bind("reset", this.render, this);
},
render: function() {
this.$el.append(this.template(this.collection.at(0).toJSON()));
}
});
var movies = new Theater.Collections.Movies();
var movieView = new Theater.Views.Movies({ collection: movies });
var myMovies =
[{
"Id": "BVwi1",
"Name": "Bag It",
"AverageRating": 4.6,
"ReleaseYear": 2010,
"Url": "http://www.netflix.com/Movie/Bag_It/70153545",
"Rating": "NR"
},
{
"Id": "BW1Ss",
"Name": "Lost Boy: The Next Chapter",
"AverageRating": 4.6,
"ReleaseYear": 2009,
"Url": "http://www.netflix.com/Movie/Lost_Boy_The_Next_Chapter/70171826",
"Rating": "NR"
}];
movies.reset(myMovies);
I hope this help.

Can't get template to display using backbone.js and underscore

I'm really new to Backbone, and I've looked everywhere to try and figure this out. Fundamentally I get how Models, Views, Collections and Templates work together, but for some reason I just can't get my Collection to render in a template. Using Firebug, I get a "this.model is undefined"
Here's my code:
(function($) {
window.Category = Backbone.Model.extend({});
window.Categories = Backbone.Collection.extend({
url: "src/api/index.php/categories?accounts_id=1",
model: Category
});
window.categories = new Categories();
categories.fetch();
window.CategoriesView = Backbone.View.extend({
initialize:function () {
_.bindAll(this,"render");
this.model.bind("reset", this.render);
},
template:_.template($('#tpl-category').html()),
render:function (eventName) {
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
var testTargetvar = new CategoriesView({ el: $("#collection") });
})(jQuery) ;
This is the data that my REST service generates:
[
{
"name": "Web Design",
"id": 0
},
{
"name": "Web Development",
"id": 0
},
{
"name": "Waste Management Solutions",
"id": 0
}
]
The "fetch" that I'm using does show the fetched data in Firebug.
And lastly, here's my template:
<div id="collection"></div>
<!-- Templates -->
<script type="text/template" id="tpl-category">
<span><%=name%></span>
</script>
I've verified that all the necessary scripts, jquery, backbone, underscore, etc. are being loaded onto the page properly.
I don't see where you're setting the model property of the view object. Your view constructor also seems to be confused between whether it represents the collection of categories (as suggested by the #collection selector) or a single category (as suggested by the template and use of the model property). Here is a working example that should help guide you to your complete solution:
http://jsfiddle.net/RAF9S/1/
( function ( $ ) {
var Category = Backbone.Model.extend( {} );
var Categories = Backbone.Collection.extend( {
url : "src/api/index.php/categories?accounts_id=1",
model : Category
} );
var categories = new Categories( [
{ name : "One" },
{ name : "Two" },
{ name : "Three" }
] );
var CategoryView = Backbone.View.extend( {
initialize : function () {
_.bindAll( this,"render" );
this.model.bind( "reset", this.render );
},
template : _.template( $( '#tpl-category' ).html() ),
render : function ( eventName ) {
this.$el.empty().append(
$( this.template( this.model.toJSON() ) ).html()
);
if ( ! this.el.parentNode ) {
$( "#collection" ).append( this.el );
}
return this;
}
// render
} );
var view, views = {};
categories.each( function ( category ) {
view = new CategoryView( {
tagName : 'span',
model : category
} );
view.render();
views[ category.id ] = view;
} );
} )( jQuery );
In this case I've simply manually populated the collection with several models in lieu of your fetch method. As you can see, I instantiate a view for each model and pass the model object as the model property.
In the render method I empty the view element (this.el / this.$el), then render the template and append the content of its root element to this.$el. That's so I get the new content without wiping out the element itself. Then, for the purposes of this example, I test whether the element is already in the document, and if not I append it to #container.
I always load my templates in my functions...that might help..
initialize: function(){
_.bindAll(this, 'render');
this.template = _.template($('#frame-template').html());
this.collection.bind('reset', this.render);
},
render: function(){
var $stages,
collection = this.collection;
this.template = _.template($('#frame-template').html());

Resources