Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js collection fetching with JSON

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?

like image 510
jessie james jackson taylor Avatar asked Sep 01 '11 04:09

jessie james jackson taylor


3 Answers

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.
like image 100
Elf Sternberg Avatar answered Oct 29 '22 05:10

Elf Sternberg


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.

like image 23
fearphage Avatar answered Oct 29 '22 06:10

fearphage


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

like image 4
Tricote Avatar answered Oct 29 '22 04:10

Tricote