Search code examples
extjsextjs4many-to-manyassociationsextjs4.2

Implementing Many-to-Many Associations in ExtJS 4


This question has been asked twice before in on SO:

BUT neither of these questions have an actual answer, so I'm going to try again!

Let's say I have two models, User and Group. A user can be in many groups, and groups can contain many users. Here's the model code for User:

Ext.define('User', {
    extend: 'Ext.data.Model',
    alias: 'model.User',
    fields: [
        {name: 'username', type: 'string'},
        ...
    ],
    proxy: {
        // Omitted for brevity...
    },
});

And Group:

Ext.define('Group', {
    extend: 'Ext.data.Model',
    alias: 'model.Group',
    fields: [
        {name: 'name', type: 'string'},
        ...
    ],
    proxy: {
        // Omitted for brevity...
    },
});

Now, let's say I wanted a Grid which lists my groups, and allows me to double-click a group and edit which users are in that group in second grid.

Let's also say there's a lot of users per group, so I don't want to load all the associated users when I load the groups.

I want to be able get a store of users for a particular group, and give that to my grid, which will load data as needed (using the usual pagination that a grid does).

I see two potential approaches here. There may another better way, but I will outline what I've tried do so far below.

Intermediate model

  • Add another joining model
  • Add hasMany associations from User and Group to that model
  • Add belongsTo associations from my joining model back the way to User and Group.

Joining model code:

Ext.define('GroupUsers', {
    extend: 'Ext.data.Model',
    alias: 'model.GroupUsers',
    fields: [
        {name: 'group_id', type: 'int'},
        {name: 'user_id', type: 'int'},
    ],
    associations: [
        {type: 'belongsTo', model: 'User'},
        {type: 'belongsTo', model: 'Group'}
    ],
    ...
});

Association in Group:

associations: [
    {type: 'hasMany', model: 'GroupUsers', name: 'group_users'}
],

I will now be able to access a store of GroupUsers for a particular Group:

group.group_users()

The problem with this approach, is that I can't just bind a store of GroupUsers to my second grid, because I want to display things like the user's name. I could iterate the store's items, fetch each User object with getUser(), add them to another store, and use that for my Grid, but that results in a server request per item! Alternatively, I could use my store of GroupUsers directly, but then would need to do something with renderers and I still need to fetch each User individually.

Direct association

  • Associate User and Group directly with a hasMany association on each

Associations on Group:

associations: [
    {type: 'hasMany', model: 'User', name: 'users', foreignKey: '???'}
],

I can now get a store of actual User objects for a given group:

group.users()

Which would be great, except there's nothing for me to set the foreignKey of the association to. User can't have a group_id field, because a User can have many Groups!


Solution

  • Maybe this is not the answer you look for, but this is how I would solve this issue :

    I would not link the groups and the users with extjs store associations, but rather on the server side.

    In the controller of your grid put something like this :

    init: function(){
        this.control({
            'grid': {itemdblclick: this.onGridItemdblclick}
        })
    },
    onGridItemdblclick: function(grid, record){
        var group_id = record.getId(),
        usersStore = this.getStore('Users');
        usersStore.load({params: {group_id: group_id}});
        var win = Ext.widget('UsersGrid'); // adapt the code to your naming scheme
        win.show();
    }
    

    The request to load the Users store will be sent with an extra parameter group_id. On the server side, your can use this extra parameter to filter your users.