Sunday, September 29, 2013

Telerik Kendo Grid - What's the drama behind putting a link a grid's cell

After a few hours I was about the end of my rope playing with Telerik's Kendo Grid control.  Seriously...how hard could it be to insert a link into grid that will generate an action, e.g. one of the CRUD operations?  Here's how I finally managed this trick.

The MVC 4 standard approach is rather easy and straight forward.  Really all that is necessary is to post a bunch of Html.ActionLink methods as illustrated in this code snip below.

 @foreach(OfferModel offerModel in ViewData.Model.Offers)  
 {  
   <tr>  
    <td>@Html.DisplayFor(m=> offerModel.Id)</td>  
    <td>@Html.DisplayFor(m=> offerModel.Title)</td>  
    <td>@Html.DisplayFor(m=> offerModel.Description)</td>  
    <td>@Html.DisplayFor(m=> offerModel.Status)</td>  
    <td>  
      @Html.ActionLink("Edit", "Edit", "Offer", new { id=offerModel.Id}, new {@class="edit_button})  
      @Html.ActionLink("Delete", "Delete", "Offer", new { id=offerModel.Id}, new {@class="delete_button})  
      @Html.ActionLink("Copy", "Copy", "Offer", new { id=offerModel.Id}, new {@class="copy_button})  
    </td>  
   </tr>  
 }  

There's a bit more going on here than simply having the action link's place a URL in my table.  I added a class so that these links appear like buttons (standard stuff from jQuery, nothing exciting).

What you end up with is displayed above when the "buttons" are clicked the appropriate controller method is invoked along with the Id so that the right record is either edited, deleted, or copied.

Then there's the Kendo grid - which honestly I'm impressed with.  No having to worry about cross browser compatability, build in sort, filter, and a lot more makes it worth the trouble of trying to figure this out.

There's a lot of postings around putting a link into a Kendo grid.  Some of the ideas presented were pretty decent - sadly they didn't work for me and likely left a few people scratching their heads.  The biggest problem I needed to solve was to be able to embed the "id" of the row in the Html.ActionLink so that the resulting URL would look something like: /Offers/Edit/<id>.

How I got this work was to insert a client template as shown below.

@(Html.Kendo().Grid(Model)  
    .Name("OfferModelGrid")  
    .Columns(columns =>  
    {  
      columns.Bound(p => p.Id);  
      columns.Bound(p => p.Title);  
      columns.Bound(p => p.ShortDescription);  
      columns.Bound(p => p.Status);  
      columns.Bound(p => p.StartDate);  
      columns.Bound(p => p.EndDate);  
   
      columns.Bound(p => p.Id)  
        .Filterable(false)  
        .Title("Action")  
        .Template(@<text></text>)  
        .ClientTemplate(Html.ActionLink("Edit", "Edit", "Offer", new {id = "#=Id#"}, new {@class = "edit_button"}).ToHtmlString() +  
                Html.ActionLink("Delete", "Delete", "Offer", new {id = "#=Id#"}, new {@class = "delete_button"}).ToHtmlString() +  
                Html.ActionLink("Copy", "Copy", "Offer", new {id = "#=Id#"}, new {@class = "copy_button"}).ToHtmlString());  
    }  
    )  
    .Pageable()  
    .Sortable()  
    .Filterable()  
    .DataSource(datasource => datasource.Ajax().Read(read => read.Action("FetchOffers", "Offer")))  
    )  

A number of examples suggested putting a Html.ActionLine between the <text></text> elements - however this didn't seem to affect much, if anything in the results.  The key piece really is the population of the data that needed to be part of the action's URL - namely the #=Id# you see in the forth parameter.  What this is really doing is taking the Id property of the Model associated with the page and placing it into the resulting action link.  The result is exactly what you need - a link which will invoke the indicated method in the indicated controller.  Add in a bit of class and you end up something that looks remarkably like the original MVC screen.


2 comments:

  1. I have the same but the delete is not firing the event. How did you get that to work? (with a popup)

    ReplyDelete
    Replies
    1. I honestly hadn't done a pop-up - rather as you can see from my code I provided an action link that would direct to another view that controller would provide to the user.

      From what I've read you can in fact call another javascript function. Given the function called "testMe" - you can place this code in place of Html.ActionLink:

      "#=TestMe#"

      (replace xxonclick with onclick).

      If you want to feed some data into that javascript call:

      "#=TestMe#"

      The "data" is apparently a key word that provides the information for the selected row.

      Delete