fetch collection using rest api in backbone - backbone.js

In that rest api url, i am getting an json array and have fetch it with EmployeeList collection. using the fetch() only call the rest api. If I didnt use the fetch, the rest api call doesnt work, it tested using the log in api-code. while fetching I get all the details, but I am getting the error,
Uncaught TypeError: this.model is not a constructor backbone-min.js:24
I am new to the backbonejs. Whats the error, why this error will happens. My code is below,
var app = {};
app.Employee = Backbone.Model.extend();
app.employee = new app.Employee();
app.EmployeeList = Backbone.Collection.extend({
model: app.employee,
url:'/api/employ',
parse: function(response) {
return response;
}
})
app.employeeList = new app.EmployeeList();
app.employeeList.fetch();
app.AppView = Backbone.View.extend({
el: '#emp',
initialize: function(){
this.render();
console.log(app.employeeList);
},
render: function(){
this.$el.html('sathish');
}
});
app.appView = new app.AppView();

Change
app.EmployeeList = Backbone.Collection.extend({
model: app.employee,
.....
})
To
app.EmployeeList = Backbone.Collection.extend({
model: app.Employee,
...
})
the model param should be a model class(a constructor function in js) like app.Employee.

You should provide app.Employee() instead of new app.Employee() as a model parameter of the collection.

Related

Backbone model empty after collection fetch

var app = {};
var FoodModel = Backbone.Model.extend({
url: "http://localhost/food"
});
var FoodCollection = Backbone.Collection.extend({
model: FoodModel,
url: "http://localhost/food"
});
var FoodView = Backbone.View.extend({
render: function(){
console.log(this.model.toJSON());
}
});
app.FoodModel = new FoodModel();
app.FoodCollection = new FoodCollection;
app.FoodCollection.fetch();
var myView = new FoodView({model: app.FoodModel})
In this piece of code, the console.log always returns null for data in this.model
If console.log the collection it is full of data, how can i get this.model inside the view to reflect the data in the collection?
I'm not sure where your app is triggering FoodView.render(). It won't happen automatically when you instantiate FoodView and it won't happen when the json response triggers a callback to app.FoodCollection.fetch() unless you are manually calling that in a success callback. If you are doing this, your context may have been lost.
Also, there are a few typos in your code (app.FoodCollection = new FoodCollection();). If not, then can you provide the exact code? Please include whatever code is calling render()
Also, I'm not sure your view is being associated with your model. Try:
var FoodView = Backbone.View.extend({
model: FoodModel,
render: function(){
console.log(this.model.toJSON());
}
});
Otherwise, Backbone has no way of knowing what model you are referring to.

Add model to collection after fetching it

Im having trouble figuring out how to populate a model's attributes from the server and then add the populated model to a collection and have that collection rendered by a view. Here's the code I have:
var movieDetails = new cinephile.Models.MovieDetailsModel({ id: movie.get('id') });
this.collection.add(movieDetails);
Inside of the MovieDetailsModel:
cinephile.Models.MovieDetailsModel = Backbone.Model.extend({
url: function()
{
return '/cinephile/api/index.php?action=getMovieDetails&movieId=' + this.id;
},
initialize: function()
{
this.fetch();
}
});
And this.collection is just a collection with the model set to be a cinephile.Models.MovieDetailsModel
I am listening for items to be added to the collection and when they are, the following is executed:
displayMovie: function(movie)
{
var view = new cinephile.Views.MovieView({
model: movie,
className: 'movie clearfix',
template: JST['app/scripts/templates/MovieView.ejs'],
});
this.$("#my-movies").append(view.el);
},
MovieView looks like this:
cinephile.Views.MovieView = Backbone.View.extend({
initialize: function(options)
{
this.template = options.template;
this.render();
},
render : function()
{
this.$el.html(this.template(this.model.attributes));
return this;
},
});
The problem I have is that the template I'm using is trying to access an attribute of the model that is undefined. Im pretty sure it's undefined because the MoveDetailsModel hasn't finished fetching before the model is added to the collection and subsequently rendered to the view.
How can I solve this issue? I'd like to be able to create a MovieDetailsModel that takes in an id, use that id to get the movie details from the server and then add the populated model to a collection and then render that collection to the screen.
Any help is appreciated.
Backbone fetch returns a jqXHR object, which is a Deferred objects Promise.
When fetch is called, the attributes are not populated yet. Promise objects have a don
ejqXHR function, where a callback can be passed to be executed once the request is done.
I would recommend moving the fetch into another method not the constructor, because there You can return the jqXHR object and access its done function.
Here is an example:
var movieDetails = new cinephile.Models.MovieDetailsModel({ id: movie.get('id') });
var promise = movieDetails.fetch();
promise.done(function() {
var view = new cinephile.Views.MovieView({model: movieDetails});
view.render();
});

