How to handle relations in backbone.js [duplicate]
Asked Answered
M

2

11

I'm stuck with how to design my backbone.js application regarding to my model relationships.

If I have an event model , that has a couple of relationships, say a user model can have many events and the event model in turn can have many comments and participations. A user can have many comments and the participation can have one user and one event. Wow, what a mess!

Event has many Comments
Event has many Participations
Event has one User

User has many Events
User has many Participations
User has many Comments

Comment has one Event
Comment has one User

Participation has one User
Participation has one Event

Okey, so my thought was to load a list of events when the user loads the page, and when a user clicks on an event load the rest of the information about that event (comments, participations and user).

So the question is, should I use some sort of global variable to hold all events, users and so on, and when I grab information from the server put it there (and check there before I grab something from the server), maybe in some sort of localstorage (and how do I do this using backbone-relational?).

Another idea I've had is to let every event have its own independent data, the problem with this is that I will probably send redundant data every time I click on an event.

What way do you recommend?

thanks!

Mithridate answered 3/6, 2012 at 15:1 Comment(0)
C
18

Like @mu_is_too_short commented, Backbone-relational might be something you are interested in looking into. With Backbone-relational your models and submodel collections are automatically created and events can be managed across the parent-child relationship.

I'll just give you some sample code so you can get a taste for it. Part of your example code might look something like this.

User has many Events:

User = Backbone.RelationalModel.extend({
    relations: [
        type: Backbone.HasMany,   // Type of relationship
        key: 'events',            // How we reference the sub-models in collection
        relatedModel: 'Event',    // The sub-model type
        collectionType: 'EventCollection',  // The sub-model collection
        reverseRelation: {
            key: 'belongsToUser'            // Key we use to refer to the parent
        }
    ],
    // Other Backbone.Model properties and functions
});

When you create a Backbone-relational model, it automatically creates a collection of submodels for you named after the 'key' that you designate. So each user that you have will have it's own collection of related events tidy-ed up.

Basically, when you create or fetch the User, you give it references to the related models that it needs. So for example, your User id=1 might need Event 5, 7, and 11. (I'm just using IDs). As long as these references are defined in array form then you can lazily load them using Relational's fetchRelated methods.

myUser = new User();
myUser.set({
    name: 'RayMysterio',
    age: '26',
    events: [5, 7, 11]    // Or this might just come with the User object from your server
});

myUser.fetchRelated('events');
// This will go fetch the related events for this user model from the URL you designate.

myUser.get('events');
// The collection of events are treated like an attribute of the User model.

myUser.get('events').find(function(eventModel){
    return // some find condition - or whatever you want to do on that collection
});

You might want to bind certain listeners to the sub-models.

myUser.bind('add:events', function(model, collection) {
    // Whatever code you want to happen when new models are added to the user events coll
});

Etc. Etc.

It's a nice way of producing one to one, one to many, and inverse relationships. This is pretty key. When you define a relationship between models and you create a model.

E.g. you create a new instance of User model.

Backbone-relational automatically creates the inverse link (Event model has an attribute defined by the reverse relation key 'belongsToUser' (or whatever you name it). This makes it pretty handy to traverse up and down the model/sub-model hierarchy.

Based on your relational needs this seems like a good fit.

If you want many to many, there is a round-about way of doing it (using intermediate models) but I've found this to be kind of wonky and I avoid it. Paul-Uithol has been updating Backbone-Relational for some time and new features keep getting added in. The learning curve was a little hard for me at first but once you start getting used to it it's mighty handy.

NOTE: Just to emphasize, Mosselman recommended Require.js and I also strongly agree with this. It has made my code much more manageable. You can tinker (wrap) the Backbone-relational code to make it AMD compliant and it works flawlessly with Require.

UPDATE: backbone-relational now supports require.js as of release 0.8.8 on April 1, 2014 - thanks Kenneth

Changeless answered 4/6, 2012 at 1:29 Comment(2)
Is it possible to relate events to the user via an Event model? myUser.set('events', [myEvent1, myEvent2, myEvent3]); something like that? Or do you have to reference the relationship via the related model id?Hydrology
@orangewarp backbone-relational now supports require.js as of release 0.8.8 on April 1, 2014. See backbonerelational.org/#change-logRetene
E
0

You could in theory load up all the separate collections and then use local filtering on the collections to grab the relevant models when you do your rendering.

You have to consider security issues with this of course.

I was not exactly clear, to me at least, from your question what you are going to do with the information you grab, but I'll try to answer as best I can.

My assumption is that you have some sort of Events with some extra data and you need to display the information related to this. Then you also need to be able to do things like add comments, etc.

As I said, you could consider doing the following:

var Events = Backbone.Collection.extend({
    url: '/events', // You might want to let the app return only an account's events or something, not just ALL events.
    initialize: function(){
        this.fetch();
    }
});

var Comments = Backbone.Collection.extend({
    url: '/comments',
    initialize: function(){
        _.bindAll(this, 'getEventComments');
        this.fetch();
    },

    getEventComments: function(event_id){
        return _.filter(this.models, function(model){ return model.get('event_id') == event_id; });
    }
});
//etc

By using underscore's filter function you can very quickly get the relevant models every time you need them (for example when rendering).

In a way this is the same as you do it in your server side scripting. Some database holds all your tables with records, as your collections will do here, and your code just asks the database for the relevant ones based on some inputs.

Lastly, I will always keep pointing Require.js in combination with Backbone out to people. Shamelessly refering to an answer I gave today, check it out, it will make life easier no matter what: Backbone Design

Edra answered 3/6, 2012 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.