Search code examples
asp.net-mvcdatatables

Use jQuery datatables server-side processing with mvc. Serialize criteria form and add this parameter to $ajax.post method


I am using mvc and jquery datatables, with serve side processing.

I have created two Class Model: the first jQueryParamModel, to pass dataTables parameters to action controller

public class JQueryDataTableParamModel
{
    /// <summary>
    /// Request sequence number sent by DataTable, same value must be returned in response
    /// </summary>       
    public string sEcho{ get; set; }

    /// <summary>
    /// Text used for filtering
    /// </summary>
    public string sSearch{ get; set; }

    /// <summary>
    /// Number of records that should be shown in table
    /// </summary>
    public int iDisplayLength{ get; set; }

    /// <summary>
    /// First record that should be shown(used for paging)
    /// </summary>
    public int iDisplayStart{ get; set; }

    /// <summary>
    /// Number of columns in table
    /// </summary>
    public int iColumns{ get; set; }

    /// <summary>
    /// Number of columns that are used in sorting
    /// </summary>
    public int iSortingCols{ get; set; }

    /// <summary>
    /// Comma separated list of column names
    /// </summary>
    public string sColumns{ get; set; }

}

the second rapresent two custom search criteria

 public class Home2Model
    {
        public CriteriaModel SearchCriteria1 { get; set; }
        public CriteriaModel SearchCriteria2 { get; set; }
    }

After i have created a strongly typed view with Home2Model, named index.cshtml

 @model GenericSearch.UI.Models.Home2Model

<link href="@Url.Content("~/Content/dataTables/demo_table.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery.dataTables.min.js")" type="text/javascript"></script>
<script>

  

  $(document).ready(function () {
        var oTable = $('#myDataTable').dataTable({
            "bServerSide": true,
            "sAjaxSource": "/Home2/AjaxHandler",
            "bProcessing": false,
            "sServerMethod": "POST",
            "fnServerData": function (sSource, aoData, fnCallback) {

                aoData.push({ "name": "hm", "value": $("myForm").serialize() });

                $.ajax({
                    "dataType": 'json',
                    "type": "POST",
                    "url": sSource,
                    "data": aoData,
                    "success": fnCallback
                })
            }
        });
    });


 </script>

    <h1>Search</h1>
<br />
@using (Html.BeginForm("Index", "Home2", FormMethod.Post, new { id="myForm"}))
{
   

 <div >
        @Html.EditorFor(m => m.SearchCriteria1)
        @Html.EditorFor(m => m.SearchCriteria2)
        <br />
        <input type="submit" name="default" value="Filter" />
        <br /><br />
        <table id="myDataTable" class="display">
            <thead>
                <tr>
                    <th>a</th>
                    <th>b</th>
                    <th>c</th>
                    <th>d</th>
                    <th>e</th>
                    <th>f</th>
                </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>

}

I have created a contoller action that recives an input in these parameters:

[HttpPost]
    public ActionResult AjaxHandler(JQueryDataTableParamModel param,Home2Model hm)
    {
        return new EmptyResult();
    }

JQueryDataTableParamModel bind works properly, but hm param isn't valorized (null). the mvc binding doesn't work correctly.

Can anyone help me?


Solution

  • $("myForm").serialize() won't cut the mustard here. First $("myForm") is a selector that is looking for a tag <myForm> which I guess doesn't exist. You are probably looking for a <form> tag with id="myForm" in which case the correct selector would have been $('#myForm').

    This being said, the .serialize() method will simply turn the form input fields into application/x-www-form-urlencoded payload. But when you pass that to the hm parameter it obviously won't work. You need the entire request payload to be application/x-www-form-urlencoded if you want the model binder to be able to deserialize it properly.

    So let me suggest you the following extension:

    $.fn.serializeObject = function () {
        var o = {};
        var a = this.serializeArray();
        $.each(a, function () {
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        });
        return o;
    };
    

    Once you have declared it you can simply do that:

    $('#myDataTable').dataTable({
        "bServerSide": true,
        "sAjaxSource": "/Home/AjaxHandler",
        "bProcessing": false,
        "sServerMethod": "POST",
        "fnServerData": function (sSource, aoData, fnCallback) {
            var formData = $('#myForm').serializeObject();
            for (var key in formData) {
                if (formData.hasOwnProperty(key)) {
                    aoData.push({
                        name: key,
                        value: formData[key]
                    });
                }
            }
    
            $.ajax({
                "dataType": 'json',
                "type": "POST",
                "url": sSource,
                "data": aoData,
                "success": fnCallback
            })
        }
    });
    

    and the 2 arguments of your AjaxHandler action will now be correctly bound. Simply inspect the Network tab in your javascript debugging tool to see the difference between the 2 payloads and you will understand why your code didn't work.