I have an application using backbone but whenever I call the fetch() method for the collection it returns undefined:
// App
(function () {
window.app = {};
app.collections = {};
app.models = {};
app.views = {};
$(function () {
app.collections.complaintTypes = new app.collections.ComplaintTypesCollection();
app.views.complaintTypesView = new app.views.ComplaintTypesView({ collection: app.collections.complaintTypes });
});
})();
// Collections
(function (collections, model) {
collections.ComplaintTypesCollection = Backbone.Collection.extend({
initialize: function () {
this.fetch();
},
model: model,
url: '/api/ComplaintTypes'
});
})(app.collections, app.models.ComplaintType);
// Models
(function (models) {
models.ComplaintType = Backbone.Model.extend({
idAttribute: 'ComplaintTypeId'
});
})(app.models);
// Views
(function (views) {
views.ComplaintTypesView = Backbone.View.extend({
initialize: function () {
this.collection.on('reset', this.render, this);
},
render: function () {
console.log(this.collection);
}
});
})(app.views);
But this doesn't return anything? If I use fiddler and go to my URL: /api/ComplaintTypes I do retrieve data back so I'm not sure what Im doing wrong here?
Deleting "model" line in the collection file worked for me.
Fetch is async. If you need to get the results, you need to pass a "success" handler, i.e.:
function myHandler(models) {
}
...
this.fetch({success: myHandler});
I think the problem is that you create the view while the collection has not been fetched yet (because of JS's asynchronous behavior). Try this way:
$(function () {
app.collections.complaintTypes = new app.collections.ComplaintTypesCollection();
app.collections.complaintTypes.fetch({success:function(){
app.views.complaintTypesView = new app.views.ComplaintTypesView({ collection: app.collections.complaintTypes });
}});
});
And remove the initialize function from your collection.
Related
I'm having a hard time initializing a simple view with a collection that I'm pulling from an API. Everything I try returns an empty array when I try to return the collection from within the view.
app.models.Employee = Backbone.Model.extend({
});
app.collections.Employees = Backbone.Collection.extend({
Model: app.models.Employee,
url: "http://api.sample.com",
initialize: function(){
this.fetch();
},
parse: function(response){
console.log(response)
},
});
app.views.Container = Backbone.View.extend({
el: $('.container'),
initialize: function(){
this.collection = new app.collections.Employees();
console.log(this.collection)
var that = this;
this.collection.fetch({
success: function(){
that.render();
}
});
},
render: function(){
console.log(this.collection) //returns no models
}
});
You have to use parse correctly:
parse: function(response) {
console.log(response);
return response;
} //`,` - remove it at last item in object
There are 3 problems with your code
You are using parse incorrectly. Per the specifications
The function is passed the raw response object, and should return the
array of model attributes to be added to the collection
so yes, as #Sergey suggested
parse: function(response) {
console.log(response);
return response;
}
or better, just remove your parse function, don't override it.
You are calling your fetch function twice.
First time at this line
this.collection = new app.collections.Employees();
which eventually calls this function
initialize: function(){
this.fetch();
},
Second time is inside your initialize function in the View.
3) You break render
Again, same thing as your parse. You are supposed to
renders the view template from model data, and updates this.el with
the new HTML
Something like this
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
In below code, when i want to use get() method as seen in code return undefined. what's the problem.
<script type="text/javascript">
(function() {
window.App = {
Models: {},
Views: {}
};
window.vent = _.extend({}, Backbone.Events);
})();
//Model
App.Models.User = Backbone.Model.extend({
url: '/users'
});
var user = new App.Models.User();
user.fetch({
success: function (user) {
console.log(user.get('firstname'));
}
});
</script>
That's because the value given to the success callback isn't a Backbone model, it's jsut the raw server responsse. To display the first name as soon as the data is fetched, you can use a deferred (see http://api.jquery.com/jQuery.Deferred/):
var user = new App.Models.User();
$.when(user.fetch()).done(function(){
console.log(user.get("firstname");
});
Your Example is working for me here it is http://jsfiddle.net/YYM43/
Try to see if you have loaded the libs (Backbone.js ...) correctly.
(function() {
window.App = {
Models: {},
Views: {}
};
window.vent = _.extend({}, Backbone.Events);
})();
//Model
App.Models.User = Backbone.Model.extend({
url: 'http://echo.jsontest.com/name/betty/age/22'
});
var user = new App.Models.User();
user.fetch({
success: function (user) {
console.log(user.get('age'));
}
});
I have set up a collection for Logs. The api returns the results as JSON. I saw a previous topic where it was suggested to add the parse method on the collection. Having done so, when I execute the code I am not getting any output to the console. Nevertheless, I am new to Backbone so any insight and/or guidance would be appreciated. My understanding of collection.each may not be correct.
var Log = Backbone.Model.extend({});
var LogList = Backbone.Collection.extend({
model: Log,
url: 'api/logs',
parse: function(response) {
return response.logs;
}
});
var LogListView = Backbone.View.extend({
el: $('#logs-list'),
initialize: function() {
this.collection = new LogList();
this.collection.fetch();
this.render();
},
render: function() {
this.collection.each(function(log) {
console.log('log item.', log);
});
}
});
$(document).ready(function(){
console.log('ready.');
new LogListView();
});
Fetch is asynchronous. Rewrite your code to call render with a callback:
var LogListView = Backbone.View.extend({
el: $('#logs-list'),
initialize: function() {
var self = this;
this.collection = new LogList();
this.collection.fetch().done(function(){
self.render();
});
},
render: function() {
this.collection.each(function(log) {
console.log('log item.', log);
});
}
});
I have Backbone view. It load content (component on backbone with AJAX):
render: function () {
var self = this;
$.get('/Blog', request, function (data) {
self.$el.html(data);
model.trigger('blogContainerLoaded');
});
}
Component code:
window.App = {
init: function (options) {
var BlogModel = Backbone.Model.extend({
});
var model = new BlogModel();
var BlogController = Backbone.Router.extend({
routes: {
"": "posts",
"posts": "posts",
"posts/:postId": "post",
"posts/:postId/": "post",
},
posts: function (anchor) {
window.App.views.posts.render(anchor);
},
post: function (postId, commentId) {
window.App.views.post.render(postId, commentId);
},
});
var controller = new BlogController();
if (notLoaded) {
var views = {
posts: new PostListView({ model: model, controller: controller }),
post: new PostView({ model: model, controller: controller }),
};
this.views = views;
Backbone.history.start();
}
}
};
var PostListView = Backbone.View.extend({
el: $(".posts"),
events: {
"click .js-edit-message": "editMessage",
"click .js-open-post": "navigateToPost",
"click .js-move-post": "move"
},
editMessage: function () {
debugger;
},
navigateToPost: function () {
debugger;
},
move: function () {
debugger;
},
All html code loads with ajax.
It works, but events (clicks and other) not firing!
When I load Blog component without AJAX - events working. Please Help!
Most likely your view is instantiated before your ajax call is complete. Because ajax is asynchronous, while it does load (eventually) your code to initialize the view runs first. Thus, when your view is looking to attach the events to your DOM, the necessary elements are not present.
This would also explain why when you eliminate the ajax portion of it, the code works (it's now synchronous and the DOM is present before you initialize your view code.)
Try putting your initialization code inside the ajax callback like this: (if possible)
render: function () {
var self = this;
$.get('/Blog', request, function (data) {
self.$el.html(data);
self.blogContainer = new BlogContainerView(); // Or however you do it
});
}
Another possibility is to keep your trigger.('blogContentLoaded') then attach the events at that time. Backbone.View's delegateEvents() method might be useful in your case.
Or something of that nature. Now you're guaranteed that the DOM is available for your View object to attach events to.
Alright, so here is my main backbone code
(function ($) {
var Job = Backbone.Model.extend({});
var JobList = Backbone.Collection.extend({
model: Job,
url: "/api/jobs?format=json"
});
var JobView = Backbone.View.extend({
el: $('#jobs'),
_templatesrc: $("#job-template").html(),
_template: {},
initialize: function () {
var self = this;
_.bindAll(this, 'render');
//create the template
this._template = Handlebars.compile(this._templatesrc);
//setup data
this.collection = new JobList();
//response function from server query
var response = function () {
console.log(arguments);
self.render();
};
var response2 = function () {
console.error(arguments);
self.render();
};
this.collection.fetch();
},
render: function () {
console.log("models", this.collection.models);
$(this.el).html(this._template(this.collection.models));
}
});
var view = new JobView();
})(jQuery);
When i do this.collection.fetch() i get nothing. When i do this.collection.fetch({ success:response, error:response2}); the following error is thrown:
Backbone.View.extend.initialize.response2 app.js:29
g.wrapError backbone-min.js:104
f.Callbacks.o jquery.min.js:2
f.Callbacks.p.fireWith jquery.min.js:2
w jquery.min.js:4
f.support.ajax.f.ajaxTransport.send.d
In chrome i can tell that it returns a JSON response though, which looks like
[{"Client":"hi",
"ReporterTime":"\/Date(-62135578800000-0500)\/",
"TimeTaken":PT0S,
"Status":"Start"}]
Any ideas on why Backbone isn't turning my JSON response into the collection?
Unless I'm mistaken PT0S is not valid JSON. Try to return it wrapped in quotes:
[{"Client":"hi",
"ReporterTime":"\/Date(-62135578800000-0500)\/",
"TimeTaken":"PT0S",
"Status":"Start"}]
I've just fixed support for TimeSpans in ServiceStack.Text's JsonSerializer.
Will be available from v3.94+ on NuGet or GitHub.