I'm just starting out with Backbone and I'm having problems generating a simple html list from some JSON data.
I'm getting the error
Uncaught TypeError: Object function (){return c.apply(this,arguments)} has no method 'each'
Here's my code
var Show = Backbone.Model.extend();
var ShowCollection = Backbone.Collection.extend({
model: Show,
url: 'http://192.168.0.7:8081/api/0b08ecef4eda8c6a28b6be3164a96ac8/?cmd=history&type=downloaded&limit=50',
parse: function(response){
return response.data;
}
});
var ItemView = Backbone.View.extend({
tagName: "li",
template: $("#item").html(),
render: function() {
var templ = _.template(this.template);
this.$el.html(templ(this.model.toJSON()));
return this;
}
});
var ShowView = Backbone.View.extend({
el: $("#history"),
initialize: function() {
this.collection = ShowCollection;
this.render();
},
render: function() {
this.collection.each(function(item) {
this.renderItem(item);
}, this);
},
renderItem: function(item) {
var itemView = new ItemView({ model: item });
this.$el.append(itemView.render().el);
}
});
var history = new ShowView();
Here's my data
{
data: [
{
date: "2013-03-16 05:14",
episode: 10,
provider: "-1",
quality: "HD TV",
resource: "bering.sea.gold.s02e10.720p.hdtv.x264-bajskorv.mkv",
resource_path: "/Users/Machine/Tv/Bering.Sea.Gold.S02E10.720p.HDTV.x264-BAJSKORV repost",
season: 2,
show_name: "Bering Sea Gold",
status: "Downloaded",
tvdbid: 254203
}
],
message: "",
result: "success"
}
this.collection = ShowCollection;
should be
this.collection = new ShowCollection();
You're assigning your this.collection to the extended Backbone Collection class, rather than to an instance of it. See the docs on extend for an example. You should have something like this.collection = new ShowCollection().
Related
I know Im pretty close to figuring this out. Im trying to filter out my collection based on if favorite eq true. If I console.log - I can see it's doing its job. But it's not updating my view.
Anyone have any idea what I'm missing or doing wrong?
Here is my code:
var Products = Backbone.Model.extend({
// Set default values.
defaults: {
favorite: false
}
});
var ProductListCollection = Backbone.Collection.extend({
model: Products,
url: '/js/data/wine_list.json',
parse: function(data) {
return data;
},
comparator: function(products) {
return products.get('Vintage');
},
favoritesFilter1: function(favorite) {
return this.filter(function(products) {
return products.get('favorite') == true;
});
},
favoritesFilter: function() {
return this.filter(function(products) {
return products.get('favorite') == true;
});
},
});
var products = new ProductListCollection();
var ProductListItemView = Backbone.View.extend({
el: '#wine-cellar-list',
initialize: function() {
products.bind('reset', this.render, this);
products.fetch();
this.render();
},
render: function() {
console.log(this.collection);
var source = $('#product-template').html();
var template = Handlebars.compile(source);
var html = template(this.collection.toJSON());
this.$el.html(html);
return this;
},
});
// Create instances of the views
var productView = new ProductListItemView({
collection: products
});
var CellarRouter = Backbone.Router.extend({
routes: {
'': 'default',
"favorites": "showFavorites",
"purchased": "showPurchased",
"top-rated": "showTopRated",
},
default: function() {
productView.render();
},
showFavorites: function() {
console.log('Favorites');
productView.initialize(products.favoritesFilter());
},
showPurchased: function() {
console.log('Purchased');
},
showTopRated: function() {
console.log('Top Rated');
}
});
$(function() {
var myCellarRouter = new CellarRouter();
Backbone.history.start();
});
There's many mistakes in your code, I'll try to clarify the most I can :
Your collection should be just like this :
var ProductListCollection = Backbone.Collection.extend({
model: Products,
url: '/js/data/wine_list.json',
comparator: 'Vintage' // I guess you want to sort by this field
});
Your view like this :
var ProductListItemView = Backbone.View.extend({
el: '#wine-cellar-list',
initialize: function() {
this.collection.bind('reset', this.full, this);
this.collection.fetch();
},
full: function() {
this.render(this.collection.models);
},
favorites: function(favorite) {
this.render(this.collection.where(favorite)); // here's the answer to your question
},
render: function(models) {
console.log(models);
var source = $('#product-template').html();
var template = Handlebars.compile(source);
var html = template(models.toJSON()); // You may have to change this line
this.$el.html(html);
return this;
},
});
And in your router :
showFavorites: function() {
console.log('Favorites');
productView.favorites(true); // or false, as you like
}
I am currently trying to render out this json object in a ul. I'd like to be able to cycle through the GamesList and get the games and their attributes in a list. I've kinda hit a wall where I am not entirely sure how to accomplish this. Still very new to backbone so any help would be greatly appreciated.
JSON Object:
{
"GamesList":[
{
"Date":"2013/07/02",
"Games":[
{
"Id":"3252",
"Time":"12:10 AM"
}
]
},
{
"Date":"2013/07/02",
"Games":[
{
"Id":"3252",
"Time":"12:10 AM"
}
]
},
{
"Date":"2013/07/02",
"Games":[
{
"Id":"3252",
"Time":"12:10 AM"
}
]
}
]
}
App Structure:
App.Models.Game = Backbone.Model.extend({
defaults: {
GamesList: ''
}
});
App.Collections.Game = Backbone.Collection.extend({
model: App.Models.Game,
url: 'path/to/json',
parse: function (response) {
return response;
}
});
App.Views.Games = Backbone.View.extend({
tagName: 'ul',
initialize: function () {
this.collection = new App.Collections.Game();
this.listenTo(this.collection, 'reset', this.render, this);
this.collection.fetch();
},
render: function () {
//filter through all items in a collection
this.collection.each(function (game) {
var gameView = new App.Views.Game({
model: game
});
this.$el.append(gameView.render().el);
}, this)
return this;
}
});
App.Views.Game = Backbone.View.extend({
tagName: 'li',
template: _.template($('#gameTemplate').html()),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var gameCollection = new App.Collections.Game();
gameCollection.fetch({
data: {
collection_id: 25
},
success: function (data, textStatus, jqXHR) {
console.log(data);
console.log(textStatus);
console.log(jqXHR);
console.log('success');
},
error: function () {
alert('Oh noes! Something went wrong!')
}
});
var gamesView = new App.Views.Games({
collection: gameCollection
});
$(document.body).append(gamesView.render().el);
It looks like your JSON object is not inlined with Backbone.Collection...
as you declared App.Collections.Game has url /path/to/json which means the json that needs to return is a list... without the GamesList that is seen in your JSON
EDIT:
You can use the parse function in your Games Collection to fix the json retrieved from your server
parse:function(response){
return response.GamesList;
}
Important:
Please note that your json objects that are fetched from the server should have ID. Backbone will 'think' these models are new and will create them upon save...
I'm seeing a little confusion in it. Let's proceed step by step:
--------- AFTER COMMENT ---------
You can set your model as:
defaults: {
Date:'',
Games:''
}
then modifying your parse function as
parse: function (response)
{
var _this = this;
_.map(response, function(obj) {
_this.add(obj)
});
}
This way you add each single item in the collection as your model expect.
Another problem I'm seeing is that you're creating and fetching the collection twice:
...
this.collection = new App.Collections.Game();
this.listenTo(this.collection, 'reset', this.render, this);
this.collection.fetch();
...
and then
var gameCollection = new App.Collections.Game();
...
gameCollection.fetch({
data: {
....
...
var gamesView = new App.Views.Games({
collection: gameCollection
});
I wanna render every waiter from my collection but console still show me error :
Uncaught TypeError: Cannot call method 'toJSON' of undefined
this is my code :
(function() {
window.App = {
Models: {},
Views: {},
Collections: {}
};
window.template = function(id) {
return _.template( $('id' + id).html() );
},
// WAITER MODEL
App.Models.Waiter = Backbone.Model.extend({
defaults: function() {
return {
title: 'Waiter Name',
id: []
};
}
});
// A LIST OF WAITERS COLLECTION
App.Collections.Waiters = Backbone.Collection.extend({
model: App.Models.Waiter
});
// VIEW FOR ALL WAITERS
App.Views.Waiters = Backbone.View.extend({
tagName: 'ul',
render: function() {
this.collection.each(function(waiter) {
var waiterView = new App.Views.Waiter({ model: waiter });
this.$el.append(waiterView.render().el);
}, this);
return this;
}
});
// A VIEW FOR ONE PERSON
App.Views.Waiter = Backbone.View.extend({
tagName: 'li',
template: _.template("<%= title %><%= id %>"),
render: function() {
this.$el.html( this.template(this.model.toJSON()) );
return this;
},
});
waitersCollection = new App.Collections.Waiters([
{
title: 'ferko fristansky',
id: 2
},
{
title: 'ferko bandaska',
id: 3
},
{
title: 'fvwerv fristansky',
id: 4
}
]);
var waitersView = new App.Views.Waiter({ collection: waitersCollection });
$(document.body).append(waitersView.render().el);
})();
You're creating your waiterView with a collection:
var waiterView = new App.Views.Waiter({ collection: waitersCollection });
but App.Views.Waiter is a model-based view; that means that this.model will be undefined inside your App.Views.Waiter and so this will fail:
this.$el.html( this.template(this.model.toJSON()) );
// this is undefined -------------^^^^^
You probably want to create an App.Views.Waiters instead:
var waitersView = new App.Views.Waiters({ collection: waitersCollection });
Then, inside App.Views.Waiters, you'd create one App.Views.Waiter for each model in the collection rather than a new App.Views.extend({ model: waiter }):
render: function() {
this.collection.each(function(waiter) {
var waiterView = new App.Views.Waiter({ model: waiter });
this.$el.append(waiterView.render().el);
}, this);
return this;
}
As an aside, be careful with this:
App.Models.Waiter = Backbone.Model.extend({
defaults: {
title: 'Waiter Name',
id: []
}
});
The values from defaults are shallow copied so everything that uses those defaults will end up using exactly the same id array and that can lead to strange bugs when you have several models sharing the same id array. If you have mutable values in defaults, you usually want to use a function instead so that everyone gets their own distinct values:
App.Models.Waiter = Backbone.Model.extend({
defaults: function() {
return {
title: 'Waiter Name',
id: []
};
}
});
i've created a view to render a collection fetched by parse.com but if i call the view passing it a collection doesn't work.
The function that fetch and send to view:
friends: function () {
var self = this;
var User = Parse.Object.extend("User");
var Amici = Parse.Object.extend("User");
var query = new Parse.Query(User);
query.equalTo("objectId", Parse.User.current().id);
query.find({
success: function (user) {
for (var i = 0; i < user.length; i++) {
user[i].relation("amici").query().find({
success: function (amici) {
console.log(amici);
var friendscollection = new Amicizie(amici);
console.log(friendscollection);
var page = new Homelistuser({
model: friendscollection
});
self.changePage(page);
}
});
}
}
});
},
the console log of friends collection is:
child {length: 3, models: Array[3], _byId: Object, _byCid: Object, url: "https://api.parse.com/1/classes/User"…}
it seems be a correct collection to pass to view but don't render correctly.Ad example this collection render correctly:
child {length: 5, models: Array[5], _byId: Object, _byCid: Object, model: function…}
Why the first collection doesn't work while the last works?
models:Array[] of collection that works is:
Models: Array[5]
0: child
1: child
2: child
3: child
while models:Array[] of collection that doesn't work is:
models: Array[3]
0: Backbone.Model
1: Backbone.Model
2: Backbone.Model
the view:
var Homelistuser = Backbone.View.extend({
tagName: "ul",
id: "list",
template: Handlebars.compile(template),
initialize: function () {
this.model.bind("reset", this.render, this);
$(window).on('orientationchange', this.onOrientationChange);
$(".out").on('click', this.log_out);
$(".prove").on('click', this.prove);
},
events: {
"click .out": "log_out"
},
render: function (eventName) {
$(this.el).empty();
_.each(this.model.models, function (ad) {
$(this.el).append(new SingleUserView({
model: ad
}).render().el);
}, this);
return this;
},
view called by first view:
var SingleUserView = Backbone.View.extend({
tagName: "li",
events: {
"click": "goToDetails",
"click .out": "log_out"
},
template: Handlebars.compile(template),
initialize: function () {
this.model.bind("change", this.render, this);
this.model.bind("destroy", this.close, this);
},
render: function (eventName) {
var ad = this.model.toJSON();
console.log(ad);
ad.cid = this.model.cid;
$(this.el).html(this.template(ad));
return this;
},
I am getting an
Object function (a){return new n(a)} has no method 'has'
error on calling the fetch() method on my model. Heres the code:
var Exercise = Backbone.Model.extend({
defaults: {
idAttribute: 'e_id',
e_id: "-1",
exerciseName: "Exercise",
exerciseDescription: "Address",
exerciseURL: "vimeo.com",
reps: "0",
sequence: "0"
},
initialize: function() {
alert("Exercise!");
}
});
var ExerciseList = Backbone.Collection.extend({
url: "/getWorkoutList.php",
model: Exercise,
initialize: function() { }
});
var Workout = Backbone.Model.extend({
urlRoot: "/getWorkoutList.php",
url: function() {
return this.urlRoot + "?workoutID=" + this.get('workoutId');
},
defaults: {
idAttribute: 'workoutId',
workoutId: "-1",
workoutName: "WorkoutName",
workoutDescription: "WorkoutDescription",
exercises: new ExerciseList()
},
initialize: function() {
_.bindAll(this);
directory.renderWorkout(this);
},
parse: function(response) {
return response;
}
});
var WorkoutList = Backbone.Collection.extend({
url: "/getWorkoutList.php",
model: Workout,
initialize: function() {
_.bindAll(this);
},
parse: function(response) {
return response;
}
});
var WorkoutView = Backbone.View.extend({
tagName: "div",
className: "workout-container",
template: $("#tmp-workout").html(),
initialize: function() {
_.bindAll(this);
this.model.bind('change', this.render, this);
},
render: function(){
console.log("WorkoutView");
var tmpl = _.template(this.template);
this.$el.html(tmpl(this.model.toJSON()));
return this;
},
//add ui events
events: {
"click #workout-details": "getWorkoutDetails"
},
getWorkoutDetails: function (e) {
e.preventDefault();
this.model.fetch();
}
});
var ExerciseView = Backbone.View.extend({
tagName: "exercise",
className: "exercise-container",
template: $("#tmp-exercise").html(),
initialize: function() {
_.bindAll(this);
alert("ExerciseView");
},
render: function(){
console.log("render exercise view");
var tmpl = _.template(this.template);
this.$el.html(tmpl(this.model.toJSON()));
return this;
}
});
var WorkoutListingView = Backbone.View.extend({
el: $("#workouts"),
initialize: function() {
var collection = new WorkoutList();
collection.fetch();
},
render: function() {
var that = this;
_.each(this.collection.models, function(item){
that.renderWorkout(item);
});
},
renderWorkout: function(item) {
var workoutView = new WorkoutView({
model:item
});
this.$el.append(workoutView.render().el);
var that = this;
_.each(workoutView.model.get('exercises').models, function(exercise) {
that.renderExercise(exercise);
});
},
renderExercise: function(item) {
var exerciseView = new ExerciseView({
model:item
});
this.$el.append(exerciseView.render().el);
}
});
Everything works fine when I am retrieving the Workout Collection the fist time. However, when I call getWorkoutDetails, I get the error. By inserting alerts and console.logs in parse() of Workout Model, I've found out that it does get the correct response from server, but for some reason, its giving this error.
Any ideas? Thanks.
OK, after spending a lot of time in the beautiful world of minified javascript spaghetti, I found out that the underscore.js version I was using didnt had the function 'has' in it. Updating underscore.js from 1.2.2 to 1.4.4 solved the problem. Also, my backbone.js version is 0.9.1