ListView and parameters

Hello everyone.
I need to pass parameters from a menu item to a ListView without using URL query parameters.
I don’t want these parameters to be exposed in the URL, to prevent that a user can change them.
Looking at the help and the various examples I think the right solution is to use a menu beam.
But I encounter the following errors:


@Component("menuBean")
public class MenuBean {

    @Autowired
    private ViewNavigators viewNavigators;

    public void handleMenuItem(Map<String, Object> parameters) {
        viewNavigators.view(this, TestListView.class)
                .withAfterNavigationHandler(afterViewNavigationEvent -> {
                    TestListViewview = afterViewNavigationEvent.getView();
                    view.setMessage("Hello World!");
                })
                .navigate();
    }
}

The viewNavigators.view(this, TestListView.class) produce an error “Cannot resolve method”

Is it possible to have a complete and working example?
Thank you

Hi!

If your parameter is simple and static, then you can simply define a field for it and set the value via the menu.xml:

        <item bean="MenuBean" beanMethod="handleMenuItem" 
              title="msg://com.company.master.view.user/UserListView.title">
            <properties>
                <property name="message" value="Hello World!"/>
            </properties>
        </item>

In your case, the error occurs because theviewNavigators#view method takes two arguments as input:

  1. the view from which navigation occurs (this is required for backward navigation)
  2. the view class to navigate to

In your case, you are trying to pass the current bean instance as a view.
You can try the following code:

    private final ViewNavigators viewNavigators;

    public MenuBean(ViewNavigators viewNavigators) {
        this.viewNavigators = viewNavigators;
    }

    public void handleMenuItem(Map<String, Object> parameters) {
        viewNavigators.view(UiComponentUtils.getCurrentView(), UserListView.class)
                .withAfterNavigationHandler(afterViewNavigationEvent -> {
                    UserListView view = afterViewNavigationEvent.getView();
                    view.setMessage((String) parameters.get("message"));
                })
                .navigate();
    }

Best regards,
Dmitriy

Unfortunately there is another problem.
UiComponentUtils.getCurrentView() works only if there is a View open, otherwise it fails.
In case there are no Views open, what should I pass?

Since this bean is a menu item, it turns out that in order to execute it, you must at least open MainView and click on the menu item.

In what cases do you call a bean menu item without opening the menu?
If such a case exist, you can try ViewNavigationSupport#navigate(Class).

Regards,
Dmitriy

Sorry, I misunderstood the error. I thought that if there were no Views open, the UiComponentUtils.getCurrentView() statement would return nothing.

The problem is in the .withAfterNavigationHandler method.
If there is only the main view open, the method is not executed.

So in the code:

    public void handleMenuItem(Map<String, Object> parameters) {
        viewNavigators.view(UiComponentUtils.getCurrentView(), UserListView.class)
                .withAfterNavigationHandler(afterViewNavigationEvent -> {
                    UserListView view = afterViewNavigationEvent.getView();
                    view.setMessage((String) parameters.get("message"));
                })
                .navigate();
    }

The view.setMessage((String) parameters.get(“message”)); statement is never executed and the view is opened without passing parameters.

Instead, if there is a view open, everything works perfectly.

This is a bug.

I created an issue to fix it: withAfterNavigationHandler not called when navigating from MainView · Issue #3910 · jmix-framework/jmix · GitHub

For now, you can use the following workaround:

public class MenuBean {

    private final ViewNavigators viewNavigators;
    private final ViewNavigationSupport navigationSupport;

    public MenuBean(ViewNavigators viewNavigators, ViewNavigationSupport navigationSupport) {
        this.viewNavigators = viewNavigators;
        this.navigationSupport = navigationSupport;
    }

    public void handleMenuItem(Map<String, Object> parameters) {
        viewNavigators.view(UiComponentUtils.getCurrentView(), UserListView.class)
                .navigate();

        Consumer<AfterViewNavigationEvent<UserListView>> handler = event -> {
            UserListView view = event.getView();
            view.setMessage((String) parameters.get("message"));
        };

        navigationSupport.findCurrentNavigationTarget(UserListView.class)
                .ifPresent(view ->
                        ViewControllerUtils.setAfterNavigationHandler(
                                view,
                                () -> handler.accept(new AfterViewNavigationEvent<>(this, view))
                        )
                );
    }
}

A project with applied workaround:
master.zip (2.3 MB)

Regards,
Dmitriy