1
votes

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!

1
The way I see it, let's assume we have the store information with the structure GroupId, GroupName, UserId, UserName (a combined store having all the records fetched using join). Let's say we have a grid to show the records which is grouped by GroupId and display a list of Groups, when expanded shows the list of users under that group. Now, assume a button click would rearrange the store and update the grid display to show a list of Users, when expanded shows the list of groups the user is under. The total logic behind this may be implemented with the store's filterBy and grouping grid feature - Mohammad Aftab Uddin
@MohammadAftabUddin thanks for your suggestion, but it doesn't really answer the question, I did say that I don't want to load all the data upfront. - Jamie Cockburn
This is probably no solution for you, but just for the record, ManyToMany associations are supported in ExtJS 5. - matt

1 Answers

3
votes

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.