Monday, November 7, 2011

Converting to Backbone-Relational

‹prev | My Chain | next›

Over the past couple of nights, I have built up a decent Backbone.js "has many" relationship. In my calendar application, an appointment can have several associated people invited to attend the appointment:


I implemented the "invitees" list as a collection, which is a property of the appointment. And that seems to work fairly well.

Today, I would like to give Backbone-relational a try.

First up, I install backbone-relational by copying it directly from the github repository into my application:
➜  calendar git:(backbone-relational) wget \
  https://raw.github.com/PaulUithol/Backbone-relational/master/backbone-relational.js \
    -O public/javascripts/backbone-relational.js
Then I add it to my application:
<script src="/javascripts/underscore.js"></script>
<script src="/javascripts/backbone.js"></script>
<script src="/javascripts/backbone-relational.js"></script>
<script src="/javascripts/calendar.js"></script>
Next up, I make my Appointment model a Backbone.RelationalModel instead of a vanilla Backbone.Model:
    var Appointment = Backbone.RelationalModel.extend({
      urlRoot : '/appointments',
      initialize: function(attributes) {
        if (!this.id)
          this.id = attributes['_id'];

        // this.loadInvitees();
      },
      // ...
    });
I also comment out the loadInvitees() call that had been responsibly for loading in the invitees collection.

To get relationships working, I need to define a relations attribute on my Appointment model:
    var Appointment = Backbone.RelationalModel.extend({
      // ...
      relations: [
        {
          type: Backbone.HasMany,
          key: 'invitees',
          relatedModel: 'Invitee',
          collectionType: 'Collection.Invitees'
        }
      ],
      // ...
    });
But, when I reload my application, I see many errors to the effect of:
Relation= child; no instance, key or relatedModel (child, "invitees", undefined)
It takes me a lot of digging, but I eventually trace this down to the way that I encapsulate my Backbone application in namespaces:
window.Cal = function(root_el) {
  var Models = (function() {
    var Invitee = Backbone.RelationalModel.extend({ /* ... */ });

    var Appointment = Backbone.RelationalModel.extend({ /* ... */ });

    return {
      Appointment: Appointment,
      Invitee: Invitee
    };
  })();

  // ...
};
It turns out, at least upon initial examination, that Backbone-relational requires these classes to be global variables so that it can store and look them up. Ick:
window.Cal = function(root_el) {
  var Models = (function() {
    Invitee = Backbone.RelationalModel.extend({ /* ... */ });

    Appointment = Backbone.RelationalModel.extend({ /* ... */ });

    return {
      Appointment: Appointment,
      Invitee: Invitee
    };
  })();

  // ...
};
With that, I can load data from my collection by manually fetching the related "invitees":


I still have a ways to got before the I can hook this into my application. I will get started on that tomorrow.

Day #198

2 comments:

  1. Chris, I was able to make Backbone-relational work in an isolated namespace by specifying the relation name as a string, rather than a reference. Instead of

    relatedModel: Spiral.Dataset

    use


    relatedModel: "Spiral.Dataset"

    And it works.

    ReplyDelete
  2. Thanks for the tip.

    I had tried that without luck. I could very well have been hitting a different issue at the time and wound up conflating the two. It is good to know that it should work (it really seemed like it should).

    I'll give it another try tonight now that I have solved most of my other issues. If that does work, then I'm golden with Backbone-relational, so big thanks for pointing that out :)

    ReplyDelete