|
| 1 | +--- |
| 2 | +title: Integration |
| 3 | +page_title: Context Menu - Integration |
| 4 | +description: Integrating the context menu with other code and customizing it according to the target and its metadata. |
| 5 | +slug: contextmenu-integration |
| 6 | +tags: telerik,blazor,menu,integration |
| 7 | +published: True |
| 8 | +position: 3 |
| 9 | +--- |
| 10 | + |
| 11 | +# Context Menu Integration |
| 12 | + |
| 13 | +In some cases, you may need to know which element the user clicked so you can use it in the command handling. You may also want to adjust the menu contents based on which element the user clicked (e.g., disable or entirely remove some items from the menu based on a condition). |
| 14 | + |
| 15 | +Using the `Selector` parameter to attach the context menu to one or more targets at a time is simple, and can be useful when you want the same menu for many elements, but it does not matter which one the user clicked. So, the Telerik Context Menu offers the `ShowAsync(x, y)` method that lets you show it on demand after executing business logic. |
| 16 | + |
| 17 | +To achieve such flexibility and granularity, you can: |
| 18 | + |
| 19 | +1. Use your own code to hook to an event such as `@oncontextmenu` to store the desired target and its metadata. |
| 20 | + * You can use other events to show the context menu, like click, mousedown and so on. Make sure to pass correct coordinates to the menu - they must be relative to the viewport. |
| 21 | + * If you use the `@oncontextmenu` event, also add `@oncontextmenu:preventDefault="true"` to avoid the browser context menu which will always show above HTML structures on the page, like the Telerik Context Menu. |
| 22 | +1. Optionally, alter the [data source]({%slug contextmenu-data-binding-overview%}) or [templates]({%slug contextmenu-templates-overview%}) of the menu based on the metadata for the target. |
| 23 | +1. Show the Telerik menu through its `@ref` and the `ShowAsync` method it exposes. |
| 24 | + |
| 25 | +This article provides the following two examples: |
| 26 | + |
| 27 | + |
| 28 | +* [Know The Target And Adjust Items](#know-the-target-and-adjust-items) |
| 29 | +* [Context Menu for a Grid Row](#context-menu-for-a-grid-row) |
| 30 | + |
| 31 | +## Know The Target And Adjust Items |
| 32 | + |
| 33 | +Hooking to your own HTML elements' events lets you determine what to do with the context menu before showing it (for example, altering its data source). |
| 34 | + |
| 35 | +>caption Use the context menu target and change menu items based on the target data |
| 36 | +
|
| 37 | +````CSHTML |
| 38 | +@* Get context menu target and alter its items based on it *@ |
| 39 | +
|
| 40 | +<TelerikContextMenu Data="@MenuItems" @ref="@TheContextMenu" |
| 41 | + TextField="Text" SeparatorField="Separator" IconField="Icon" DisabledField="Disabled" |
| 42 | + OnClick="@( (ContextMenuItem itm) => ClickHandler(itm) )"> |
| 43 | +</TelerikContextMenu> |
| 44 | +
|
| 45 | +<TelerikListView Data="@ListViewData" Width="700px" Pageable="true"> |
| 46 | + <Template> |
| 47 | + <div @oncontextmenu:preventDefault="true" |
| 48 | + @oncontextmenu="@( (MouseEventArgs e) => ShowContextMenu(e, context) )" |
| 49 | + class="listview-item"> |
| 50 | + <h4>@context.Name</h4> |
| 51 | + <h5>@context.Team</h5> |
| 52 | + <h6>Special context menu: @context.IsSpecial</h6> |
| 53 | + </div> |
| 54 | + </Template> |
| 55 | +</TelerikListView> |
| 56 | +
|
| 57 | +@code { |
| 58 | + public List<ContextMenuItem> MenuItems { get; set; } |
| 59 | + TelerikContextMenu<ContextMenuItem> TheContextMenu { get; set; } |
| 60 | + SampleData LastClickedItem { get; set; } |
| 61 | +
|
| 62 | + async Task ShowContextMenu(MouseEventArgs e, SampleData clickedItem) |
| 63 | + { |
| 64 | + // save the target/metadata |
| 65 | + LastClickedItem = clickedItem; |
| 66 | + // change the menu items |
| 67 | + PrepareMenuItems(clickedItem); |
| 68 | + // show the menu |
| 69 | + await TheContextMenu.ShowAsync(e.ClientX, e.ClientY); |
| 70 | + } |
| 71 | +
|
| 72 | + void PrepareMenuItems(SampleData clickedItem) |
| 73 | + { |
| 74 | + // disable one item, you can make bigger changes here too |
| 75 | + MenuItems[2].Items[0].Disabled = clickedItem.IsSpecial; |
| 76 | + } |
| 77 | +
|
| 78 | + async Task ClickHandler(ContextMenuItem clickedItem) |
| 79 | + { |
| 80 | + // handle the command from the context menu by using the stored metadata |
| 81 | + if (!string.IsNullOrEmpty(clickedItem.CommandName) && LastClickedItem != null) |
| 82 | + { |
| 83 | + Console.WriteLine($"The programm will now perform the {clickedItem.CommandName} operation for {LastClickedItem.Name}"); |
| 84 | + } |
| 85 | + LastClickedItem = null; |
| 86 | + } |
| 87 | +
|
| 88 | + // generate sample data for the listview and the menu |
| 89 | + protected override void OnInitialized() |
| 90 | + { |
| 91 | +
|
| 92 | + MenuItems = new List<ContextMenuItem>() |
| 93 | + { |
| 94 | + new ContextMenuItem |
| 95 | + { |
| 96 | + Text = "More Info", |
| 97 | + Icon = IconName.Information, |
| 98 | + CommandName = "info" |
| 99 | + }, |
| 100 | + new ContextMenuItem |
| 101 | + { |
| 102 | + Separator = true |
| 103 | + }, |
| 104 | + new ContextMenuItem |
| 105 | + { |
| 106 | + Text = "Advanced", |
| 107 | + Items = new List<ContextMenuItem>() |
| 108 | + { |
| 109 | + new ContextMenuItem |
| 110 | + { |
| 111 | + Text = "Delete", |
| 112 | + Icon = IconName.Delete, |
| 113 | + CommandName = "delete" |
| 114 | + }, |
| 115 | + new ContextMenuItem |
| 116 | + { |
| 117 | + Text = "Report", |
| 118 | + Icon = IconName.Cancel, |
| 119 | + CommandName = "report" |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + }; |
| 124 | +
|
| 125 | + base.OnInitialized(); |
| 126 | + } |
| 127 | +
|
| 128 | + public class ContextMenuItem |
| 129 | + { |
| 130 | + public string Text { get; set; } |
| 131 | + public string CommandName { get; set; } |
| 132 | + public string Icon { get; set; } |
| 133 | + public bool Separator { get; set; } |
| 134 | + public bool Disabled { get; set; } |
| 135 | + public List<ContextMenuItem> Items { get; set; } |
| 136 | + } |
| 137 | +
|
| 138 | + List<SampleData> ListViewData { get; set; } = Enumerable.Range(1, 25).Select(x => new SampleData |
| 139 | + { |
| 140 | + Id = x, |
| 141 | + Name = $"Name {x}", |
| 142 | + Team = $"Team {x % 3}", |
| 143 | + IsSpecial = x % 4 == 0 |
| 144 | + }).ToList(); |
| 145 | +
|
| 146 | + public class SampleData |
| 147 | + { |
| 148 | + public int Id { get; set; } |
| 149 | + public string Name { get; set; } |
| 150 | + public string Team { get; set; } |
| 151 | + public bool IsSpecial { get; set; } |
| 152 | + } |
| 153 | +} |
| 154 | +
|
| 155 | +<style> |
| 156 | + .listview-item { |
| 157 | + height: 150px; |
| 158 | + width: 150px; |
| 159 | + display: inline-block; |
| 160 | + margin: 10px; |
| 161 | + border: 1px solid black; |
| 162 | + border-radius: 10px; |
| 163 | + padding: 10px; |
| 164 | + } |
| 165 | +</style> |
| 166 | +```` |
| 167 | + |
| 168 | +## Context Menu for a Grid Row |
| 169 | + |
| 170 | +To integrate the context menu with the Telerik Grid, you need to: |
| 171 | + |
| 172 | +1. Use the grid's `OnRowContextMenu` event to get the current row model and show the menu |
| 173 | +2. Use the context menu's `OnClick` event to handle the desired operation |
| 174 | + |
| 175 | +In this example, the context menu is used to select/deselect items, put an item in edit mode and delete items |
| 176 | + |
| 177 | +>caption Use a Context Menu for Grid rows |
| 178 | +
|
| 179 | +````CSHTML |
| 180 | +@using System.Collections.Generic |
| 181 | +@using System.Collections.ObjectModel |
| 182 | +
|
| 183 | +<TelerikContextMenu @ref="@ContextMenuRef" Data="@MenuItems" OnClick="@((MenuItem item) => OnItemClick(item))"></TelerikContextMenu> |
| 184 | +
|
| 185 | +<TelerikGrid Data="@GridData" @ref="@GridRef" |
| 186 | + EditMode="@GridEditMode.Inline" |
| 187 | + Height="500px" |
| 188 | + Pageable="true" |
| 189 | + OnCreate="@CreateItem" OnUpdate="@UpdateHandler" |
| 190 | + OnRowContextMenu="@OnContextMenu" |
| 191 | + SelectionMode="@GridSelectionMode.Multiple" |
| 192 | + @bind-SelectedItems="@SelectedItems"> |
| 193 | + <GridToolBar> |
| 194 | + <GridCommandButton Command="Add" Icon="add">Add Employee</GridCommandButton> |
| 195 | + </GridToolBar> |
| 196 | + <GridColumns> |
| 197 | + <GridColumn Field=@nameof(SampleData.ID) Editable="false" /> |
| 198 | + <GridColumn Field=@nameof(SampleData.Name) /> |
| 199 | + <GridCommandColumn> |
| 200 | + <GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton> |
| 201 | + <GridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</GridCommandButton> |
| 202 | + </GridCommandColumn> |
| 203 | + </GridColumns> |
| 204 | +</TelerikGrid> |
| 205 | +
|
| 206 | +@if (SelectedItems.Any()) |
| 207 | +{ |
| 208 | + <ul> |
| 209 | + @foreach (var item in SelectedItems) |
| 210 | + { |
| 211 | + <li>@item.Name</li> |
| 212 | + } |
| 213 | + </ul> |
| 214 | +} |
| 215 | +
|
| 216 | +@code { |
| 217 | + //data sources |
| 218 | + ObservableCollection<SampleData> GridData { get; set; } |
| 219 | + List<MenuItem> MenuItems { get; set; } |
| 220 | + IEnumerable<SampleData> SelectedItems { get; set; } = Enumerable.Empty<SampleData>(); |
| 221 | + //metadata for the context menu actions |
| 222 | + SampleData SelectedPerson { get; set; } |
| 223 | + //component references so we can use their methods |
| 224 | + TelerikContextMenu<MenuItem> ContextMenuRef { get; set; } |
| 225 | + TelerikGrid<SampleData> GridRef { get; set; } |
| 226 | +
|
| 227 | + // sample menu item class |
| 228 | + public class MenuItem |
| 229 | + { |
| 230 | + public string Text { get; set; } |
| 231 | + public string Icon { get; set; } |
| 232 | + public Action Action { get; set; } |
| 233 | + public string CommandName { get; set; } |
| 234 | + } |
| 235 | +
|
| 236 | + // show the context menu for a particular row |
| 237 | + async Task OnContextMenu(GridRowClickEventArgs args) |
| 238 | + { |
| 239 | + var argsItem = args.Item as SampleData; |
| 240 | +
|
| 241 | + SelectedPerson = argsItem; |
| 242 | +
|
| 243 | + if (args.EventArgs is MouseEventArgs mouseEventArgs) |
| 244 | + { |
| 245 | + await ContextMenuRef.ShowAsync(mouseEventArgs.ClientX, mouseEventArgs.ClientY); |
| 246 | + } |
| 247 | + } |
| 248 | +
|
| 249 | + // sample handling of the context menu click |
| 250 | + async Task OnItemClick(MenuItem item) |
| 251 | + { |
| 252 | + // one way to pass handlers is to use an Action, you don't have to use this |
| 253 | + if (item.Action != null) |
| 254 | + { |
| 255 | + item.Action.Invoke(); |
| 256 | + } |
| 257 | + else |
| 258 | + { |
| 259 | + // or you can use local code to perform a task |
| 260 | + // such as put a row in edit mode or select it |
| 261 | + switch (item.CommandName) |
| 262 | + { |
| 263 | + case "BeginEdit": // read more at https://localhost/blazor-ui/components/grid/state#initiate-editing-or-inserting-of-an-item |
| 264 | + var currState = GridRef.GetState(); |
| 265 | + currState.InsertedItem = null; |
| 266 | + SampleData itemToEdit = SampleData.GetClonedInstance(GridData.Where(itm => itm.ID == SelectedPerson.ID).FirstOrDefault()); |
| 267 | + currState.OriginalEditItem = itemToEdit; |
| 268 | + await GridRef.SetState(currState); |
| 269 | + break; |
| 270 | + case "ToggleSelect": |
| 271 | + var selItems = SelectedItems.ToList(); |
| 272 | + if (SelectedItems.Contains(SelectedPerson)) |
| 273 | + { |
| 274 | + selItems.Remove(SelectedPerson); |
| 275 | + } |
| 276 | + else |
| 277 | + { |
| 278 | + selItems.Add(SelectedPerson); |
| 279 | + } |
| 280 | + SelectedItems = selItems; |
| 281 | + break; |
| 282 | + default: |
| 283 | + break; |
| 284 | + } |
| 285 | + } |
| 286 | + SelectedPerson = null; // clean up |
| 287 | + } |
| 288 | +
|
| 289 | + // generate data |
| 290 | + protected override void OnInitialized() |
| 291 | + { |
| 292 | + // context menu items |
| 293 | + MenuItems = new List<MenuItem>() |
| 294 | + { |
| 295 | + new MenuItem(){ Text = "Select", Icon=IconName.CheckboxChecked, CommandName="ToggleSelect" }, |
| 296 | + new MenuItem(){ Text = "Edit", Icon=IconName.Edit, CommandName="BeginEdit" }, |
| 297 | + new MenuItem(){ Text = "Delete", Icon=IconName.Delete, Action = DeleteItem } |
| 298 | + }; |
| 299 | +
|
| 300 | + // generate data for the grid |
| 301 | + GridData = new ObservableCollection<SampleData>(); |
| 302 | + var rand = new Random(); |
| 303 | +
|
| 304 | + for (int i = 0; i < 100; i++) |
| 305 | + { |
| 306 | + GridData.Add(new SampleData() |
| 307 | + { |
| 308 | + ID = i, |
| 309 | + Name = "Employee " + i.ToString(), |
| 310 | + }); |
| 311 | + } |
| 312 | + } |
| 313 | +
|
| 314 | +
|
| 315 | + // CUD operations for the grid |
| 316 | +
|
| 317 | + async Task CreateItem(GridCommandEventArgs args) |
| 318 | + { |
| 319 | + var argsItem = args.Item as SampleData; |
| 320 | +
|
| 321 | + // call the actual data service here |
| 322 | +
|
| 323 | + argsItem.ID = GridData.Count + 1; |
| 324 | +
|
| 325 | + GridData.Insert(0, argsItem); |
| 326 | + } |
| 327 | +
|
| 328 | + void DeleteItem() // not async so it can be passed as an Action |
| 329 | + { |
| 330 | + var argsItem = SelectedPerson; |
| 331 | +
|
| 332 | + // call the actual data service here |
| 333 | +
|
| 334 | + GridData.Remove(argsItem); |
| 335 | + } |
| 336 | +
|
| 337 | + async Task UpdateHandler(GridCommandEventArgs args) |
| 338 | + { |
| 339 | + var argsItem = args.Item as SampleData; |
| 340 | +
|
| 341 | + // call the actual data service here |
| 342 | +
|
| 343 | + var index = GridData.ToList().FindIndex(i => i.ID == argsItem.ID); |
| 344 | + if (index != -1) |
| 345 | + { |
| 346 | + GridData[index] = argsItem; |
| 347 | + } |
| 348 | + } |
| 349 | +
|
| 350 | + public class SampleData |
| 351 | + { |
| 352 | + public int ID { get; set; } |
| 353 | + public string Name { get; set; } |
| 354 | +
|
| 355 | +
|
| 356 | + public override bool Equals(object obj) |
| 357 | + { |
| 358 | + if (obj is SampleData) |
| 359 | + { |
| 360 | + return this.ID == (obj as SampleData).ID; |
| 361 | + } |
| 362 | + return false; |
| 363 | + } |
| 364 | +
|
| 365 | + public SampleData() |
| 366 | + { |
| 367 | +
|
| 368 | + } |
| 369 | +
|
| 370 | + public SampleData(SampleData itmToClone) |
| 371 | + { |
| 372 | + this.ID = itmToClone.ID; |
| 373 | + this.Name = itmToClone.Name; |
| 374 | + } |
| 375 | +
|
| 376 | + public static SampleData GetClonedInstance(SampleData itmToClone) |
| 377 | + { |
| 378 | + return new SampleData(itmToClone); |
| 379 | + } |
| 380 | + } |
| 381 | +} |
| 382 | +```` |
| 383 | + |
| 384 | + |
| 385 | +## See Also |
| 386 | + |
| 387 | +* [Context Menu Overview]({%slug contextmenu-overview%}) |
| 388 | +* [Context Menu Data Binding]({%slug contextmenu-data-binding-overview%}) |
| 389 | +* [Context Menu Templates]({%slug contextmenu-templates-overview%}) |
0 commit comments