Completed
Last Updated: 13 Oct 2023 08:07 by ADMIN
Release 5.0.0 (15 Nov 2023) (R1 PI1)
Jeffrey
Created on: 08 Jan 2022 12:26
Category: ContextMenu
Type: Bug Report
3
Showing the context menu via its API method does not set its z-index

When the menu shows on its own (it has a Selector and you right click that element), it tracks the z-index of other Telerik popups and has an inline z-index rule. This does not happen when you show it via its API (.ShowAsync()).

 

-----

ADMIN EDIT

A workaround could be using a CSS CLass to set a higher z-index to it, but there is an issue with that where it does not render high enough in the DOM: https://feedback.telerik.com/blazor/1514877-css-class-does-not-render-on-the-topmost-element. You can Vote for that and Follow it as well, and it contains a CSS workaround you can consider for this issue too. Note that it will affect all animation containers on the page.

Basic reproducible - showing a context menu on a grid row in a Window - the context menu is not visible behind the window (you can only see it partially in the last 1-2 rows).

 

<TelerikWindow Visible="true">
    <WindowContent>
        Copy code@using System.Collections.Generic
        @using System.Collections.ObjectModel

        <TelerikContextMenu @ref="@ContextMenuRef" Data="@MenuItems"
                            OnClick="@((MenuItem item) => ContextMenuClickHandler(item))">
        </TelerikContextMenu>

        <TelerikGrid Data="@GridData" @ref="@GridRef"
                     EditMode="@GridEditMode.Inline"
                     Height="500px"
                     Pageable="false"
                     OnCreate="@CreateItem" OnUpdate="@UpdateHandler"
                     OnRowContextMenu="@OnContextMenu"
                     SelectionMode="@GridSelectionMode.Multiple"
                     @bind-SelectedItems="@SelectedItems">
            <GridToolBar>
                <GridCommandButton Command="Add" Icon="add">Add Employee</GridCommandButton>
            </GridToolBar>
            <GridColumns>
                <GridColumn Field=@nameof(SampleData.ID) Editable="false" />
                <GridColumn Field=@nameof(SampleData.Name) />
                <GridCommandColumn>
                    <GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton>
                    <GridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</GridCommandButton>
                </GridCommandColumn>
            </GridColumns>
        </TelerikGrid>

        @if (SelectedItems.Any())
        {
            <ul>
                @foreach (var item in SelectedItems)
                {
                    <li>@item.Name</li>
                }
            </ul>
        }

        @code {
            //data sources
            ObservableCollection<SampleData> GridData { get; set; }
            List<MenuItem> MenuItems { get; set; }
            IEnumerable<SampleData> SelectedItems { get; set; } = Enumerable.Empty<SampleData>();
            //metadata for the context menu actions
            SampleData SelectedPerson { get; set; }
            //component references so we can use their methods
            TelerikContextMenu<MenuItem> ContextMenuRef { get; set; }
            TelerikGrid<SampleData> GridRef { get; set; }

            // sample menu item class
            public class MenuItem
            {
                public string Text { get; set; }
                public string Icon { get; set; }
                public Action Action { get; set; }
                public string CommandName { get; set; }
            }

            // show the context menu for a particular row
            async Task OnContextMenu(GridRowClickEventArgs args)
            {
                var argsItem = args.Item as SampleData;

                SelectedPerson = argsItem;

                if (args.EventArgs is MouseEventArgs mouseEventArgs)
                {
                    await ContextMenuRef.ShowAsync(mouseEventArgs.ClientX, mouseEventArgs.ClientY);
                }
            }

            // sample handling of the context menu click
            async Task ContextMenuClickHandler(MenuItem item)
            {
                // one way to pass handlers is to use an Action, you don't have to use this
                if (item.Action != null)
                {
                    item.Action.Invoke();
                }
                else
                {
                    // or you can use local code to perform a task
                    // such as put a row in edit mode or select it
                    switch (item.CommandName)
                    {
                        case "BeginEdit": // read more at https://localhost/blazor-ui/components/grid/state#initiate-editing-or-inserting-of-an-item
                            var currState = GridRef.GetState();
                            currState.InsertedItem = null;
                            SampleData itemToEdit = SampleData.GetClonedInstance(GridData.Where(itm => itm.ID == SelectedPerson.ID).FirstOrDefault());
                            currState.OriginalEditItem = itemToEdit;
                            await GridRef.SetState(currState);
                            break;
                        case "ToggleSelect":
                            var selItems = SelectedItems.ToList();
                            if (SelectedItems.Contains(SelectedPerson))
                            {
                                selItems.Remove(SelectedPerson);
                            }
                            else
                            {
                                selItems.Add(SelectedPerson);
                            }
                            SelectedItems = selItems;
                            break;
                        default:
                            break;
                    }
                }
                SelectedPerson = null; // clean up
            }

            // generate data
            protected override void OnInitialized()
            {
                // context menu items
                MenuItems = new List<MenuItem>()
        {
            new MenuItem(){ Text = "Select", Icon="checkbox-checked", CommandName="ToggleSelect" },
            new MenuItem(){ Text = "Edit", Icon="edit", CommandName="BeginEdit" },
            new MenuItem(){ Text = "Delete", Icon="delete", Action = DeleteItem }
        };

                // generate data for the grid
                GridData = new ObservableCollection<SampleData>();
                var rand = new Random();

                for (int i = 0; i < 100; i++)
                {
                    GridData.Add(new SampleData()
                    {
                        ID = i,
                        Name = "Employee " + i.ToString(),
                    });
                }
            }


            // CUD operations for the grid

            async Task CreateItem(GridCommandEventArgs args)
            {
                var argsItem = args.Item as SampleData;

                // call the actual data service here

                argsItem.ID = GridData.Count + 1;

                GridData.Insert(0, argsItem);
            }

            void DeleteItem() // not async so it can be passed as an Action
            {
                var argsItem = SelectedPerson;

                // call the actual data service here

                GridData.Remove(argsItem);
            }

            async Task UpdateHandler(GridCommandEventArgs args)
            {
                var argsItem = args.Item as SampleData;

                // call the actual data service here

                var index = GridData.ToList().FindIndex(i => i.ID == argsItem.ID);
                if (index != -1)
                {
                    GridData[index] = argsItem;
                }
            }

            public class SampleData
            {
                public int ID { get; set; }
                public string Name { get; set; }


                public override bool Equals(object obj)
                {
                    if (obj is SampleData)
                    {
                        return this.ID == (obj as SampleData).ID;
                    }
                    return false;
                }

                public SampleData()
                {

                }

                public SampleData(SampleData itmToClone)
                {
                    this.ID = itmToClone.ID;
                    this.Name = itmToClone.Name;
                }

                public static SampleData GetClonedInstance(SampleData itmToClone)
                {
                    return new SampleData(itmToClone);
                }
            }
        }
    </WindowContent>
</TelerikWindow>

 

0 comments