This is a migrated thread and some comments may be shown as answers.

[Solved] Client-side binding via JSON call

1 Answer 314 Views
Grid
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Simon
Top achievements
Rank 1
Simon asked on 30 Nov 2010, 11:01 PM
Hi,

I have a page in my MVC app that consists of some filter options (a couple of select boxes) and the results which display in the Telerik MVC grid. The grid also uses custom binding to implement paging and sorting. I had this working easily with server binding and I also managed to get it working with Ajax binding. The initial load, paging and sorting all worked using my controller method tagged with the [GridAction] attribute and passing back a GridModel into the View. This all worked great.

However, remember those filter options I have at the top? When I click Search to initiate a search it still does a postback.

I want to get rid of this postback, such that the data is retrieved from my controller method using an Ajax call and rebound to the grid. I would like to take out the .DataBinding() from the grid definition and use jQuery to do the databinding, both for initial load and when the user clicks Search.

Can someone point me in the right direction? There do not appear to be any code samples that do this. The Twitter example doesn't call into a controller method, and I want to use my controller method as that is how the paging and sorting works.

many thanks,
Simon.

1 Answer, 1 is accepted

Sort by
0
Simon
Top achievements
Rank 1
answered on 02 Dec 2010, 12:42 AM
I solved the issue starting with the sample code from this post: http://www.telerik.com/community/forums/aspnet-mvc/grid/client-binding-with-no-initial-source.aspx (thanks Atanas).

However, since I was doing my own binding using the onDataBinding client event, neither Template or ClientTemplate columns would work. Therefore to do my own custom column formatting I had to use the onRowDataBound and manipulate individual cells using JQuery. That was a serious pain in the butt.

Anyway, it works.

Here is the grid definition. Notice that DataBinding is commented out and so are Template and ClientTemplate because they won't work without binding set (grrrr!).

Html.Telerik().Grid<NovationConsentEntity>()
    .Name("Grid")
    .PrefixUrlParameters(false)
    //.DataBinding(db => db.Server().Select("Monitor", "NovationConsent"))
    //.DataBinding(db => db.Ajax().Select("MonitorCustomBinding", "NovationConsent"))
    .ClientEvents(events =>
                      {
                          events.OnRowDataBound("onRowDataBound");
                          events.OnDataBinding("onDataBinding");
                      })
    .Columns(columns =>
                 {
                     columns.Bound(n => n.Book)
                         .HeaderHtmlAttributes(new {style = "height:40px;"});
                     columns.Bound(n => n.TransactionRef);
                     columns.Bound(n => n.TransactionNumberSupplement)
                         .Title("Transaction Number<br/>Supplement")
                         .HeaderHtmlAttributes(new { style = "white-space:nowrap; vertical-align:top;" });
                     if (Model.AllowChangeStatus)
                     {
                         columns
                             .Bound(n => n.UiStatusCode)
                             // Can't use Format because I need to access more than one property of the Model
                             //.Format(
                             //    string.Format("<a href='{0}' onclick = 'StopEventPropagation(event);'>{1}</a>",
                             //           Url.Action("ChangeStatus", new { id = "<#= NovationConsentId #>", uiStatusCode = "{0}" }),
                             //           "{0}"))
                             //.Encoded(false)
                             .Title("<b>Status</b>")
                             // Template is for Server binding
                             //.Template(
                             //    n =>
                             //    Html.ActionLink(n.UiStatusCode, "ChangeStatus",
                             //                    new { id = n.NovationConsentId, uiStatusCode = n.UiStatusCode },
                             //                    new { onclick = "StopEventPropagation(event);" }))
                             // ClientTemplate is for Ajax binding
                             //.ClientTemplate(
                             //   string.Format("<a href='{0}' onclick = 'StopEventPropagation(event);'>{1}</a>",
                             //       Url.Action("ChangeStatus", new { id = "<#= NovationConsentId #>", uiStatusCode = "<#= UiStatusCode #>" }),
                             //       "<#= UiStatusCode #>"));
                             ;
                     }
                     else
                     {
                         columns.Bound(n => n.UiStatusCode).Title("Status");
                     }

Here is my Javascript to do the binding and also to accomplish the formatting that the templates can't do:

//function to add row onclick handler for Ajax binding
function onRowDataBound(e) {
    e.row.style.cursor = "pointer";
 
    var novationConsentId = e.dataItem.NovationConsentId;
    var uiStatusCode = e.dataItem.UiStatusCode;
     
    var detailsUrl = "/NovationConsent.mvc/NovationConsent/Details/" + novationConsentId + "/" + uiStatusCode;
    var changeStatusUrl = "/NovationConsent.mvc/NovationConsent/ChangeStatus/" + novationConsentId + "/" + uiStatusCode;
    var changeStatusHtml = jQuery.validator.format("<a href='{0}' onclick = 'StopEventPropagation(event);'>{1}</a>",
                                        changeStatusUrl,
                                        uiStatusCode);
 
    e.row.cells[3].innerHTML = changeStatusHtml;
 
    $(e.row).click(function() {
        OpenDetailsWindow(detailsUrl);
    });
}
 
function onDataBinding(e) {
    var grid = $("#Grid").data('tGrid');
 
    var url = GetRefreshUrl(grid.currentPage) + "/" + grid.sortExpr();
 
    $('body').css('cursor', 'wait');
 
    $.getJSON(url,
        null,
        function(result) {
            grid.total = result.total;
            grid.pageSize = 20;
            grid.dataBind(result.data);
        });
 
        $('body').css('cursor', 'auto');
    }

Here's my controller method. Be sure not to have the [GridAction] attribute set, as I had that by accident and it gave me errors about JsonRequestBehavior.AllowGet not being set.

public ActionResult MonitorAjaxBinding(string blah, int page, int size, string orderBy)
{
    var model = GetMonitorModel(string blah);
 
    return Json(new
                    {
                        data = model.Novations,
                        total = model.Novations.TotalRecords
                    },
                JsonRequestBehavior.AllowGet);
}

The reason I want to do my own binding is so that I can refresh the grid on button click after the user selects different search options.

Hope that helps someone because I didn't find any other people in the forums trying to do this exact type of thing (my own binding and also formatting columns without templates).

Simon.
Tags
Grid
Asked by
Simon
Top achievements
Rank 1
Answers by
Simon
Top achievements
Rank 1
Share this question
or