CUBA 7 legacy editor screen context help

Hello,

In my extended User editor, I have a button click method that needs to remove a design-time role and add a different design-time role, but I can’t get the screen to reflect the new role. It adds a blank line to the User Roles collection table.

    @Subscribe("approveRequestedRoleBtn")
    public void onApproveRequestedRoleBtnClick(Button.ClickEvent event) {
        //Remove all existing from collection
        List<UserRole> currentUserRoles = new ArrayList<>();
        currentUserRoles.addAll(getEditedEntity().getUserRoles());
        getEditedEntity().getUserRoles().removeAll(currentUserRoles);
        for (UserRole currentUserRole : currentUserRoles) {
            rolesDs.removeItem(currentUserRole);
        }
        //Add requested role to collection
        UserRole requestedUserRole = metadata.create(UserRole.class);
        requestedUserRole.setUser(getEditedEntity());
        requestedUserRole.setRoleName(((ExtUser) getEditedEntity()).getRequestedRole().getId());

        // ??????????
        rolesDs.addItem(requestedUserRole);
        getEditedEntity().getUserRoles().add(requestedUserRole);
        // UserRole is added to the table at this point, but the line is blank
        rolesDs.refresh();
        dsContext.refresh();
    }

I asked about this in a different post, but I’m not sure the answer was directed at this specific problem because I added it as another question.

I can’t find how to get the table to reflect the changes. I’ve checked the documentation and searched the forum, but maybe I didn’t understand a solution for this issue.

Thank you,
Adam

Will a test project help with a solution?

collectionchange.zip (92.3 KB)

  • Run application
  • Create dummy user
  • Set Requested role to some value
  • Remove any default roles
  • Add Registered role
  • Save changes
  • Edit new user (current state now represents new user having come from registration process)
  • Click Approve Requested Role button

This is where I need guidance.

Thank you,
Adam

Hi,
Check how com.haulmont.cuba.gui.app.security.user.edit.UserEditor.AddRoleAction#actionPerform is implemented.

You ned to also call userRole.setRole(role);

These calls are useless, remove them:

        rolesDs.refresh();
        dsContext.refresh();

These two lines repeat the same action:

        rolesDs.addItem(requestedUserRole);
        getEditedEntity().getUserRoles().add(requestedUserRole);

When you are adding a new item to the rolesDs - it automatically adds the item to the underlying collection.

As a general, when you extend platform functionality, it is a good idea to study its code. In this case - code of the com.haulmont.cuba.gui.app.security.user.edit.UserEditor.

Hi Alexander,

Thank you for addressing this question.

So, like I said above, these are design-time roles. Since there’s no Role in the database, I didn’t set this, and set the roleName attribute of the UserRole object instead. If this is incorrect, please let me know (though I don’t know how it could be, because the database shows nothing in the role_id column of the sec_user_role table for design-time roles).

Yes, I was just showing what I’ve tried in order to get the rolesTable to reflect the changes. I apologize for the confusion.

Also, yes, I was just showing what I’ve tried in order to get the rolesTable to reflect the changes. I should have removed this line before posting. I have removed the getEditedEntity().getUserRoles().add(requestedUserRole); line.

It doesn’t appear that the actionPerform method is doing anything to the rolesTable object other than setting the focus and setting multi-select to true. I see nothing in the actionPerform method to show how to interact with the context of the data. So again, that’s the question that I’ve been trying to pry an answer for; how can I get the rolesTables to reflect the changes of adding the role programmatically? This is all I need regarding this issue.

The current state of my method is as follows:

    @Subscribe("approveRequestedRoleBtn")
    public void onApproveRequestedRoleBtnClick(Button.ClickEvent event) {
        rolesDs.suspendListeners();

        //Remove all existing from collection
        List<UserRole> currentUserRoles = new ArrayList<>();
        currentUserRoles.addAll(getEditedEntity().getUserRoles());
        for (UserRole currentUserRole : currentUserRoles) {
            rolesDs.removeItem(currentUserRole);
        }
        //Add requested role to collection
        UserRole requestedUserRole = metadata.create(UserRole.class);
        requestedUserRole.setUser(userDs.getItem());
        requestedUserRole.setRoleName(((ExtUser) getEditedEntity()).getRequestedRole().getId());

        try {
            rolesDs.addItem(requestedUserRole);
        } finally {
            rolesDs.resumeListeners();
        }
    }

The UserRole object is adding correctly (saving and reloading the editor screen reflects this), but it doesn’t show in the rolesTable prior to saving. It only shows a blank line:

And again, I’m sorry if I’m overlooking something.

I really appreciate the help,
Adam

It feels weird for me that I have to convince you…

  1. If you invoke “Find Usages” action for the UserRole#setRoleName method
    Then you will see the logic in the UserEditor#preCommit method that performs all necessary work:

  2. If you view the source code of the user-edit.xml XML descriptor - you will see why the table row was blank in your case:

<groupTable id="rolesTable" editable="false" multiselect="true" width="100%" fixedGrouping="true">
                    ...
                    <columns>
                        <column id="role.name" caption="msg://roleName"/>
                        <column id="role.locName" caption="msg://localizedRoleName"/>
                        <column id="role.locSecurityScope"/>
                    </columns>
                    <rows datasource="rolesDs"/>
                </groupTable>

It’s because it displays sub-properties of the “UserRole#role” attribute.

That’s why one should study the code of the screen before extending one…

The action does this call:

rolesDs.addItem(userRole);

This immediately leads to the table bound to this datasource to be repainted with new data. That’s how data binding works.
See here: Datasources (Legacy) - CUBA Platform. Developer’s Manual

Datasources provide data to data-aware components.

  • When a user changes a value in the component, the new value is set for the entity attribute in the datasource.
  • When the entity attribute is modified in the code, the new value is set and displayed in the visual component.
  • User input can be monitored both by datasource listeners and value listeners on the component – they are notified sequentially.
  • To read or write the value of an attribute in the application code, it is recommended to use the datasource, rather than the component. Below is an example of reading the attribute:

Hello Alexander,

I really appreciate the help (if not the rude reply)! Thank you for helping me understand how roles are set, despite the difference between design-time and runtime role definitions. I will remember this for the future.

Thanks again,
Adam