0
votes

I have two entities, User and Role both with manyToMany association to each other.

Then I have a grid displaying the list of users and on the rightside a form with user details including a tagfield which will show and allow select roles for the user.

If the binding for the tagfield is set as

bind: {
          store: '{roles}',
          value: '{mainGrid.selection.roles}'
       }

then it don't show the roles that the user already has and throws:

"Uncaught TypeError: parentData[association.setterName] is not a function"

when one tries to set the user roles

So I've also tried to bind the tagfield value to a formula like

bind: {
         store: '{roles}',
         value: '{userRoles}'
      }

and the tagfield shows the roles of the selected user but I don't know how to set the selected roles back to the user entity.

My models are:

Ext.define('App.model.security.User', {
    extend: 'App.model.Base',

    entityName: 'User',

    fields: [
        { name: 'id' },
        { name: 'email'},
        { name: 'name'},
        { name: 'enabled', type: 'bool'}
    ],

    manyToMany: {
        UserRoles: {
            type: 'Role',
            role: 'roles',
            field: 'id',
            right: {
                field: 'id',
                role: 'users'
            }
        }
    }
});

and

Ext.define('App.model.security.Role', {
    extend: 'App.model.Base',

    entityName: 'Role',

    fields: [
        { name: 'id' },
        { name: 'name'},
        { name: 'enabled', type: 'bool'}
    ],

    manyToMany: {
        RoleUsers: {
            type: 'User',
            role: 'users',
            field: 'id',
            right: {
                field: 'id',
                role: 'roles'
            }
        }
    }
});

the tagfield definition:

    xtype: 'tagfield',
    fieldLabel: 'Roles',
    displayField: 'name',
    valueField: 'id',
    stacked: true,
    multiSelect: true,
    filterPickList: true,
    queryMode: 'local',
    publishes: 'value',
    bind: {
        store: '{roles}',
        value: '{userRoles}'
    }

and the ViewModel:

Ext.define('App.view.security.user.UsersModel', {
    extend: 'Ext.app.ViewModel',

    alias: 'viewmodel.users',

    stores: {
        users: {
            model: 'App.model.security.User',
            pageSize: 15,
            autoLoad: true,
            session: true
        },
        roles: {
            model: 'App.model.security.Role',
            autoLoad: true,
            session: true
        }
    },

    formulas: {
        userRoles: {
            bind: {
                bindTo: '{mainGrid.selection.roles.data.items}',
                deep: true
            },

            get: function(value){
                return value;
            },

            set: function(value){
            }
       }
    }
});

This is my very first project with Ext so maybe I'm missing some configuration at the model associations, I don't know. I've googled a lot but lack information about the linked tagfield. Any help will be gratefully appreciated.

1

1 Answers

0
votes

Well I ended up using the formula by completing the missing code of the setter like this:

           set: function(values){
                //Delete the roles that were not established
                var del = [], noadd = [];
                var roles = this.get('mainGrid').selection.roles();
                roles.each(function(record){
                    if (values.indexOf(record.get('id')) == -1) {
                        del.push(record);
                    }
                    else {
                        noadd.push(record.get('id'));
                    }
                });
                del.forEach(function(record){
                    roles.remove(record);
                });

                //Add the roles that didn't exist
                var store = this.getStore('roles');
                var allRecords = store.getData().getSource() || store.getData();
                allRecords.each(function(record){
                    if (values.indexOf(record.get('id')) != -1 && noadd.indexOf(record.get('id')) == -1) {
                        roles.add(record);
                    }
                });
            }

Those arrays that I'm using are there because:

(del) cannot loop and delete over the same collection that I'm looping

(noadd) if I try to add an existing record into the roles collection it won't be added twice but at save time the existing record strangely appears as a create, I think this is a BUG.

I'll leave this question open for some time so if you know a better way to solve this you can make your contribution.

Thanks!