Connection between model and collection in backbone and parse.com

i'm trying to connect model and collection using parse.com but i'm confused. I'm tring to fetch by collection using backbone and javascript api parse.com but compare this error:POST https://api.parse.com/1/classes 404 (Not Found).
Model:
var Person = Backbone.Model.extend({
defaults:{
},
initialize:function(){
console.log("inperson");
this.validate();
this.send();
},
validate:function(){
console.log("validate");
},
send:function(){
var user = new Parse.User();
user.set("username", this.get("username"));
user.set("password", this.get("password"));
user.set("email", this.get("email"));
user.signUp(null, {
success: function(user) {
// Hooray! Let them use the app now.
},
error: function(user, error) {
// Show the error message somewhere and let the user try again.
alert("Error: " + error.code + " " + error.message);
}
});
}
});
return Person;
});
Collection:
var Usercollection = Parse.Collection.extend({
model:Person,
initialize:function(){
}
});
return Usercollection;
});
and finally the view that call the colletion and fetch:
var HomeView = Backbone.View.extend({
template: Handlebars.compile(template),
events: {
},
initialize: function() {
console.log("inhomeview");
var amici = new Usercollection();
amici.fetch({
success: function(collection) {
amici.each(function(object) {
console.warn(object);
});
},
error: function(amici, error) {
// The collection could not be retrieved.
}
});
},
render: function() {
}
});
return HomeView;
});
Cant you just swap the backbone collection and model to Parse's ones? (You only used the Parse type of the collection, not the model!)
Try switch that Backbone model to a Parse.Object .
Step by step below:
First of all Lets create a new app on Parse.com, mine is called FunkyAppartments.
Insert the script tag for loading Parse javascript lib into index.html or whathever:
<script src="http://www.parsecdn.com/js/parse-1.5.0.min.js"></script>
Switch the backbone model and collection to use parse types instead (and rename the fetch method if you have extended backbones, since we do not want to overide the one of parse):
//var Appartment = Backbone.Model.extend(); Backbone wo. Parse.com
var Appartment = Parse.Object.extend("Appartment");
//var Appartments = Backbone.Collection.extend({ Backbone wo. Parse.com
var Appartments = Parse.Collection.extend({
model: Appartment,
loadAppartments: function(callback){
debugger;
this.query = new Parse.Query(Appartment);
this.fetch();
}
});
I added a debugger tag in the load appartments so that developer tools breaks in the middle of the controller, here I have access to the Appartment private type of the controller, hence i can store some data on the parse server and verify by pasting the below in the developer tools console.
var testAppartment = new Appartment();
testAppartment.save({name: "foobars"}).then(function(object) {
alert("yay! it worked");
});
Yei, the data shows up in the parse.com UI for the app we just added there. And more importantly it shows up in our frontend. That was easy!
UPDATE: PROBLEMS W BACKBONE 1.2.1, MARIONETTE 2.4.2, UNDERSCORE 1.8.3
I noticed that I actually had been using old versions of marionette, backbone and underscore.js. An initial update appeared to break the application.
After some research i found that it was the parse part that did not return objects that would successfully render. Hence I changed the collection type back to an extension of: Backbone.collection instead of Parse.collection.
I also had to override the query method, since the objects would not save on the correct id, updating an object resulted in a new object being added instead of an old one being updated.
var Apartment = Parse.Object.extend('Appartment');
var Apartments = Backbone.Collection.extend({
model: Apartment,
query: new Parse.Query(Apartment),
initialize: function(){
MyApp.vent.on('search:param', function(param){self.search(param); });
var self = this;
this.query.find({
success: function(results){
self.reset();
results.forEach(function(result){
result.attributes.id__ = result.id
var ap = new Apartment(result.attributes);
self.add(ap);
});
}
});
}
});
I added an attribute: id__ to hold the parse id (naming it just id did not work since it backbone interfered with it, making it disappear).
Finally in saving the model to parse i utilized id__ as id in the save call:
var ApartmentEditView = Backbone.Marionette.ItemView.extend({
template: "#apartment-edit-template",
className: "apartmentDetail",
events: {
"click .store": "storeEdit",
"click .close": "closeEdit"
},
storeEdit: function(){
var priceNum = Number($('#price_field').val().replace(/\s/g, ''));
this.model.set({
id: this.model.attributes.id__,
name:$('#name_field').val(),
price:priceNum,
description:$('#desc_field').val(),
url:$('#url_field').val()
});
this.model.save();
this.closeEdit();
},
closeEdit: function(){
var detailView = new ApartmentDetailView({model: this.model});
MyApp.Subletting.layout.details.show(detailView);
}
});
Now the object is updated correctly in the database.

