I'm using Backbone.js and Phil Sturgeon's CI rest server (AMAZING TOOL, definitely recommended).
Here is my page: http://interr0bang.net/7357/fetch/. It is very basic, a model (Event), a collection (Events), and a view (EventView). The collection is located at http://api.interr0bang.net/calendar/events and returns a JSON array that has been validated using jsonformatter.curiousconcept.com.
Here's the code:
$(function(){
var Event = Backbone.Model.extend();
var Events = Backbone.Collection.extend({
model: Event,
url: 'http://api.interr0bang.net/calendar/events',
});
var EventView = Backbone.View.extend({
initialize: function(){
_.bindAll(this, "render","count");
this.collection = new Events();
this.collection.bind("change",this.count);
this.collection.fetch();
this.counter = this.collection.length;
this.render();
},
render: function(){
this.el.html(this.counter);
},
count: function(){
this.counter = this.collection.length;
}
});
eventView = new EventView({el:$('#collection')});
});
The view renders fine, but it always displays 0, and Firebug shows the GET request, and the status is 200 OK, but the response body is empty... Why doesn't this work?
You have a configuration problem. If you look at your browser, it reports:
XMLHttpRequest cannot load http://api.interr0bang.net/calendar/events. Origin
http://interr0bang.net is not allowed by Access-Control-Allow-Origin.
I'm currently getting errors from both of the URLs you've posted.
http://interr0bang.net/7357/fetch/ = 404
http://api.interr0bang.net/calendar/events = Unreachable
On a side note, I find it best to keep things as separated as possible (models shouldn't know about views, views shouldn't know about models, etc). For that reason, I would recommend you don't instantiate the collection inside of the view.
Here is a refactored implementation of the above code:
$(function(){
var
Event = Backbone.Model.extend({})
,Events = Backbone.Collection.extend({
model: Event
,url: 'http://api.interr0bang.net/calendar/events'
})
,EventView = Backbone.View.extend({
initialize: function(){
_.bindAll(this, 'count');
this.collection.bind('all', this.count);
}
,count: function() {
this.el.html(this.counter = this.collection.length);
}
})
,events = new Events()
,eventView = new EventView({
el: $('#collection')
,collection: events
})
;
events.fetch();
});
Notice how I'm passing the collection to the view instead of it creating it itself. Also note that I removed the render method and combined it with count. Whenever the collection is changed (add, remove, reset), count
will be called and the view will be updated.
You can not make cross domain Ajax calls, even between sub domains... So basically, your browser, on the domain interr0bang.net
, blocks the Ajax call to your API on the domain api.interr0bang.net
... This is the meaning the JavaScript warning:
Origin http://interr0bang.net is not allowed by Access-Control-Allow-Origin.
You could fix this by moving your API to the same domain, for instance: http://interr0bang.net/api/calendar/events
if you can.
If you can not do that, you can authorize Ajax cross-domain calls by including some header in the response of your API methods. This is the CORS protocol, and it works with most modern browsers.
Here is another Stack Overflow answer concerning CORS that explains how it works: JSONP and Backbone.js
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With