Hi,
The approach depends a bit on how your sub menu and items are going to be defined,
- Static menus
if these are known to you then you can extend the menu-item , and render the items in your tree there, e.g this is what uSync is doing for it’s extensions :
uSync is a menu item defined in a manifest of uSyncMenu
item. which then has it’s own special ‘render children’ method which in this case it renders usync-menuItem
elements
render() {
return html`<umb-menu-item-layout
label=${this.manifest.meta.label ?? this.manifest.name}
icon-name=${this.manifest.meta.icon ?? 'icon-bug'}
.href=${this.itemPath}
?has-Children=${this.hasChildren}
>${this.renderChildren()}
</umb-menu-item-layout>`;
}
renderChildren() {
return html`<umb-extension-slot
type="usync-menuItem"
default-element="umb-menu-item-default"></umb-extension-slot>`;
}
This means the items are in code, but they are not coming from the database, rather other extensions. this is part of the power of the menu, it can ifact be anything you want it to be.
- Dynamic menu items
(n.b this is way more involved!)
if your menu is coming from the DB then you will probably need to implement a tree
this is what uSync.Complete does for servers :
here the servers come from the database, and we have had to impliement a tree in the manifest, with a treeItem and a menu item…
const tree: UmbExtensionManifest = {
type: 'tree',
kind: 'default',
alias: 'usync.publisher.server.tree',
name: 'Publisher tree',
meta: {
repositoryAlias: repository.alias,
},
};
const treeItem: UmbExtensionManifest = {
type: 'treeItem',
kind: 'default',
alias: 'sync.publisher.server.tree.rootitem',
name: 'Publisher server tree root item',
forEntityTypes: [SYNC_PUBLISHER_SERVER_ITEM_TYPE, SYNC_PUBLISHER_SERVER_ROOT_ITEM_TYPE],
};
const menuItem: UmbExtensionManifest = {
type: 'menuItem',
kind: 'tree',
alias: 'usync.publisher.server.tree.menuitem',
name: 'Publisher server menu item',
weight: -1,
meta: {
label: 'usyncpublish_publisher',
icon: 'icon-clock-alt',
entityType: SYNC_PUBLISHER_SERVER_ITEM_TYPE,
menus: ['usync.menu'],
treeAlias: tree.alias,
},
};
then there is even more to this, because you have to impliment a treeStore to get the items, and other bits. some of this is in the docs : Trees | Umbraco CMS
but not all of it because you also need to impliment the controllers in the same way as the core, without going to deep into it - it can start to look a bit like this :
[HttpGet("ServerRoot")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<SyncServerItemResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<SyncServerItemResponseModel>>> Root(CancellationToken cancellationToken, int skip = 0, int take = 100, bool foldersOnly = false)
{
IEnumerable<SyncServerItemResponseModel> items = await GetServers();
PagedViewModel<SyncServerItemResponseModel> result = PagedViewModel(items, items.Count());
return Ok(result);
}
there is loads to this, and its quite hard to go through it all in a single post to be honest. the documention does give you a start - but depending on how complex it can become a little bit more digging through source code to get the tree working this way. (in my experience anyway)