MVC4 WebGrid loaded from Ajax form - multiple calls to Controller when sorting and paging MVC4 WebGrid loaded from Ajax form - multiple calls to Controller when sorting and paging ajax ajax

MVC4 WebGrid loaded from Ajax form - multiple calls to Controller when sorting and paging


The reason this is happening is because the WebGrid control injects the following script into your DOM every time you render it (in your case every time you submit the AJAX form because the WebGrid is situated in a partial that you are injecting in your DOM):

<script type="text/javascript">    (function($) {        $.fn.swhgLoad = function(url, containerId, callback) {            url = url + (url.indexOf('?') == -1 ? '?' : '&') + '__swhg=' + new Date().getTime();            $('<div/>').load(url + ' ' + containerId, function(data, status, xhr) {                $containerId).replaceWith($(this).html());                if (typeof(callback) === 'function') {                    callback.apply(this, arguments);                }            });            return this;        }        $(function() {            $('table[data-swhgajax="true"],span[data-swhgajax="true"]').each(function() {                var self = $(this);                var containerId = '#' + self.data('swhgcontainer');                var callback = getFunction(self.data('swhgcallback'));                $(containerId).parent().delegate(containerId + ' a[data-swhglnk="true"]', 'click', function() {                    $(containerId).swhgLoad($(this).attr('href'), containerId, callback);                    return false;                });            })        });        function getFunction(code, argNames) {            argNames = argNames || [];            var fn = window, parts = (code || "").split(".");            while (fn && parts.length) {                fn = fn[parts.shift()];            }            if (typeof (fn) === "function") {                return fn;            }            argNames.push(code);            return Function.constructor.apply(null, argNames);        }    })(jQuery);</script>

This script is baked into the WebGrid helper and there's not much you could do against it once you enable AJAX on your WebGrid. In this script you will undoubtedly notice how it subscribes to the click event of the pagination anchors in a lively manner:

$(containerId).parent().delegate(containerId + ' a[data-swhglnk="true"]', 'click', function() {    $(containerId).swhgLoad($(this).attr('href'), containerId, callback);    return false;});

which is all sweet and dandy except that every time you click on the submit button you are injecting this script into your DOM (because your WebGrid is in the partial) and basically you are subscribing to the click event of the pagination anchors multiple times.

It would have been great if the authors of this WebGrid helper have left you the possibility to replace this delegate with a standard click handler registration which would have been ideal in this case as it wouldn't create multiple event registrations, but unfortunately the authors didn't left you with this possibility. They just assumed that the WebGrid would be part of the initial DOM and thus their script.

One way would be to subscribe to the OnBegin handler of the Ajax form submission and simply undelegate the existing event handlers because they will be overwritten once you refresh the DOM:

@using (Ajax.BeginForm("Search", "Home", null,    new AjaxOptions    {        InsertionMode = InsertionMode.Replace,        OnBegin = "callback",        HttpMethod = "POST",        UpdateTargetId = "gridContent",    }, new { @class = "search" })){    <input type="submit" value="Search" />}<div id="gridContent"></div><script type="text/javascript">    var callback = function (a) {        $('#tableDiv').parent().undelegate('#tableDiv a[data-swhglnk="true"]', 'click');    };</script>

But to be honest, personally I just hate all this automatically generated scripts and simply never use any Ajax.* helpers stuff as well as activating AJAX on the WebGrid. I prefer to unobtrusively AJAXify the elements I want using jQuery which provides me with far greater control over what's happening. This way I would simply have externalized the bunch of automatically generated javascript by the WebGrid helper into a separate js file that I would have included in my View and there wouldn't be any needs of unregistering and cleaning the mess of the duplicate event handlers created by following the standard way of doing things.


A bit late but I had a similar problem and couldn't find any description of it so thought I'd add it here in case it can help somebody.

No matter what I tried the sorting and paging requests were always duplicated. I tried fixes as described here but even before I had done any type of AJAX update I got the duplication.

I put that problem on hold and after failing to style the pagination to my satisfaction I created my own as a partial view. When deleting the old pagination the duplication was no more..... Haven't taken the time to try and figure out why, just happy it is solved.

So I removed this:

        @grid.Pager(mode: WebGridPagerModes.All, firstText: "First", previousText: "Prev", nextText: "Next", lastText: "Last")

As I said, in case it helps someone.


Looks like the paging and sorting links are bound using "on"/"live" event every time the grid is rendered. It could be solved unbinding the events of the elements of the grid before rendering the grid html or on the ajaxUpdateCallback method.

$('#tableDiv').andSelf().unbind();