Multiple menu in multiple main views

Hi all,

is it possibile to add multiple main views (under different routes) containing its own menu?
The base idea is to split big menus for a single application. For now i was able to create multiple main views, but reusing the same main menu

I’m going to try to reformulate the question: is it possible to use listmenu component referencing to a particolar subset of main menu, for example a menu including only some specific items from main menu

Thanks for helping!

Hi Michele,

Yes it’s possible.

First, turn off the default loading of listMenu:

<listMenu id="menu" loadMenuConfig="false"/>

Then create your own MenuItemProvider and use it in listMenu component:

package com.company.demo.view.main;

import com.vaadin.flow.router.Route;
import io.jmix.flowui.app.main.StandardMainView;
import io.jmix.flowui.component.main.JmixListMenu;
import io.jmix.flowui.kit.component.main.ListMenu;
import io.jmix.flowui.menu.ListMenuBuilder;
import io.jmix.flowui.menu.MenuConfig;
import io.jmix.flowui.menu.MenuItem;
import io.jmix.flowui.menu.provider.MenuConfigMenuItemProvider;
import io.jmix.flowui.view.Subscribe;
import io.jmix.flowui.view.ViewComponent;
import io.jmix.flowui.view.ViewController;
import io.jmix.flowui.view.ViewDescriptor;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Route("")
@ViewController("MainView")
@ViewDescriptor("main-view.xml")
public class MainView extends StandardMainView {
    @ViewComponent
    private JmixListMenu menu;
    @Autowired
    private MenuConfig menuConfig;
    @Autowired
    private ListMenuBuilder listMenuBuilder;

    @Subscribe
    public void onInit(final InitEvent event) {
        // Create custom MenuItemProvider and set it to ListMenu component
        SampleMenuItemProvider menuItemProvider = new SampleMenuItemProvider(menuConfig, listMenuBuilder);
        menu.setMenuItemProvider(menuItemProvider);
        // Load ListMenu from the MenuItemProvider
        menuItemProvider.load();
    }

    private static class SampleMenuItemProvider extends MenuConfigMenuItemProvider<ListMenu.MenuItem> {

        protected ListMenuBuilder listMenuBuilder;

        public SampleMenuItemProvider(MenuConfig menuConfig, ListMenuBuilder listMenuBuilder) {
            super(menuConfig);
            this.listMenuBuilder = listMenuBuilder;
        }

        @Override
        protected List<ListMenu.MenuItem> convertToMenuItems(Collection<MenuItem> menuConfigItems) {
            // Create a desired copy of the menu structure
            Collection<MenuItem> sampleMenuItems = new ArrayList<>();
            createSampleMenuItems(menuConfigItems, sampleMenuItems);
            // Convert the created menu structure to ListMenu items structure
            return sampleMenuItems.stream()
                    .flatMap(menuItem -> listMenuBuilder.createListMenu(menuItem).stream())
                    .collect(Collectors.toCollection(ArrayList::new));
        }

        private void createSampleMenuItems(Collection<MenuItem> srcItems, Collection<MenuItem> dstItems) {
            for (MenuItem srcItem : srcItems) {
                if (satisfiesSampleCondition(srcItem)) {
                    MenuItem dstItem = new MenuItem(srcItem.getId());
                    dstItems.add(dstItem);
                    dstItem.setMenu(srcItem.isMenu());
                    dstItem.setView(srcItem.getView());
                    dstItem.setTitle(srcItem.getTitle());
                    // copy all MenuItem properties here
                    // ...
                    if (!srcItem.getChildren().isEmpty()) {
                        createSampleMenuItems(srcItem.getChildren(), dstItem.getChildren());
                    }
                }
            }
        }

        private boolean satisfiesSampleCondition(MenuItem srcItem) {
            return srcItem.isMenu() || srcItem.getView().startsWith("User");
        }
    }

}

Regards,
Konstantin

Thanks!

Ok, good, but if i’d want to write my custom xml menu config and rely on this building a custon MenuConfig bean?

Consider turning off the default loading of listMenu and just building it using the JmixListMenu.addMenuItem() methods.

I think my last question is not clear…

Actually, if i understood how the mechanism works, listMenu rely on menu.xml by default; but i’d want to know if is it posssible creating a custom-menu.xml and passing it, in some way, to a listMenu instance programmatically or through xml definition in main view

Thank’s again!

In my example above, I implemented SampleMenuItemProvider by extending MenuConfigMenuItemProvider class which loads items from the standard menu.xml.

You could create a menu item provider by implementing the MenuItemProvider interface from scratch and load items from a different source.