At the moment, when you click a menu item it does not hide.
A method can be exposed to hide the expanded items that can be invoked from the OnClick handler.
---
ADMIN EDIT
Here is a potential workaround - when the menu item is clicked, we use a little bit of JS to go over the menu items at the root and make the browser think that the user moved the mouse away from them which is the signal for the menu dropdowns to hide. Do test this carefully before using in production, though.
@inject IJSRuntime _js
@* Move this script together with other scripts in the project, it is here to make the snippet shorter *@
<script suppress-error="BL9992">
function closeMenu() {
setTimeout(function () {
var mouseLeaveEvent = new Event('mouseleave');
var rootNodes = document.querySelectorAll("li.k-menu-item");
rootNodes.forEach(function (elem) { elem.dispatchEvent(mouseLeaveEvent); })
}, 30);
}
</script>
<TelerikMenu Data="@MenuItems"
ItemsField="@nameof(MenuItem.SubSectionList)"
TextField="@nameof(MenuItem.Section)"
UrlField="@nameof(MenuItem.Page)"
OnClick="@((MenuItem item) => OnClickHandler(item))">
</TelerikMenu>
@code {
public List<MenuItem> MenuItems { get; set; }
async Task OnClickHandler(MenuItem item)
{
await _js.InvokeVoidAsync("closeMenu");
}
public class MenuItem
{
public string Section { get; set; }
public string Page { get; set; }
public List<MenuItem> SubSectionList { get; set; }
}
protected override void OnInitialized()
{
MenuItems = new List<MenuItem>()
{
new MenuItem()
{
Section = "fetchdata",
Page = "fetchdata"
},
new MenuItem()
{
Section = "counter",
Page = "counter"
},
// sample URLs for SPA navigation
new MenuItem()
{
Section = "Company",
SubSectionList = new List<MenuItem>()
{
new MenuItem()
{
Section = "Overview",
Page = "fetchdata"
},
new MenuItem()
{
Section = "Events",
Page = "fetchdata"
},
new MenuItem()
{
Section = "Careers",
Page = "counter"
}
}
},
// sample URLs for external navigation
new MenuItem()
{
Section = "Services",
SubSectionList = new List<MenuItem>()
{
new MenuItem()
{
Section = "Consulting",
Page = "counter"
},
new MenuItem()
{
Section = "Education",
Page = "fetchdata"
}
}
},
new MenuItem()
{
Section = "Contact",
Page = "counter"
}
};
base.OnInitialized();
}
}
---
Dear,
the blazor menu UI adapt it self for hamburguer menu when mobile?
best,
Jeff
---
ADMIN EDIT
I have attached to this post a sample implementation that you can use as base. Another option is to add more conditional markup to remove the menu altogether and replace it with another structure for small screens. A third option is to use the Drawer component as it collapses anyway (see here and here).
----
Implementation of one or both of these features:
- Screen boundary detection: The list of child items expands to the opposite direction when necessary to prevent screen boundaries from being crossed.
- ExpandDirection: Gets or sets the direction in which child items will open.
Use any demo and rapidly hover between parent menu items:
Currently, on mobile devices (where is no hover), to open the child menu you need to click/tap the parent and the only way close it afterwards is if you click away. This is not very convenient for mobile usage. I want to be able to close the child menu on click/tap of the parent as well.
Is there a way to not create menu programmatically but only using "html" elements ? Something like this :
<TelerikMenu>
<TelerikMenuItem Text="File">
<TelerikMenuItem Text="Open" OnClick="@OnFileOpenMenuClick"/>
<TelerikMenuItem Text="Save" OnClick="@OnFileSaveMenuClick"/>
</TelerikMenuItem>
</TelerikMenu>
I'm using the Menu component and I am handling the OnClick event. I noticed that when an exception is thrown in its handler, it does not reach the ErrorBoundary.
===
ADMIN EDIT
===
This issue also affects the SplitButton component.
The Menu uses the NavigationManager to go to the pages that are assigned to the individual MenuItem objects. Is there a way to pass the "force load" value to these menu items?
-------------------- ADMIN EDIT --------------------
You can work around the issue if you skip setting Url field of the items that you want to force load and set your own property. Then, handle OnClick of the menu items and check if this property is set and manually call the navigation manager for the URL. You can see the code for this approach below:
public List<MenuItem> MenuItems { get; set; }
protected void OnClickHandler(MenuItem item)
{
if (item.ForceLoadUrl != null)
{
navManager.NavigateTo(item.ForceLoadUrl, true);
}
}
public class MenuItem
{
public string Text { get; set; }
public string Url { get; set; }
public string ForceLoadUrl { get; set; }
public List<MenuItem> Items { get; set; }
}
protected override void OnInitialized()
{
MenuItems = new List<MenuItem>()
{
new MenuItem()
{
Text = "site.css",
ForceLoadUrl = "/css/site.css"
},
new MenuItem()
{
Text = "Counter",
Url = "/counter"
},
new MenuItem()
{
Text = "Fetch Data",
Url = "/fetchdata"
}
};
base.OnInitialized();
}
I need to style the entire menu item, not just my template, but there are classes from the menu that I cannot override with my code or template.
The current implementation of the component has hardcoded values for the alignment of the popup - e.g.:
for horizontal orientation: left horizontal align and bottom vertical align
for vertical orientation: right horizontal align and top vertical align
Ideally, those should be customizable to facilitate various use-cases.
While the menu is usable the way it is, it could be better. If you take a look at the example menu in the best practices link that I provided in the original post, you will see what I mean. Some of the differences include the following:
Best practices example: https://www.w3.org/TR/wai-aria-practices-1.1/examples/menubar/menubar-1/menubar-1.html
Hello,
If I disable a Menu item at runtime, it prohibits access to child items via the mouse, but still opens the child group of items if I use the keyboard navigation.
Here is a test page with a workaround included (which is to recreate the Menu).
<TelerikButton OnClick="@DisableItem">Disable Services item</TelerikButton>
<TelerikButton OnClick="@EnableItem">Enable Services item</TelerikButton>
@if (ShowMenu)
{
<TelerikMenu Data="@MenuItems" />
}
@code {
List<MenuItem> MenuItems { get; set; }
bool ShowMenu { get; set; } = true;
async Task DisableItem()
{
MenuItems.Find(x => x.Text == "Services").Disabled = true;
MenuItems = new List<MenuItem>(MenuItems);
// workaround start
ShowMenu = false;
await Task.Delay(1);
ShowMenu = true;
// workaround end
}
async Task EnableItem()
{
MenuItems.Find(x => x.Text == "Services").Disabled = false;
MenuItems = new List<MenuItem>(MenuItems);
}
protected override void OnInitialized()
{
MenuItems = new List<MenuItem>()
{
new MenuItem()
{
Text = "Company",
Items = new List<MenuItem>()
{
new MenuItem()
{
Text = "Overview"
},
new MenuItem()
{
Text = "Events"
}
}
},
new MenuItem()
{
Text = "Services",
Items = new List<MenuItem>()
{
new MenuItem()
{
Text = "Consulting"
},
new MenuItem()
{
Text = "Education"
}
}
}
};
base.OnInitialized();
}
public class MenuItem
{
public string Text { get; set; }
public bool Disabled { get; set; }
public List<MenuItem> Items { get; set; }
}
}