6

I want to utilize the Kendo UI Context Menu in my app. I was expecting the standard behavior of having text displayed in the menu itself but a different value (an ID or key) being returned to the select event handler.

For instance, the menu displays a list of names but when I click on one of them, I get the ID associated with the name.

I've tried adding additional properties besides text to the array of items in the context menu but I don't see them on the event object in the handler.

I can't use the text to find the appropriate id that matches it since there could be entries with the same text but different IDs.

Any ideas?


Edit:

Currently I build the context menu like this:

open: (e) => {
    let itemKeys = [1, 2, 3];

    let menu = e.sender;
    menu.remove(".context-menu-item");
    menu.append(itemKeys.map((itemKey) => {
        return {
            text: "<div data-item-key='" + itemKey + "'>Test Text</div>",
            cssClass: "context-menu-item",
            encoded: false
        };
    }));
}

While this solution does satisfy my needs, it adds an extra element to the DOM which, while being insignificant, isn't perfect...

Shai
  • 3,659
  • 2
  • 13
  • 26

2 Answers2

7

It's undocumented, but ContextMenu actually inherits from Menu. Therefore, all options of Menu are available. In particular, you can add an attr object to your data items, cf the example in the documentation.

To complete your example:

open: (e) => {
    let itemKeys = [1, 2, 3];

    let menu = e.sender;
    menu.remove(".context-menu-item");
    menu.append(itemKeys.map((itemKey) => {
        return {
            text: "Test Text",
            cssClass: "context-menu-item",
            // add whatever attribute
            attr: {
                'data-item-key': itemKey
            }
        };
    }));
}

Then, in your select handler:

select: (e) => {
    console.log($(e.item).data('item-key'));
}
Métoule
  • 13,062
  • 2
  • 56
  • 84
  • 1
    Thanks, it worked. Do you happen to know when this option was added? I think I might have tried it a year ago and it didn't work... Anyway, I preferred avoiding another jQuery call so I used `attr: {"item-key": itemKey}` and `e.item.getAttribute("item-key")`. – Shai Mar 29 '18 at 07:32
  • Based on my tests, it appeared in version `2016.2.504` (was not present in `2016.1.112`). – Métoule Mar 29 '18 at 07:41
1

Option 1) You might add a data that will specify your Id. I made this with mvc wrapper but it can be done with pure javascript as well.

@(Html.Kendo()
    .ContextMenu()
    .Name("contextMenuGridTicketTestiMessaggi")
    .Target("#gridTicketTestiMessaggi")
    .Filter("tr")
    .Orientation(ContextMenuOrientation.Vertical)
    .Items(items =>
    {
        items.Add().Text("Update").HtmlAttributes(new { data_toggle = "update" });
        items.Add().Text("Save").HtmlAttributes(new { data_toggle = "save" });
        items.Add().Text("Delete").HtmlAttributes(new { data_toggle = "delete" });
    })
    .Events(e => {
        e.Select("contextMenuGridTicketTestiMessaggiSelect"); 
    }));

    var contextMenuGridTicketTestiMessaggiSelect = function(e) {
        var action = $(e.item).data("toggle");
        var that = this;
        if (action === "update") {}
    ...

Option 2) You might define with every item(throught html content) a function to be called in each onClick event for the specific item.

items.Add().Encoded(false).Text("<span onclick='update()'>Update</span>");
items.Add().Encoded(false).Text("<span onclick='delete()'>Delete</span>");
...

Update

<div id="target">Target</div>
<ul id="context-menu"></div>
<script>
    $("#context-menu").kendoContextMenu({
        target: "#target",
        open: function(e) {
            let itemKeys = [1, 2, 3];

            let menu = e.sender;                 
            menu.remove(".context-menu-item");
            menu.setOptions({
                dataSource: itemKeys.map((itemKey) => {
                    return {
                        text: "<div data-item-key='" + itemKey + "' style='white-space: nowrap'>Test Text</div>",
                        cssClass: "context-menu-item",
                        encoded: false
                    };
                })
            });
        },
        select: function(e) {
           console.log($($(e.item).find("div")[0]).data("item-key"))                      
        }
    });
</script>
Métoule
  • 13,062
  • 2
  • 56
  • 84
Giovanni Romio
  • 1,008
  • 1
  • 11
  • 30
  • First of all, thanks for your answer. **Option 1**: this is exactly what I want to do but there is no way to add HTML attributes to items when using the Kendo UI ContextMenu widget, at least as far as I know. **Option 2**: In my current solution I do something similar to what you suggested but instead of supplying a function, I enter my extra data in an attribute in the inner element and extract it in the `select` event. – Shai Apr 20 '17 at 09:16
  • You are welcome. I used those solutions in the current MVC project i'm working on and both works. Those solutions don't satisfy my obsession for clear code but i don't think it can be done in a better way. – Giovanni Romio Apr 20 '17 at 09:33
  • The problem is that they're working in MVC but the first option isn't available in the JS Kendo UI and I have a better solution than the second one... – Shai Apr 20 '17 at 09:36
  • I tried first solution and works with js as well as long as you define data attributes in the list item definition:
    Target
    • Item 1
    – Giovanni Romio Apr 20 '17 at 09:55
  • It's not totally clear from my original question but I set the items dynamically and not in the HTML. – Shai Apr 20 '17 at 10:40
  • Can you post the code otherwhise it's hard to help? – Giovanni Romio Apr 20 '17 at 10:41
  • I added my current code to the original question above. – Shai Apr 20 '17 at 11:09
  • Does menu.setOptions fix the issue? – Giovanni Romio Apr 20 '17 at 19:27
  • `setOptions` allows setting any of the fields of the `ContextMenuOptions` object of the context menu. This allows me to set the `dataSource` field and the items of the context menu but I can't add additional data to the items in this manner either. – Shai Apr 20 '17 at 19:36
  • Unfortunately no, only few properties are available throught setOptions which are considered in the items creation in the DOM. – Giovanni Romio Apr 20 '17 at 19:43