Heres my code:
var RowsSubView = Backbone.View.extend({
initialize: function() {
log.debug(this.collection);
},
render: function() {
var html = RowView();
this.setElement(html);
return this;
}
});
var View = BaseView.extend({
id: 'wrapper',
className: 'container-fluid',
events: {
},
initialize: function() {
_.bindAll(this, 'render');
log.debug('Initialized Queue View');
this.opportunities = new Opportunities();
this.opportunities.on('add', function(model){
});
this.opportunities.fetch({
success: function(response, options) {
},
error: function(response) {
}
});
},
render: function() {
var template = QueueView();
this.$el.html(template);
this.renderRowsSubView();
return this;
},
renderRowsSubView: function() {
// render rows
this.row = new RowsSubView({collection: this.opportunities});
this.row.render();
this.$el.find('tbody').append(this.row.el);
}
});
Heres my question:
Sorry for the noob question! I am learning Backbone and having a bit of an issue. I've looked at a bunch of tutorials/guides, but I think I've confused myself.
I am trying to create a list of items and render them in a table. I want to pass each item into my template and spit it out in the view.
I am stuck after passing my collection to my RowsSubView. I'm not sure how to render each object in the template. Then insert those.
PS: I am able to log this.collection in my RowsSubView and see an object with the array of items.
Thanks.
Ok well start with this. Looks like there's quite a bit of cleanup that needs to be done =)
var RowsSubView = Backbone.View.extend({
initialize: function() {
log.debug(this.collection);
},
render: function() {
//var html = RowView(); // Looks like you're already placing a tbody as the container
//this.setElement(html);
this.collection.forEach(function( model ){
this.$el.append( RowView( model.toJSON() ) ); // Assuming RowView knows what to do with the model data
});
return this;
}
});
Then change the renderRowsSubView to
renderRowsSubView: function() {
// render rows
this.row = new RowsSubView({collection: this.opportunities});
this.row.render();
this.$el.find('tbody').append(this.row.$el.html());
}
For those that this might help, heres what I ended up with:
var RowsSubView = Backbone.View.extend({
initialize: function() {
},
render: function() {
var html = RowView({
opp: this.model.toJSON()
});
this.setElement(html);
return this;
}
});
var View = BaseView.extend({
id: 'wrapper',
className: 'container-fluid',
events: {
},
initialize: function() {
_.bindAll(this, 'render', 'add');
log.debug('Initialized Queue View');
this.opportunities = new Opportunities();
this.opportunities.on('add', this.add);
this.fetch();
},
add: function(row) {
this.row = new RowsSubView({model: row});
this.row.render();
$('tbody').append(this.row.el);
},
fetch: function() {
this.opportunities.fetch({
data: $.param({
$expand: "Company"
}),
success: function(response, options) {
// hide spinner
},
error: function(response) {
// hide spinner
// show error
}
});
},
render: function() {
var template = QueueView();
this.$el.html(template);
return this;
}
});
return View;
});
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've created 2 separate views, 1 to render the template and the other one is where I bind the events, then I tried merging them into one in which case it causes an Uncaught TypeError: Object [object Object] has no method 'template'. It renders the template and the events are working as well, but I get the error.
edit.js, this is the combined view, which I think it has something to do with their el where the error is coming from
window.EditView = Backbone.View.extend ({
events: {
"click #btn-save" : "submit"
},
initialize: function() {
this.render();
},
render: function() {
$(this.el).html(this.template());
return this;
},
submit: function () {
console.log('editing');
$.ajax({ ... });
return false;
}
});
var editView = new EditView();
signin.js, this is the view that I can't merge because of the el being used by the ajax call and in SigninView's $(this.el) which causes the rendering of the templates faulty
window.toSigninView = Backbone.View.extend ({
el: '#signin-container',
events: {
"click #btn-signin" : "submit"
},
initialize: function() {
console.log('Signin View');
},
submit: function() {
$.ajax({ ... });
return false;
}
});
var toSignin = new toSigninView();
window.SigninView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
$(this.el).html(this.template());
return this;
}
});
and I use utils.js to call my templates
window.utils = {
loadTpl: function(views, callback) {
var deferreds = [];
$.each(views, function(index, view) {
if (window[view]) {
deferreds.push($.get('templates/' + view + '.html', function(data) {
window[view].prototype.template = _.template(data);
}));
} else {
alert(view + " not found");
}
});
$.when.apply(null, deferreds).done(callback);
}
};
In my Router.js, this is how I call the rendering of templates
editProfile: function() {
if (!this.editView) {
this.editView = new EditView();
}
$('#global-container').html(this.editView.el);
},
utils.loadTpl (['SigninView', 'EditView'],
function() {
appRouter = new AppRouter();
Backbone.history.start();
});
I think that I figured out your problem.
First merge your views and delete the line var toSignin = new toSigninView();
Second modify your utils.js code like this :
window[view].prototype.template = _.template(data);
new window[view]();
So my application below is actually firing "FIRE!" in the console twice on page load. Not sure why backbone is firing the url function twice when I am only seeing the one fetch being made. Any ideas as to why this might be causing it to fire twice?
window.ScheduleApp = {
Models: {},
Collections: {},
Views: {}
};
window.template = function(id) {
return _.template($('#' + id).html());
};
//Define the Game Model.
ScheduleApp.Game = Backbone.Model.extend({
initialize: function() {
this.gameId = this.get('Id');
this.gameTime = this.get('Time');
}
});
//Define the Games Collection that contains Game Models.
ScheduleApp.Games = Backbone.Collection.extend({
model: ScheduleApp.Game
});
//Define the Day Model.
ScheduleApp.Day = Backbone.Model.extend({
initialize: function() {
this.games = new ScheduleApp.Games(this.get('Games'));
this.games.parent = this;
this.gameDayGDT = this.get('GeneratedDateTime');
this.gameDayDate = this.get('Date');
}
});
//Define the Days Collection that contains the Day Models.
ScheduleApp.Days = Backbone.Collection.extend({
model: ScheduleApp.Day,
url: function() {
console.log('FIRE!');
return '/js/test.json'
},
parse: function(data) {
var parsedSchedule = JSON.parse('[' + data.STUFF + ']');
return parsedSchedule;
}
});
ScheduleApp.DayCollectionView = Backbone.View.extend({
el: '.container', //Container where the views get rendered to.
initialize: function() {
this.listenTo(this.collection, 'reset', this.render);
},
render: function(event) {
if (this.collection.length === 0) {
$('.container-hidden').show();
}
//Cycle through collection of each day.
this.collection.each(function(day) {
var dayView = new ScheduleApp.DayView({
model: day
});
this.$el.append(dayView.render().el);
}, this);
return this;
}
});
ScheduleApp.DayView = Backbone.View.extend({
tagName: 'div',
className: 'game-date',
template: _.template($("#gameSchedule").html(), this.model),
initialize: function() {
this.listenTo(this.model, "reset", this.render);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var daysList = new ScheduleApp.Days();
daysList.fetch({
reset: true,
update: true,
cache: false,
success: function(collection, response) {
//console.log(collection);
},
error: function(model, resp) {
// console.log('error arguments: ', arguments);
// console.log("error retrieving model");
}
});
//create new collection view.
var daysCollectionView = new ScheduleApp.DayCollectionView({
collection: daysList
});
All models belonging to a collection build their URLs based on the collection URL, as stated here. My guess would be that your collection is calling the method once, then your model / models place the second call, in order to build the model URL.
Then again, this method seems pretty harmless to me: it's just a getter. I'd rather place the console.log call in the Collection#parse or Model#initializer methods, and count how many times it gets invoked there.
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 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