Advanced row-level operations with KendoUI

29 posts, 1 answers
  1. Mono
    Mono avatar
    7 posts
    Member since:
    Nov 2011

    Posted 30 Nov 2011 Link to this post

    Hello,

    I'm very interested in using Kendo UI for my upcoming project. However, i have two needs that need to be met. I would like to figure out how to integrate them into my test project. For my test project, I'm just altering the index.html in the examples/web/grid directory. Within this grid, I need to support:

    1. Double-Clicking on a row. When someone double-clicks on a row, I want to just show an an alert window that says "Hello", just to see it working.
    2. Context-Menu on a row. When someone right-clicks on a row, I need to show a popup menu. I know this won't work in touch-based environments. But we're building a desktop solution and context-menu is a requirement, not an option :(.
    Is it possible to do these? If so, how do you do it on the example grid?

    Thank you!
  2. Answer
    Atanas Korchev
    Admin
    Atanas Korchev avatar
    8462 posts

    Posted 01 Dec 2011 Link to this post

    Hello Mono,

     You can easily use the built-in "dblclick" and "contextmenu" DOM events. I have created a quick demo to show you how to do this:


    Regards,
    Atanas Korchev
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  3. Kendo UI is VS 2017 Ready
  4. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 07 Feb 2012 Link to this post

    For those of you who are looking to use a context menu with KendoUI (as I was).  I have created a small jQuery based context menu that uses the KendoUI stylesheet.  So, the context menu you get will fit right in with the rest of KendoUI.

    Enjoy!

    http://jsfiddle.net/jkappel/wVHmR/

    PS - Kendo Team, please build an official context control into KendoUI.
            Feel free to use my code if any of it is useful to you.
  5. Boone
    Boone avatar
    47 posts
    Member since:
    May 2008

    Posted 16 Feb 2012 Link to this post

    Jay, this looks great. Although, I need to know how to attach it to each grid row like your first question and unfortunately Atlanas's response to JSFIDDLE is throwing a 404 error.

    Here is my grid:

    $("#grid").kendoGrid({
                    scrollable: false,
                    sortable: true,
                    pageable: true,
                    selectable: "row",
                    sortable: {
                        mode: "multiple",
                        allowUnsort: true
                    },
                    columns: [
                                //Fields here
                            ],
                    dataSource: {
                        schema: {
                            data: "d.LoadSearchingResults",
                            total: function (data) {
                                return data.d.TotalResults;
                            }
                        },
                        pageSize: 200,
                        transport: {
                            read: {
                                url: "ServiceURL",
                                contentType: "application/json; charset=utf-8",
                                type: "POST"
                            },
                            parameterMap: function (options) {
                                var object = {};
                                object.pageIndex = options.page;
                                object.size = options.pageSize;
                                object.orderBy = options.sort;
                                return JSON.stringify({ options: object, criteria: searchCriteria });
                            }
                        }
                    }
                });

    Any help would be greatly appreciated. Thanks
  6. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 16 Feb 2012 Link to this post

    Ah, yes.  Basically what you need to do is use a jQuery selector for the trigger property that will get hold of each row you want.  One thing to keep in mind with the Kendo Gird though, is that if you are using remote data, the data will not be available when you instantiate your grid.  So, you have to attach to the dataBound event and do your work there.  For example:

     $("#grid").kendoGrid({
         dataBound
    : function(e) {
             my.contextMenu({
    trigger: '#grid td',
            leftButton: false,
            rightButton: true,
            menu: '#testMenu',
            callback: ctxCallback
        });

         
    }
     
    });

    I updated my jsFiddle example to include a grid as well.  Hope this helps!
    http://jsfiddle.net/jkappel/wVHmR/ 

    PS - in my example, I attached it to the TD elements, but you can use any element you like such as TR or whatever.
  7. Boone
    Boone avatar
    47 posts
    Member since:
    May 2008

    Posted 16 Feb 2012 Link to this post

    Perfect, although I would like the menu to come out where the mouse was clicked (I should be able to handle that part). One more question thought, how would I get that rows ID populated into that value.

    So when I right click, the menu comes up. If I click on the first item I would like to call another webservice and pass in the id of the row that brought up the context menu.
  8. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 17 Feb 2012 Link to this post

    OK, so the callback from the item click passes the menu Item that was clicked, as well as the trigger that opened the menu.  So, by interrogating the trigger object, you should be able to get the data you need.  For example if the trigger object is a table row, then you might want to interrogate that row for the ID or the data value within the first TD.

    It might look something like this:

    function ctxCallback (menuItem, trigger) {
        var id = trigger.find('td:first').attr('id');
        alert('User clicked Context Menu Item "'+ menuItem.text().trim() +'" for the id: ' +id);
  9. Mike
    Mike avatar
    19 posts
    Member since:
    Feb 2012

    Posted 26 Mar 2012 Link to this post


    Hello,
    I'm interested to see the example for the double-click on the grid.
    The connection to the example indicates that the page does not exist.
    Can I have the correct link?
    Thank you.



    http://jsfiddle.net/korchev/UVaKQ/44/ -> not page found
  10. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 26 Mar 2012 Link to this post

    I don't know what happened to Atanas jsFiddle page, but if all you need is an example of how to respond to double clicking a row, this should help:

        $('#myGrid tr').dblclick(function({
            alert($(this).find('td:first').text());
        }); 

    when you double click a row, you will get an alert with the text data from the first TD element on the row.
  11. Mike
    Mike avatar
    19 posts
    Member since:
    Feb 2012

    Posted 26 Mar 2012 Link to this post

    Thanks.
  12. Ikue
    Ikue avatar
    2 posts
    Member since:
    Jan 2011

    Posted 19 Aug 2012 Link to this post

    Hi 

    My client wants to have right click menu for filtering.
    I could mange to create right click menu and filter a datasource.(Thanks for nice work  http://jsfiddle.net/jkappel/wVHmR/ 
    )
    However the context menu doesn't appear after I filter it.
    Do I need to recreate a menu?
  13. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 20 Aug 2012 Link to this post

    Ikue,

         I have not played with the filtering myself, so I can't say for certain.  What I imagine is happening is that the data source removes all rows from the grid, filters the dataset, then re-inserts the filtered results.  Therefore, the objects in the grid are completley new.  The context menu attaches functions to events on the objects in the list.  Therefore, it would need to be run again since the new objects would not have the functions attached to their events.

    What you might want to do is to take the code that creates the context menu and place it in it's own procedure.  Then call that function from the grid dataBound event, and also after whatever code you have in place to filter the list.

    If you need more specific help, feel free to upload a sample of what you are trying to do and I would be happy to look at it for you. 
  14. Ikue
    Ikue avatar
    2 posts
    Member since:
    Jan 2011

    Posted 22 Aug 2012 Link to this post

    Hi Jay

    I repeated some lines of your function after filtering. It worked.
    Thank you!
  15. Andrew
    Andrew avatar
    4 posts
    Member since:
    Aug 2012

    Posted 11 Sep 2012 Link to this post

    Hi Jay Thanks for the awesome demo, just one thing, i am unable to get hold of the UID or the Entire Row data in the ctxCallback for some reason

    trigger.attr(

     

    'id') is undefined? any ideas

     

  16. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 11 Sep 2012 Link to this post

    What are you passing in for the trigger value when you create the context menu?
  17. Andrew
    Andrew avatar
    4 posts
    Member since:
    Aug 2012

    Posted 12 Sep 2012 Link to this post

    trigger: '#DriverLog td'

    the full function binds after the databound event so each row is bound to the menu, I even thought of trying to add another value to parse

    dataItem: this.dataItem($(this.currentTarget).closest('tr'))

     

     

    but this failed dismally.

    also i have been doing this the MVC way, this is how i bound your code, but getting no where with accessing row data.

     

    @{

     

    Html.Kendo().Grid<

     

    DriverLogDTO>()
    .Name("DriverLog")
    .Columns(columns =>
    {
    columns.Bound(o => o.LogDate).Format("{0:yyyy-MM-dd}")
    columns.Bound(o => o.LogItemID).Visible(
    false);
    }).DataSource(dataSource => dataSource
    .Ajax()
    .Model(model => model.Id(o => o.LogItemID))

     

    .Read(read =>
    read.Action(
    "GetDriverLog", "TripCapture", new { AssetID = ViewData["AssetID"], DriverID = ViewData["DriverID"], Startdate = DateTime.Parse(ViewData["StartDate"].ToString()), EndDate = DateTime.Parse(ViewData["EndDate"].ToString()) })))
    .Events(e => e.DataBound(
    "function() { my.contextMenu({ trigger: '#DriverLog td', leftButton: false, rightButton: true, menu: '#testMenu', callback: ctxCallback }); LineItems_Databound(); }"))

     

    .Render();}

     

     

  18. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 12 Sep 2012 Link to this post

    Alright, so you are binding the menu to the TD element which is fine.  But you want to read attributes from the row which contains the TD.  So, in your callback function, trigger will be a jQuery object referencing the TD element the user clicked.  Therefore, you should be able to get an attribute such as the id from the row containing the TD element via either of the methods below:

        trigger.parent().attr('id');  
    or
        trigger.closest('tr').attr('id');

    let me know if this still doesn't help and I will put together a sample for you.
  19. Stefan
    Stefan avatar
    15 posts
    Member since:
    Sep 2012

    Posted 13 Sep 2012 Link to this post

    Hi & thank you for the good tutorial script.
    I am new with using Kendo, so i cant get this working as i want with my grid.

    I want that when i right click on a <tr> in my grid i want to display the Menu. I want to begin by getting the id of that row as a value.
    I also want an alert when i double left click on a row in my grid.

    <div id="Grid">
    @(Html.Kendo().Grid(Model)
        .Name("GridField")
        .Columns(columns =>
        {
            columns.Bound(item => item.SalonID);
            columns.Bound(item => item.Avtnr);
            columns.Bound(item => item.SalonName);
            columns.Bound(item => item.Street);
            columns.Bound(item => item.ZipCode);
            columns.Bound(item => item.City);
            columns.Bound(item => item.Telephone);
            columns.Bound(item => item.SalonEmail);
            columns.Bound(item => item.Description);
            columns.Bound(item => item.ContactPerson);
        })
        .ColumnMenu()
        .Groupable()
        .Pageable()
        .Sortable()
        .Resizable(resize => resize.Columns(true))
        .Selectable(selectable => selectable.Mode(GridSelectionMode.Single))
        .DataSource(dataSource => dataSource
            .Ajax()
            .Read(read => read.Action("Read", "Search"))
            .ServerOperation(false)
            .PageSize(15)
        )
            .Events(events => events.Change("ctxCallback"))
        )
    </div>

    Here is the rest of the code:
    http://jsfiddle.net/Qz9MM/
  20. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 24 Sep 2012 Link to this post

    Stefan,

    Sorry for the delayed response, I have been on vacation.  The jsFiddle sample you posted does not contain a data grid, so I am not sure exactly how to help with that.  However, from the looks of the code that you pasted above, I think the issue you are running into is that when the grid is first instantiated, it has no rows in it.  Then the data source performs an asynchronous fetch.  Once the data has been received, the data source notifies the grid, and the grid generates the data rows.  Therefore, you must instantiate the context menu after the grid has generated it's data rows.  Look up within this thread at my February 16, 2012 post for assistance with this.

    Also, I have updated my jsFiddle example to include showing how to get a Row ID when using the TD as the trigger since so many people have been asking about it.  I hope this helps.

    http://jsfiddle.net/jkappel/wVHmR/ 
  21. steven
    steven avatar
    7 posts
    Member since:
    Oct 2012

    Posted 21 Oct 2012 Link to this post

    Jay,

    First, thanks for contributing your context menu to the site, Its greatly appreciated to a newbie like myself trying to learn kendoui.

    I have a grid, bound to remote data, and I have the context menu activating.

    I'm using this for a CRUD interface and was wondering, without displaying the "ID" field as the first column, is there any other way to have it recognize an "ID" to pass to script?

    Such as a product table:
    productid, productname and product price.  I dont want to show productid. can i still right click on an option, choose an "edit" option and have the script take me to product.cfm?productid=(productid variable)

    thanks
    steve

  22. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 22 Oct 2012 Link to this post

    Steven,

    I'm glad that my work on the context menu is useful to you.  In your situation, I would recommend that you use the KendoUI Row Templates to render your grid rows.  These allow you to have whatever HTML you want rendered for each row.  You can then assign your product id to a hidden div or as an attribute on some other item.  For example:

    <div class="myCustomRow">
        <div id="productId" style="display:none">${ productId }</div>
        <div class="column1">$ { productName }</div>
        <div class="column2">$ { price} </div>
        etc...
    </div>

    You could then attach the context menu to the "myCustomRow" class.  When the callback event fires, the trigger would be that div.  you could find your product_id via: trigger.find('#productId').html();

  23. Kerry
    Kerry avatar
    4 posts
    Member since:
    Jun 2012

    Posted 22 Oct 2012 Link to this post

    Hi Jay!  Since you seem to still be responding to this thread, I'd like to ask your advice on a problem I'm having.  I have a page with 2 context menus (per your code) that work fine until I throw a splitter on the page.  Any ideas on how to fix?  Here's a fiddle, top context works, bottom does not.

    http://jsfiddle.net/hKAB8/6/ 


    Thanks for any help!!!

    Kerry
  24. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 24 Oct 2012 Link to this post

    Kerry,

    Sorry for taking a bit to get back to you, but I have been looking into the issue you are experiencing.  Unfortunately, I have not been able to determine what the cause of it is.  I suspect that the instantiation of the splitter control re-creates the elements within the split containers, but my testing was not able to verify this.

    I also tried creating the context menus after the instantiation of the splitter, and even set a 1000ms timeout callback for their creation.  Nothing helped.  At this point, I don't know what to say.  Maybe someone from Kendo UI can help?
  25. Kerry
    Kerry avatar
    4 posts
    Member since:
    Jun 2012

    Posted 24 Oct 2012 Link to this post

    Thanks Jay!  I know you're under no obligation here.  I did ask Kendo and they updated my jsfiddle (http://jsfiddle.net/hKAB8/7/).  It looks like it's a positional thing.  Adding the splitter must reset the vertical position in that panel maybe.  It's still appearing way too far south but I'll continue to tweak it.
  26. Jay
    Jay avatar
    45 posts
    Member since:
    Dec 2011

    Posted 24 Oct 2012 Link to this post

    Well, that's quite interesting.  At least now you can just "fiddle" (pun intended) with the positioning of the menu to resolve the issue. :)

    You'll want to look in the menu.show() function.  The positioning starts with the following line:

    var pos = $(this).offset();
  27. Andrew
    Andrew avatar
    171 posts
    Member since:
    Jun 2009

    Posted 19 Jun 2013 Link to this post

    Has anyone managed to get this to work with a grid that loads data dynamically as well as one that refreshes?
    Or with multiple grids?

    If i put the context menu once before the grid is loaded i get no menu at all. and if i put it after the grid load i end up with multiple alert messages.
    So if the data was loaded 4 times and i have 2 grids, i will have 8 alert messages.
    http://jsfiddle.net/zawisza/HwUDA/4/
  28. Stefan Timm
    Stefan Timm avatar
    6 posts
    Member since:
    May 2007

    Posted 02 Jul 2013 Link to this post

    At first, thanks to Jay. I'm a MVC and Kendo beginner. The contextmenu is very usefull. Telerik send me an feedback, contextmenu on grid is not on their releaseplan. I think this is not the correct decision, because this is a basic usability thing in grids.

    I spent a lot of time to implement the menu by Jay to my grid, and some failure come up. I want to describe theese things, so other developer save time by implementation.

    @Jay, please can you optimize your code and send this to Telerik, they should publish this in their code-library, many thanks to you. I also wrote to Telerik, because I'm a Customer with a paid full license, and I expect this code in their code-library.

    At first, when you implement the menu to the grid, have a look how you bind the grid to your data. When you use ajax binding, you have to use the method .ondatabound to bind the menu function to the row. Any other way is not working.

    Ok, now the problems begin. The menu is bound to every cell in the grid, but when you switch on the virtual scrolling the grid will sometimes reload by the .ondatabound function. This is really a problem, because now the click event from the menuitem is bind a second time, or more. I'm searching and debugging to find this behaviour and I found the problem.
    You have to append the following line to the code:

    list.find('li').unbind("click");

    before you bind the event again.

    Now the click binding looks following:

    var list = menu.find('ul').css({ 'list-style-type': 'none', padding: 0, margin: 0 });
                list.find('li').unbind("click");
                list.find('li').click(function () {
                    menu.close();
                    options.callback($(this), menu.data('trigger'));
                }).mouseenter(function () {
                    $(this).addClass('k-state-hover');
                }).mouseleave(function () {
                    $(this).removeClass('k-state-hover');
                }).mousedown(function () {
                    $(this).addClass('k-state-selected');
                }).mouseup(function () {
                    $(this).removeClass('k-state-selected');
                }).css({ margin: 0, cursor: 'pointer', padding: '3px 7px 3px 7px' });

    The callback function is raised only one time.

    Then, do not change the trigger -> td to tr, this is not working in the kendo grid. The menu appears always in the first cell, not on the selected cell.

    Have Fun
    Regards from Germany

    @Jay, when you have a lot of time, or you are boring a little bit. You can try to implement the kendo.menu instead off ;-)

  29. Paolo
    Paolo avatar
    423 posts
    Member since:
    Jun 2009

    Posted 27 Aug 2013 Link to this post

    Hello,
    I'm looking at your solution for context menu.... just a question consider a case where I've a kendo grid with 3 column

    ID | Description | Date
    1   | User1           | 2013/08/22
    2   | User2           | 2013/08/26
    3   | User3           | 2013/08/24

    How can I modify you code so when I right click on a row I got "Show UserX data" ?

    I'm not able to access at the grid content when it opens the popup...I've tried with a function but I'm not js skilled...

    In Silverlight it's really easy.......here I'm lost...

    Thanks
    Paolo
  30. Stefan Timm
    Stefan Timm avatar
    6 posts
    Member since:
    May 2007

    Posted 28 Aug 2013 Link to this post

    Hi Paolo,

    I think this is more complex. You can try to add a new option, then you fill the new parameter with the cell value when you call my.contextmenu while ondatabound. In the function my.contextmenu now you can replace the html text with the value of the new parameter.
    regards Stefan Timm
Back to Top
Kendo UI is VS 2017 Ready