Lazy Tabs and Frames

I’m having a bit of an issue with loading Frames within a Lazy Tab

What I have is a Tab Sheet with a number of Lazy Tabs. In the Lazy Tabs I have a Frame in which I want to show a Combined Screen.

It works fine if I setup the Frame and Screen in Studio but then I can’t send parameters to the Screen.

If I try to inject the Frame to the code I can’t as it is in a Lazy Tab.

I tried an empty tab and used Code to create a Frame and call OpenFrame with the required parameters which works but then the CUBA doesn’t apply the UserSetting for the window to the loaded Frame such as the Default Presentation applied to the table in the frame.

It seem there is no combination I can get to work.

Is there a way of having a frame defined in the XML and hook in to it before it loads the attached screen to set parameters?

It would appear to me that using OpenFrame to load a Screen in to a tab, which you need to do to pass parameters will not apply User Settings such as default presentations.

Using the following code, taken from within CUBA, will apply the settings to a Screen loaded via OpenFrame.

If any CUBA developers can comment that would be great.

    BoxLayout tabContent = (BoxLayout)tabSheet.getTabComponent(tabSheet.getSelectedTab().getName());
    Window window = ComponentsHelper.getWindow(this);
    if (window != null) {
        walkComponents(tabContent, (settingsComponent, name) -> {
            if (settingsComponent.getId() != null
                    && settingsComponent instanceof HasSettings) {
                Settings settings = window.getSettings();
                if (settings != null) {
                    Element e = settings.get(name);
                    ((HasSettings) settingsComponent).applySettings(e);

                    if (tabContent instanceof Component.HasPresentations
                            && e.attributeValue("presentation") != null) {
                        final String def = e.attributeValue("presentation");
                        if (!StringUtils.isEmpty(def)) {
                            UUID defaultId = UUID.fromString(def);
                            ((Component.HasPresentations) tabContent).applyPresentationAsDefault(defaultId);
                        }
                    }
                }
            }
        });
    }

Hello, @JohnM

Could you clarify the following:

  1. What parameters you want to pass to a screen? And how are you trying to do it?
  2. Do you mean that UserSettings are not propagated into a frame that is opened in lazy tab dynamically?

It will be great if you share a sample with you case.

Regards,
Daniil.

Hi Daniil (@tsarev)

To answer your questions.

  1. I’m just trying to pass in and entity instance to the frame. This is working fine in the codeI use in my project. I am using the params.ITEM.set which is all good.

  2. That is exactly what I am saying. The settings seem to save fine from what I can tell but aren’t applied as the frame is added dynamically. As far as I can tell adding parameters to a frame can’t be done other than creating the frame in code and adding it to the tab. I can’t inject anything either as the tab is lazy loaded.

In the attached example you will see two screens in the menu "error"and “working

In both of them try to apply a default presentation and reopen the screen. The error screen will not apply the default presentation but the working screen will.The additional code in the working screen seems to do the trick of apply the default presentation and was taken from inside the CUBA code. I don’t think it is 100% because in my actual project it isn’t totally working for some reason which I haven’t figured out yet.

CubaLazyTabIssue.zip (88.3 KB)

Does this make any more sense now?

@tsarev

Did you by any chance get to see the issue i was talking about in the example project I attached above?

Would it be logical that the user’s screen settings are applied to a frame attached dynamically if they are saved?

Hello @JohnM

Yes, I checked your sample and here is a solution.

So, first of all i’ve declared the TestEntity browse screen as a content for the presentationTab:

<tab id="presentationTab"
     caption="Test Presentations"
     lazy="true"
     margin="true,false,false,false"
     spacing="true">
    <frame id="lazyFrame"
           screen="cubalazytabissue$TestEntity.browse"/>
</tab>

Then due to absence of generic mechanism for passing params to frames in lazy tabs I’ve added public method for TestEntityBrowse and pass params from the owning controller:

public class TestEntityBrowse extends AbstractLookup {

    public void setParams(Map<String, Object> params) {
    }
}

// Owning controller
@Override
public void init(Map<String, Object> params) {
    tabSheet.addSelectedTabChangeListener(event -> {
        if ("presentationTab".equals(event.getSelectedTab().getName())) {
            TestEntityBrowse entityBrowse = (TestEntityBrowse) getComponent("lazyFrame");
            if (entityBrowse != null) {
                entityBrowse.setParams(ParamsMap.of("testParam", 42));
            }
        }
    });
}

And then I’ve added a label with a value of param to the frame to check whether param is passed correctly:

@Inject
private ComponentsFactory componentsFactory;

public void setParams(Map<String, Object> params) {
    Label label = componentsFactory.createComponent(Label.class);
    label.setValue("Passed param: " + params.get("testParam"));
    add(label, 0);
}

In this case new order of table columns in TestEntity browser is saved and successfully applied later.

Please check updated sample:
CubaLazyTabIssue.zip (77.9 KB)

Regards,
Daniil.

Hi @tsarev

Thanks for having a look. I did try this but the issue I had was two things.

One in the frame screen the passing of the parameters happens after the init so my code setting the datasources didn’t happen during the init which I think caused more DB hits than necessary.

Two I was setting variables with @WindowParam which doesn’t work using the method shown.

I was continually getting the Chicken / Egg problems which is why I ended up down the path of reusing that code to apply user settings.