backbone model get throws undefined error - javascript

app.Model.Brand = Backbone.Model.extend({});
app.Collection.BrandCollection = Backbone.Collection.extend({
model: app.Model.Brand,
parse: function (response) {
return response.brandDTOList;
}
});
var brandcollection = new app.Collection.BrandCollection();
brandcollection.url = '/brands';
brandcollection.fetch({
success: function (collection, response, options) {
app.views.brandline = new app.View.BrandPanelView({
model: brandcollection
});
$('#tab-content').empty();
$('#tab-content').append(app.views.brandline.render());
}
});
In this view a single model is passed.
app.View.BrandItemPanelView = Backbone.View.extend({
initialize: function (options) {
this.views = {};
this.model.bind('destroy', this.remove, this);
},
events: {
'click .bra-edt': 'brandEditAction',
},
brandEditAction: function () {
this.model.get('image');
}
});
When i do this.model.get('image'); i get get is not a function.
I am not sure why i am getting such a error.
I tried to deep clone it but still no success. The values are there.
var newModel = new app.Model.Brand();
newModel = $.extend(true, {}, self.model);
newModel.get('image')

Your problem is where you are passing in your BrandCollection, instead of passing it in as a collection you are passing it in as a model.
So instead of
app.views.brandline = new app.View.BrandPanelView({
model: brandcollection
});
You probably want to do
app.views.brandline = new app.View.BrandPanelView({
collection: brandcollection
});

How are you instantiating the BrandItemPanelView?
You will have to pass in the model explicitly:
var view = new app.View.BrandItemPanelView({ model: myModel });
If myModel is in fact a Backbone model, it ought to have the get function...
view.model // should return your model
view.brandEditAction() // should run the function and get the 'image' attribute from your model

Related

Backbone.js this.collection.models works when rendering view but then returns empty array when called somewhere else

