I need help with my code, I'm trying to learn Backbone for my Social Project. I'm trying to render a view from a collection that I got from an API (deployd API)
Here is the HTML code for the table:
<div class="container-fluid">
<table id= "teachers">
<thead>
<tr>
<th>Name</th>
<th>Last Name</th>
<th>Code</th>
<th>Last time online</th>
</tr>
</thead>
<tbody id="table-body"></tbody>
</table>
</div>
<script type="text/template" id="teacher-template">
<td><%= name %></td>
<td><%= lastname %></td>
<td><%= code %></td>
<td><%= lastactivity %></td>
</script>
Here is the JS code:
var TeacherModel = Backbone.Model.extend({
defaults: {
id:'',
name: '',
lastname: '',
code: '',
lastactivity: ''
}
});
var TeacherCollection = Backbone.Collection.extend({
url: "/teachers",
model: TeacherModel
});
var teachercollection = new TeacherCollection();
teachercollection.url = '/teachers';
teachercollection.fetch({
success: function(collection, response) {
console.log("Done!!");
}, error: function(collection, response) {
alert(response);
}
});
var TeachersView = Backbone.View.extend({
el: '#table-body',
initialize: function() {
this.render();
},
render: function() {
this.$el.html('');
teachercollection.each(function(model) {
var teacher = new TeacherView({
model: model
});
this.$el.append(teacher.render().el);
}.bind(this));
return this;
}
});
var TeacherView = Backbone.View.extend({
tagName: 'tr',
template: _.template($('#teacher-template').html()),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
// Launch app
var app = new TeachersView;
So my question is, how I can pass a collection to a view, or a model of the collection to a view? I want to render the data in each row from the table. The browser gets the collection, as you can see here:
I've been trying for days, and I just can't understand the logic, I have read the documentation, and a little of the Addy Osmani's book but just can't get my head on it, can someone explain it to me? Been looking for answers in this site but some on them include some "add models" stuff, which confuse me more.
(The parameters of the model in the image, differ from the code. I'd translate to make it more easy to understand.)
how I can pass a collection to a view, or a model of the collection to a view?
You are already doing that in your code:
var teacher = new TeacherView({
model: model
});
Here you're passing a model to view's constructor using model option.
You can pass a collection to view via it's constructor like:
var app = new TeachersView({
collection:teachercollection
});
Which you can access inside the view via this.collection and this.model respectively.
var TeachersView = Backbone.View.extend({
el: '#table-body',
initialize: function() {
this.render();
},
render: function() {
this.$el.html('');
this.collection.each(function(model) {
this.$el.append(new TeacherView({
model: model
}).el);
},this);
return this;
}
});
Note that fetch() is asynchronous, so you'll need to wait till it succeeds before rendering the view.
See the suggestions in this answer regarding the changes I made to your render method.
this answer might help understanding a thing or two.
Related
Ive created a simple backbone app that gets data from MySQL database about users to display in a view called LeaderBoardView.
Below is the HTML code for the view,
<body>
<div id="container"></div>
<h1>Leaderboard</h1>
<table class="table" id="modtable">
<tr>
<th>Username</th>
<th>Level</th>
</tr>
</table>
<div id="bbcontent"></div>
Im trying to get data and populate inside the div with bbcontent as the id.
Below is my Backbone model, collection and view,
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js">
</script>
<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.3/backbone-min.js">
</script>
<script language="javascript">
$(document).ready(function() {
alert("heyyyyyy")
//model
var User = Backbone.Model.extend({
idAttribute: "userId",
defaults: {
username: null,
userLevel: null
}
});
//collection
var Users = Backbone.Collection.extend({
model: User,
url: "/CW2/ASSWDCW2/cw2app/index.php/Leaderboard/leaderboard",
});
var usersC = new Users();
var LeaderboardDeetsView = Backbone.View.extend({
model: usersC,
el: $('#bbcontent'),
intialize: function() {
alert("asndasnxdjksa")
usersC.fetch({
async: false
})
this.render()
},
render: function() {
var self = this;
usersC.each(function(c) {
var block = "<div class='name'><h1>" + c.get('username') + "</h1></div>"
self.$el.append(block)
})
}
})
var leaderboardDeetsView = new LeaderboardDeetsView();
});
Problem with this code :
The LeaderboardDeetsView isn't being called hence the collection fetch function inside the initialize function of the LeaderboardDeetsView isn't being called.How can I correct my code? Please help
I'm trying to create a simple hello world with backbone and firebase(using backfire). The code is working to insert data to firebase, but when I try to get data and fill the template, it says "Uncaught ReferenceError: firstName is not defined". On debug I can see the object with the data but I don't know how to provide the template with this object.
Here is the code:
$(document).ready(function(){
var registerModel = Backbone.Model.extend({
defaults: {
firstName: '',
lastName: ''
}
});
var registerColletion = Backbone.Firebase.Collection.extend({
model:registerModel,
firebase: new Firebase("https://XXXXXXXX.firebaseio.com/")
});
var registerView = Backbone.View.extend({
el: $("#myTest"),
itemTemplate: _.template($('#item-template').html()),
events: {
"click #btnSave": "saveToFirebase"
},
initialize: function () {
this.listenTo(registerList, 'add', this.render);
},
render: function(){
$('#divContent').html(this.itemTemplate(this.model.toJSON()));
},
saveToFirebase: function () {
registerList.add({firstName: $("#txtFirstName").val(), lastName: $("#txtLastName").val()});
}
});
var registerList = new registerColletion;
var app = new registerView({model:registerList});
});
The exact point of the exception is on render function:
render: function(){
$('#divContent').html(this.itemTemplate(this.model.toJSON()));
},
The template:
<script type="text/template" id="item-template">
<div class="view">
<p>
<%- firstName %> <%- lastName %>
</p>
</div>
</script>
Can anyone please help me? I think I'm missing something (probably obvious) but I can't see it.
Thank you!
When you create the registerView you're telling it that the underlying model is a registerList (not a registerModel)
var app = new registerView({model:registerList});
Therefore, when the render function is called, it's looking for the firstName property of a registerList, and that property doesn't exist.
Seems like you've got Models and Collections mixed up
I've looked around a ton, and can't find an answer to this issue. I'm trying to take a local JSON file, load it up using Backbone.js and render it to a template in the browser. My file downloads, and the template appears, but it is never populated by the data. Any thoughts? Thanks in advance.
HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>People list</title>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>People list</h1>
<hr />
<div class="page"></div>
</div>
<script type="text/template" id="people-template">
<table class="table striped">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Photo</th>
<th>Video</th>
</tr>
</thead>
<tbody>
<% _.each(PersonCollection, function(Person) { %>
<tr>
<td><%= Person.get("firstName") %></td>
<td><%= Person.get("lastName") %></td>
<td><%= Person.get("age") %></td>
<td><%= Person.get("photo") %></td>
<td><%= Person.get("video") %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
</body>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
JAVASCRIPT
<script>
// MODEL MODEL MODEL
// MODEL MODEL MODEL
var Person = Backbone.Model;
// COLLECTION COLLECTION COLLECTION
// COLLECTION COLLECTION COLLECTION
var PersonCollection = Backbone.Collection.extend({
model: Person,
url: '/people.json',
parse: function (response) {
return response
}
});
// VIEWS VIEWS VIEWS
// VIEWS VIEWS VIEWS
var About = Backbone.View.extend ({
el: '.page',
render: function () {
var that = this;
var people = new PersonCollection();
people.fetch({
success: function (PersonCollection) {
var template = _.template($('#people-template').html(), {PersonCollection: PersonCollection.models});
that.$el.html(template);
}
})
}
});
var About = new About ();
// ROUTES ROUTES ROUTES
// ROUTES ROUTES ROUTES
var Router = Backbone.Router.extend({
routes: {
'': 'home'
}
});
var router = new Router();
router.on('route:home', function () {
About.render();
});
Backbone.history.start();
</script>
JSON SAMPLE
{
"people": [
{
"firstName": "Jane",
"lastName": "Doe",
"age": "32",
"photo": "test_photo",
"video": "test_video"
},
{
"firstName": "James",
"lastName": "Hamm",
"age": "56",
"photo": "test_photo",
"video": "test_video"
},
Thanks again for any suggestions. I'm new to stackoverflow (first question posted) so let me know if I need to provide more information.
If you don't wan't to modify your JSON file, you could change parse function in your PersonCollection to return you the person array. Example:
var PersonCollection = Backbone.Collection.extend({
model: Person,
url: '/people.json',
parse: function (response) {
// Return people object which is the array from response
return response.people
}
});
Backbone Documentation: http://backbonejs.org/#Model-parse
parse is called whenever a model's data is returned by the server, in fetch, and save. The function is passed the raw response object,
and should return the attributes hash to be set on the model. The
default implementation is a no-op, simply passing through the JSON
response. Override this if you need to work with a preexisting API, or
better namespace your responses.
U can directly populate JSON data with your Collection. Collection will take care of populating the data according to the array of JSON objects. In your case if you don't want to change JSON data, i.e. if you want to keep the 'people' attribute as it is, you can populate all data by backbone-relational.js. It helps to work with nested JSON data.
My html template look like this:
<script type="text/template" id="players-template">
<table id="example" class="table table-striped table-bordered table-condensed table-hover">
<thead>
<tr>
<th>Name</th>
<th>group</th>
<th></th>
</tr>
</thead>
<tbody id="playersTable"></tbody>
</table>
</script>
<script type="text/template" id="player-list-item-template">
<td><#= name #></td>
<td>
<# _.each(hroups, function(group) { #>
<#= group.role #>
<# }); #>
</td>
</script>
My backbone view is as follows:
playerView = Backbone.View.extend({
template: _.template( $("#player-template").html() ),
initialize: function ()
if(this.collection){
this.collection.fetch();
},
render: function () {
this.$el.html( this.template );
this.collection.each(function(player) {
var itemView = new app.PlayerListItemView({ model: player });
itemView.render();
this.$el.find('#playersTable').append(itemView.$el);
},this
});
// view to generate each player for list of players
PlayerListItemView = Backbone.View.extend({
template: _.template($('#player-list-item-template').html()),
tagName: "tr",
render: function (eventName) {
this.$el.html( this.template(this.model.toJSON()) );
}
});
The above code works perfectly. Now, I want to use apply jquery datatable plugin wtih bootstrap support. You can find detail here :http://www.datatables.net/blog/Twitter_Bootstrap_2
So, I just added the line inside render as:
render: function () {
this.$el.html( this.template );
this.collection.each(function(player) {
var itemView = new app.PlayerListItemView({ model: player });
itemView.render();
this.$el.find('#playersTable').append(itemView.$el);
$('#example').dataTable( {
console.log('datatable');
"sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i> <'span6'p>>",
"sPaginationType": "bootstrap",
"oLanguage": {
"sLengthMenu": "_MENU_ records per page"
},
"aoColumnDefs": [
{ 'bSortable': false, 'aTargets': [ 2 ] }
]
} );
},this);
},
Now, the jquery datable is not initialized. They just diisplay normal table.
where should I intialized the table to apply jquery datatable?
they worked perfectly without backbone.
Most likely, the jQuery plugin needs the elements to be on the page to work. You don't show where you are calling render on that view, but I am going to assume you are doing something like this:
var view = new PlayerView();
$('#foo').html(view.render().el); // this renders, then adds to page
If this is true, then using the plugin inside render is too early, since the view's html is not yet added to the page.
You can try this:
var view = new PlayerView();
$('#foo').html(view.el); // add the view to page before rendering
view.render();
Or you can try this:
var view = new PlayerView();
$('#foo').html(view.render().el);
view.setupDataTable(); // setup the jQuery plugin after rendering and adding to page
I am running into the issue of getting Uncaught TypeError: Object # has no method 'get' when i try to display data in a template here are the different backbone parts:
Template:
<script type="text/template" id="class-template">
<table class="table striped"></table>
<thead>
<tr>
<th>Picture</th>
<th>First Name</th>
<th>Last Name</th>
<th>Role</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<% _.each(users,function(user){ %>
<tr>
<td><%= user.get('picUrl') %></td>
<td><%= user.get('firstName') %></td>
<td><%= user.get('lastLame') %></td>
<td><%= user.get('role') %></td>
<td><%= user.get('email') %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
Data Models and Collection:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
options.url = 'http://localhost/' +options.url;
});
var Office = Backbone.Model.extend({
defaults: {
street : null,
city : null,
state : null,
country : null,
postal_code : null,
},
initialize: function(){
console.log("==> NEW LOCATION");
// you can add event handlers here...
}
});
var Person = Backbone.Model.extend({
defaults: {
picURL : null,
firstName : null,
lastName : null,
email : null,
role : null,
location : new Office()
},
initialize: function(){
console.log("==> NEW PERSON MODEL");
// you can add event handlers here...
}
});
var Users = Backbone.Collection.extend({
url:'loadData.php?list=16025,28477,28474,25513,16489,58911,04607',
model:Person
});
View:
var ShowClass = Backbone.View.extend({
el: '.page',
initialize: function() {
_.bindAll(this); //Make all methods in this class have `this` bound to this class
},
template: _.template($('#class-template').html()),
render: function() {
var users = new Users();
console.log('calling fetch');
users.fetch();
users.on("reset", function(users){
console.log('rendering with data:'+users.models[0].get('firstName'));
this.$el.html(this.template({users:users.models}));
console.log('finished');
}, this);
}
});
I am able to see the data that is returned from the fetch call, so i know that I am getting data back. It all seems to fall apart when i send it to the template. Thanks in advance for all of your help!
Instead of performing the get() on your script template, you should just pass the raw attributes as oppose to passing in the entire model.
I realize that you also have to change your template but abstracting your template this way and doing the loop outside the template itself would give you a better handle on your error. This will also make your code modular and easier to debug.
View:
users.on("reset", function(users){
_.each(users, function (user) {
var data = user.toJSON();
this.$el.html(this.template({
picUrl: data.picUrl,
firstName: data.firstName }));
}, this);
The template would simply be:
<td><%- picUrl %></td>
<td><%- firstName %></td>
...