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.
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 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.
My data model is as given below.
Module
Fields (ObservableArray)
Actions(ObservableArray)
Fields (?)
name (dyanmic from field list)
type (dynamic from field list)
selected (entered by user in UI)
Module is main object. Fields and Actions are observable arrays. Field lists under each action needs to be have updated field list and also will have an additional property which is captured from UI.
How the Fields under action model should be populated? Fields list under each action will have unique value for selected field.
Do I need to subscribe to fields ObservableArray and manipulate the Fields list under each action manually or is there any other better way doing this?
This is how I handle this situation
http://plnkr.co/edit/sWVqrFHdzWUXob42xS7Z?p=preview
Javascript
var childObject = function(data){
var self = this;
//No special mapping needed here, the mapping plugin does it for us
ko.mapping.fromJS(data, {}, self);
this.Select = function(){
self.selected(!self.selected());
};
};
var parentObject = function(data){
var self = this;
//Map the object to myself, using the mapping object we made earlier
ko.mapping.fromJS(data, {}, self);
//Remap the actions column to observable's
this.Actions = ko.observableArray(_.map(self.Actions(), function(item){
return new childObject(item);
}));
};
var myViewModel = function(){
var self = this;
this.RootObject = ko.observable();
var objectData = {
"Fields": [1, 2, 3, 4],
"Actions": [
{
"name": "David",
"type": "string",
"selected": false
},
{
"name": "Nish",
"type": "string",
"selected": true
}]
};
this.Init = function(){
//Pass the object data to the parent object.
self.RootObject(new parentObject(objectData))
};
};
$(function(){
myApp = new myViewModel();
myApp.Init();
ko.applyBindings(myApp);
})
Html
<div data-bind="with: RootObject">
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Selected</th>
</tr>
</thead>
<tbody data-bind="foreach: Actions">
<tr data-bind="click: Select">
<td data-bind="text: name"></td>
<td data-bind="text: type"></td>
<td data-bind="text: selected"></td>
</tr>
</tbody>
</table>
</div>
I am using require.js with backbone and backbone.localstorage and I am trying to figure out how to make use of the data after calling fetch, not sure how to go about it... I am trying to pass the data into my view and make use of it.
Here is the example of the data stored in localstorage:
[{"artist":"Hits 1 Entertainment 4-1-1","title":"Hear Katy's Perry's New Album!"}, ...]
So it is objects within an array.
This is my code for backbone...
var songz = new Songs();
songz.localStorage = new Backbone.LocalStorage("music");
songz.fetch({dataType: 'json'});
var songV = new SongV({collection: songz});
songV.render();
Songs is a collection, that looks like this in the collections file, SongV is the view for each song.
Here is the view with the code above included:
define([
'jquery',
'underscore',
'backbone',
'models/song',
'collections/songs',
'views/song',
'text!templates/page.html'
], function($, _, Backbone, Song, Songs, SongV, PageT){
var Page = Backbone.View.extend({
el: $("#page"),
render: function () {
this.$el.html( PageT );
var songz = new Songs();
songz.localStorage = new Backbone.LocalStorage("music");
songz.fetch({dataType: 'json'});
var songV = new SongV({collection: songz});
songV.render();
}
});
return Page;
});
Here is the collection file:
define([
'jquery',
'underscore',
'backbone',
'models/song',
], function($, _, Backbone, Song){
var Songs = Backbone.Collection.extend({
model: Song,
initialize: function () {
}
});
return Songs;
});
Here is the model file:
define([
'underscore',
'backbone'
], function(_, Backbone) {
var Song = Backbone.Model.extend({
});
return Song;
});
Here is the template file:
<tr>
<th> Number </th>
<th> Title </th>
<th> Artist </th>
<th> Date_Added </th>
<th> Video </th>
</tr>
<% _.each(songs, function(song){ %>
<tr>
<td> <%= song.get("number") %> </td>
<td> <%= song.get("title") %> </td>
<td> <%= song.get("artist") %> </td>
<td> <%= song.get("added_on") %> </td>
<td> <%= song.get("video") %> </td>
</tr>
<% }); %>
You need to fetch and then bind to the reset event on the collection to see when it was successfully pulled the data from the server.
Page = Backbone.View.extend
el: $('#page')
render: ->
songz = new Songs()
# Initialize view
songV = new SongV({collection: songz})
# Render view
songV.render()
# Fetch collection
songz.fetch()
SongV = Backbone.View.extend
initialize: ->
#listenTo #collection, "reset", #onReset
onReset: (collection) ->
# Use populated collection data
...
Songs = Backbone.Collection.extend
model: Song
localStorage: new Backbone.LocalStorage("music")
initialize: ->
This is how Backbone.LocalStorage stores the collections and models --> here
See the table at the bottom, the key for the chain block is you local storage name and then each model has a unique key.
So this means if you have data sitting in local storage that you have put there yourself, you should take it out with a cross-browser local storage device like store.js and then use it to populate your Backbone.Collection.
Alternatively, you could fetch from the server (recommended) and that will populate your collection. Or you could bootstrap the data on page load and reset your collection that way.
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>
...