var Order = Backbone.Model.extend({
url: function() {
return 'http://localhost:51782/api/orders/'+this.id;
}
});
var DataSetOrders = Backbone.Collection.extend({
url: "http://localhost:51782/api/orders",
model: Order,
initialize: function(){
this.fetch({
success: this.fetchSuccess,
error: this.fetchError
});
},
// This is where my data is being extracted I am returning the
// response since its an array of all the objects within my database
// perhaps i should not use return? Is there a way to save this information so it can always
// be available when i call DataSetOrders();?
fetchSuccess: function (collection, response) {
// console.log('Collection fetch success', response);
// console.log('Collection models: ', collection.models);
return response;
},
fetchError: function (collection, response) {
throw new Error("Orders fetch error");
}
});
var DataSetOrdersView = Backbone.View.extend({
el: $("#orders"),
// collection: new DataSetOrders(),
initialize: function () {
this.collection = new DataSetOrders();
this._modelBinder = new Backbone.ModelBinder();
this.render();
this.$el.find("#filter").append(this.createSelect());
this.on("change:filterType", this.filterByStatus, this);
this.collection.on("reset", this.render, this);
this.collection.on("add", this.renderOrder, this);
this.collection.on("remove", this.removeOrder, this);
},
render: function () {
this.$el.find("article").remove();
// This is the line where we are getting all of our models and rendering it to the #orders view
// as you can see it is referencing the this.collection = new DataSetOrders()
// This is actually working the view is being rendered and I can see the orders being pulled from
// the database
_.each(this.collection.models, function (item) {
this.renderOrder(item);
}, this);
},
renderOrder: function (item) {
// The item which is an element of the previous array returned is now being placed in the model
// and its being rendered prefectly.
var orderView = new OrderView({
model: item
});
this.$el.append(orderView.render().el);
// this.$el.append(this._modelBinder.bind(orderView.render().el));
},
getTypes: function () {
// HERE!!! IS where this.collection is now = [] wtf?!? I dont know why its doing this pleace help me!!
return _.uniq(this.collection.pluck("OrderStatus"), false, function (type) {
return type.toLowerCase();
});
},
Guys sorry for the long code, but I have a simple question. Why does the first time my code calls when using the method render this.collection has the elements within it and because of my code structure it renders my database objects and works perfectly. But when I call this.collection again on my geTypes function I get an empty array I dont understand whats going on??

how to access changed attributes after fetch? backbone.js

I'm using this code to fetch a model from a server:
var id = args.model.get('id');
var options = {
action: 'getSubscriber',
address: args.model.get('address'),
silent: true
};
new Subscriber({ id: id }, options).fetch({
success: function(model, response) {
console.log(response);
console.log(model);
}
});
the response object contains all the data I need whereas model stores the data not as its direct attributes but as changed object. Is it wrong?
Usually I access model attributes with help of model.get('name') call. How do I access fresh attributes in that case? Should it be model.changed.thePropertyIwantToAccess?
You can use this change event
this.model.on('change', function () {
var changedAttributes = this.model.changedAttributes();
//Process the changed attributes
}, this);
Bind this events in the initialize function of the View
Ended up with this:
var Subscriber = Backbone.Model.extend({
defaults: {
id: null,
name: null,
status: null
// ...
},
initialize: function(attributes, options) {
var _this = this;
this.options = options || {};
this.on('change', function() {
_this.set(_this.changedAttributes()['0']);
});
}
// ...

Backbone collection view url firing twice

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.

Returning variable outside backbone function

I am trying to return profile.toJSON() to an object so as to use it outside the above code. I am not understanding exactly how backbone function works, so i declare a global variable obj and trying to parse data with obj = profile.toJSON(). When i use console.log(obj) it displays successfully my data. When I put console outside the above code it returns underfined.
var obj;
var ProfileView = Backbone.View.extend(
{
el: "#profiles",
template: _.template($('#profileTemplate').html()),
render: function(eventName)
{
_.each(this.model.models, function(profile)
{
var profileTemplate = this.template(profile.toJSON());
obj = profile.toJSON();
$(this.el).html(profileTemplate);
}, this);
return this;
}
});
You're taking it by the wrong end. Precreate your model and pass it to a view. Don't try to extract something from the view rendering code, it's not meant to be used this way.
var Profile = Backbone.Model.extend({});
var ProfileCollection = Backbone.Collection.extend({
model: Profile
});
var ProfileListView = Backbone.View.extend({
...
// Everything render does is rendering
render: function() {
this.collection.each(function(model) {
this.$el.append(
this.template(model.toJSON);
);
}, this);
}
...
});
// Your profile instance is defined outside the view, making
// it de facto available to outside code
var profile = new Profile({
name: 'Fere Res',
rep: 48
});
// The profile we just created gets added to a collection
var profiles = new ProfileCollection([profile]);
// We create the profile list view and pass it the collection
var view = new ProfileListView({collection: profiles});
// When we render the view, the render() code defined above is called.
// You can easily see that all the params/variables it uses are in place
view.render();
// Rendering is done, let's check our model is still available
console.log(profile.toJSON()); // :)
I ve got this code which actually fetch data from json file:
$(function() {
var Profile = Backbone.Model.extend({
defaults: {
tstamp: "",
map:"",
tagsCloud:"",
sentiment: "",
usersCloud: "",
timeline: "",
highlights: "",
signals: ""
},
initialize: function() {
}
});
var ProfileList = Backbone.Collection.extend({
model: Profile,
url: 'data.json'
});
var ProfileView = Backbone.View.extend({
el: "#profiles",
template: _.template($('#profileTemplate').html()),
render: function(eventName) {
_.each(this.model.models, function(profile){
var profileTemplate = this.template(profile.toJSON());
//obj = profile.toJSON();
//console.log(obj.tstamp);
$(this.el).html(profileTemplate);
}, this);
return this;
}
});
var profiles = new ProfileList();
var profilesView = new ProfileView({model: profiles});
setInterval(function() {
profiles.fetch({reset: true});
}, 400); // Time in milliseconds
profiles.bind('reset', function () {
profilesView.render();
});
});
I tried to add profiles to a new collection:
var profiles1 = new ProfileList([profiles]);
var view = new ProfileView({collection: profiles1});
view.render();
console.log(profile.toJSON());
I ve got console message: Cannot read property 'models' of undefined

How to use the original Backbone collection after filtering?

I'm relatively new to Backbone and though I know the general idea of how to use it, my learning has been rapid and I'm probably missing some key elements.
So I have a collection that contains an attribute called "type" which can be article, book, video, class. I have the view rendering and everything but I need to be able to filter the collection when links are clicked.
My question is - how can I get it to filter down the collection and still be able to refilter the original collection when I click on another type?
Here's the gist of my code, I simplified it for easy reading:
var TagsView = Backbone.View.extend({
initialize: function(query) {
this.collection = new TagsCollection([], {query: self.apiQuery} );
this.collection.on('sync', function() {
self.render();
});
this.collection.on('reset', this.render, this);
},
render: function() {
//renders the template just fine
},
filter: function() {
//filtered does work correctly the first time I click on it but not the second.
var filtered = this.collection.where({'type':filter});
this.collection.reset(filtered);
}
});
update: I managed to get this working. I ended up triggering a filter event.
var TagsCollection = Backbone.Collection.extend({
initialize: function(model, options) {
this.query = options.query;
this.fetch();
},
url: function() {
return '/api/assets?tag=' + this.query;
},
filterBy: function(filter) {
filtered = this.filter(function(asset) {
return asset.get('type') == filter;
});
this.trigger('filter');
return new TagsCollection(filtered, {query: this.query});
},
model: AssetModel
});
And then in my view, I added some stuff to render my new collection.
var TagsView = Backbone.View.extend({
initialize: function(query) {
this.collection = new TagsCollection([], {query: self.apiQuery} );
this.collection.on('sync', function() {
self.render();
});
this.collection.on('filter sync', this.filterTemplate, this);
this.collection.on('reset', this.render, this);
},
render: function() {
//renders the template just fine
},
filterCollection: function(target) {
var filter = $(target).text().toLowerCase().slice(0,-1);
if (filter != 'al') {
var filtered = this.collection.filterBy(filter);
} else {
this.render();
}
},
filterTemplate: function() {
filterResults = new TagsCollection(filtered, {query: self.apiQuery});
console.log(filterResults);
$('.asset').remove();
filterResults.each(function(asset,index) {
dust.render('dust/academy-card', asset.toJSON(), function(error,output) {
self.$el.append(output);
});
});
},
});
The reason it's not working a second time is because you're deleting the models that don't match your filter when you call reset. That's normal behaviour for the reset function.
Instead of rendering with the view's main collection, try using a second collection just for rendering which represents the filtered data of the original base collection. So your view MIGHT look something like:
var TagsView = Backbone.View.extend({
filter: null,
events: {
'click .filter-button': 'filter'
},
initialize: function (query) {
this.baseCollection = new TagsCollection([], {query: self.apiQuery} );
this.baseCollection.on('reset sync', this.filterCollection, this);
this.collection = new Backbone.Collection;
this.collection.on('reset', this.render, this);
},
render: function () {
var self = this,
data = this.collection.toJSON();
// This renders all models in the one template
dust.render('some-template', data, function (error, output) {
self.$el.append(output);
});
},
filter: function (e) {
// Grab filter from data attribute or however else you prefer
this.filter = $(e.currentTarget).attr('data-filter');
this.filterCollection();
},
filterCollection: function () {
var filtered;
if (this.filter) {
filtered = this.baseCollection.where({'type': this.filter});
} else {
filtered = this.baseCollection.models;
}
this.collection.reset(filtered);
}
});
To remove any filters, set a button with class filter-button to have an empty data-filter attribute. collection will then be reset with all of baseCollection's models
Here's a better answer to this. Instead of making it so complicated, you can just use the where method. Here's my replacement solution for the question above.
filterby: function(type) {
return type === 'all' ? this : new BaseCollection(this.where({type: type});
});
You can try using comparator function of your Collection.
http://backbonejs.org/#Collection-comparator
Basically its is like sorting your collection.

Categories