Laravel 4 and Backbone not playing well together -- JSON improperly formatted

I'm trying to return JSON output from a Laravel route. Here's my route:
Route::get('main-contact-count', function() {
$mc = MainContact::where('flag', '=', '1')->count();
return Response::json(['count' => $mc]);
});
If I look at the response tab in Firebug, I'm getting back:
{"count":9}
The JSON encoding is missing the square brackets. This JSON is different than the JSON Laravel returns from a resourceful controller. It has the square brackets. Backbone parses it fine. Backbone doesn't parse the above JSON correctly. If you look at the length and models when you console.log a collection, they're both zero. You can, however, drill down into the object and you can find a count property set to 9.
How do I get the correct JSON out of Laravel?
Just for kicks and giggles, I'm posting my Backbone, in case I'm doing something hinky there:
App.Collections.Count = Backbone.Collection.extend({
model: App.Models.Count,
initialize: function(models, options) {
this.fetch({
success: function(data, options) {
// console.log(data.models);
}
});
if (options) {
this.url = this.url || options.url;
}
}
});
App.Views.Count = Backbone.View.extend({
tagName: 'span',
className: 'leadCount',
template: _.template($('#contactCount').html()),
initialize: function() {
},
render: function() {
this.$el.html(this.template(this.collection.toJSON()));
return this;
}
});
And in my route:
var mc = new (App.Collections.Count.extend({ url: 'main-contact-count' }))();
var mcv = new (App.Views.Count.extend({ collection: mc }))();
The JSON response sent by your service is a single JSON object ({...}) Your collection is not able to parse it because it expects an array of JSON objects ([{...}, {...}]).
If I've understood your code correctly, /main-contact-count is a specialized service whose function is to return and single datum: a count of contacts. If this is the case, Backbone.Collection may not be the correct solution. Collections are meant for... well, collections of things.
You should use just a model instead:
App.Models.Count = Backbone.Model.extend({
url:'main-contact-count'
});
var countModel = new App.Models.Count();
countModel.fetch({success: function(model, resp) {
var count = model.get('count');
});
Or even better, forego Backbone altogether and just fetch the data using jQuery:
$.getJSON('main-contact-count', function(response) {
var count = response.count;
});
try:
return Response::json(array(array('count' => $mc));

Backbone.js binding collection to models after a fetch using ajax

I'm trying to learn backbone.js and I'm having trouble understanding how to bind models and read them after a fetch.
This is my code:
$(function() {
var Bid = Backbone.Model.extend();
var BidsList = Backbone.Collection.extend({
model: Bid,
url: '/buyers/auction/latestBids?auctionId=26&latestBidId=0',
});
var BidsView = Backbone.View.extend({
el: $('#bids'),
initialize: function() {
log('hi');
_.bindAll(this, 'render');
this.collection = new BidsList();
this.collection.fetch();
this.render();
},
render: function() {
log(this.collection);
return this;
},
});
var bidsView = new BidsView();
});
function log(m) { console.log(m); }
This is what the webservice json looks like
{
"AuctionState":3,
"ClosedOn":null,
"Bids":[
{
"BidId":132,
"AuctionId":26
},
{
"BidId":131,
"AuctionId":2
}
]
}
How do I would I bind that response to the model?
You need to override the parse() method on your BidCollection to pull the Bids out and present them, and them only, to the collection's add() routine. You can do other things with the parse() method to manage the AuctionState field.
You also need to listen for 'change' events in your view, so the view automatically updates after the fetch. You shouldn't need to call render() in your view; you should bind the model's 'change' event to to render(), then fetch the data and let that trigger the render.
As always, Backbone's source code is highly readable. I recommend learning and understanding it.
For example:
var BidsList = Backbone.Collection.extend({
model: Bid,
url: '/buyers/auction/latestBids?auctionId=26&latestBidId=0',
parse: function(response){
return response.Bids;
}
});

Resources