My iOS Device Does Not Display the Context Menu
- 3 minutes to read
The Context Menu component is displayed every time the contextmenu event occurs. However, this event never occurs on iOS devices.
Implement JavaScript functions to handle touch events in your application to display the context menu on iOS devices. To do this, follow the steps below:
Add the
DxContextMenu
component to a.razor
file:<DxContextMenu @ref="@ContextMenu" ItemClick="@OnItemClick"> <Items> <DxContextMenuItem Text="Sort By"> <Items> <DxContextMenuItem Text="Name"></DxContextMenuItem> <DxContextMenuItem Text="Size"></DxContextMenuItem> <DxContextMenuItem Text="Type"></DxContextMenuItem> </Items> </DxContextMenuItem> <DxContextMenuItem Text="Copy" BeginGroup="true"></DxContextMenuItem> <DxContextMenuItem Text="Cut"></DxContextMenuItem> <DxContextMenuItem Text="Remove"></DxContextMenuItem> <DxContextMenuItem Text="Select All" BeginGroup="true"></DxContextMenuItem> </Items> </DxContextMenu> @code { DxContextMenu ContextMenu { get; set; } string ClickedItem { get; set; } void OnItemClick(ContextMenuItemClickEventArgs args) { ClickedItem = args.ItemInfo.Text; InvokeAsync(StateHasChanged); } }
Add a container to display the Context Menu as follows:
<div class="card-header"> <b>Clicked item: @(ClickedItem != null ? ClickedItem : "None")</b> </div> <div class="card-body" style="padding: 0"> <div class="span-container" @oncontextmenu:preventDefault @ref="ContextMenuTarget"> <span style="text-align: center; font-weight: 600"> RIGHT-CLICK OR TOUCH AND HOLD TO SHOW THE CONTEXT MENU </span> </div> <DxContextMenu @ref="@ContextMenu" ItemClick="@OnItemClick"> @* ... *@ </DxContextMenu> </div>
The contextmenu event fires in PC web browsers and on Android devices. To keep your code consistent across all platforms, assign an empty handler to the oncontextmenu event to disable the browser’s default context menu. The
<div>
container should also have an element reference (@ref="ContextMenuTarget"
) to attach a touch or mouse event listener.Create a folder to store JavaScript source code. To do this, right-click the wwwroot folder in the Visual Studio Solution Explorer, select Add → New Folder, and specify a name for the folder (for example, js).
- Right-click the js folder and select Add → New Item. Choose the JavaScript file template and give it a name (for example, contextmenu.js).
Copy the following code to the JavaScript file:
function isTouchDevice() { return ("ontouchstart" in window) && ("ontouchend" in window); } function ShowMenu(x, y, dotNetHelper) { dotNetHelper.invokeMethodAsync("ShowMenu", x, y); } window.AttachContextMenuCrossPlatform = (targetElement, dotNetHelper) => { if (!isTouchDevice()) { targetElement.addEventListener("contextmenu", (evt) => { evt.preventDefault(); ShowMenu(evt.clientX, evt.clientY, dotNetHelper); }); } else { let timer; targetElement.addEventListener("touchstart", (evt) => { evt.preventDefault(); // Here you can change "touch and hold" time timer = setTimeout(() => { ShowMenu(evt.changedTouches[0].clientX, evt.changedTouches[0].clientY, dotNetHelper); }, 500); }); targetElement.addEventListener("touchend", (evt) => { evt.preventDefault(); if (timer) { clearTimeout(timer); timer = null; } }); } };
The snippet above attaches a touch event listener to the container that shows the Context Menu if the device is touch-enabled. Otherwise, the container listens to mouse events.
Embed the contextmenu.js script into the _Layout.cshtml file:
<script src="js/contextmenu.js"></script>
Add the following code to the
.razor
file to call JavaScript methods that add event listeners:@code { // ... [Inject] IJSRuntime JsRuntime { get; set; } ElementReference ContextMenuTarget; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) await JsRuntime.InvokeVoidAsync("AttachContextMenuCrossPlatform", ContextMenuTarget, DotNetObjectReference.Create(this)); } [JSInvokable] public async Task ShowMenu(double x, double y) { await ContextMenu.ShowAsync(x, y); } }
Use a long tap to display the Context Menu.