4

I was using MVC table to initially display the data to the user but because the data was quite large and started throwing storage out of memory exception, i decided to switch to DataTables. The data is displayed fine but on the postback, no data is coming over to the HTTPPost action method. I understand that MVC View had hidden views to store the values and during the postback they bind the model but how will we replicate this behaviour with a datatable?

thank you

@model IList<ViewModels.ReferralViewModel>@model IList<ViewModels.ReferralViewModel>

@{
    Layout = "";
}

@if (Model != null)
{
    <script src="~/Scripts/DataTables/jquery.dataTables.min.js" type="text/javascript"></script>
    <script src="~/Scripts/DataTables/dataTables.bootstrap.js" type="text/javascript"></script>

    <link href="~/Content/DataTables/css/dataTables.bootstrap.css" />
    <script type="text/javascript">

        var editor;
        $('#example').DataTable({
            "serverSide": true,
            "processing": true,

            "order": [[1, 'asc']],
            "ajax": {
                "url": "/SMS/ReferralDetailsTest",
                "type": "POST",
                "dataType": "json"
            },
            'columnDefs': [{
                'targets': 0,
                'searchable': false,
                'orderable': false,
                'className': 'dt-body-center',
                'render': function (data, type, full, meta) {
                    return '<input type="checkbox" name="IsSelected[]">';
                }
            },
                {
                    'targets': 17,
                    'data': null,
                    'defaultContent': "<input type=\"text\" size=\"100\" style = \"width: 95px; padding: 6px 2px 6px 2px\" >"
                },
                {
                    'targets': 19,
                    'data': null,
                    'defaultContent': "<input type=\"button\" value=\"SMS\" class=\"btn btn - primary\" onclick=\"return $('#sendSMS').click();\" />"
                }
            ],
            "columns": [
                {
                    "data": null,
                    "defaultContent": '',
                    "className": 'select-checkbox',
                    "orderable": false,
                    "title": "Select All"
                },
                { "title": "Referral Id", "data": "ReferralId", "autoWidth": true },
                { "title": "First Name", "data": "patient.PatientFirstName", "autoWidth": true },
                { "title": "Last Name", "data": "patient.PatientLastName", "autoWidth": true },
                { "title": "Referral Date", "data": "ReferralDate", "autoWidth": true },
                { "title": "Referral Priority", "data": "ReferralPriority", "autoWidth": true },
                { "title": "Referral HospCode", "data": "ReferralHospCode", "autoWidth": true },
                { "title": "Referral Specialty Code", "data": "ReferralSpecialtyCode", "autoWidth": true },
                { "title": "Referral Specialty Name", "data": "ReferralSpecialtyName", "autoWidth": true },
                { "title": "Referral Clinic Code", "data": "ReferralClinicCode", "autoWidth": true },
                { "title": "Referral Clinic Description", "data": "ReferralClinicDescription", "autoWidth": true },
                { "title": "Last Booked Clinic Category Code", "data": "LastBookedClinicCategoryCode", "autoWidth": true },
                { "title": "Last Booked Clinic Category", "data": "LastBookedClinicCategory", "autoWidth": true },
                { "title": "Last Booked Clinic Code", "data": "LastBookedClinicCode", "autoWidth": true },
                { "title": "Last Booked Clinic Description", "data": "LastBookedClinicDescription", "autoWidth": true },
                { "title": "Mobile No", "data": "patient.MobileNumber", "autoWidth": true },
                { "title": "Overwrite Mobile No", "data": null },
                { "title": "Status", "data": "Status", "autoWidth": true }
            ],

            "select": {
                "style": 'os',
                "selector": 'td:first-child'
            }
        });
    </script>


    <div class="form-group">
        &nbsp;
    </div>
    <div>
        <ul class="nav nav-tabs" role="tablist" id="DetailsTab">
            <li role="presentation" class="active"><a href="#Referral" aria-controls="Referral" role="tab" data-toggle="tab" class="tbs">Referrals</a></li>
            <li role="presentation"><a href="#Responses" aria-controls="Response" role="tab" data-toggle="tab" class="tbs">Responses</a></li>

        </ul>
        <div class="tab-content">

            <div role="tabpanel" class="tab-pane active" id="Referral">
                <br />


            </div>

            <div>
                <table class="table table-striped" id="example"></table>


            </div>
        </div>
    </div>
}

--Code for post method--

      $('#sendSMS').click(function () {
     var formData = $('#sendSMSForm').serialize();
                    $.ajax({
                        type: "POST",
                        url: "/SMS/SendSMSForClients",
                        data: formData, //if you need to post Model data, use this
                        success: function (result) {
                            $("#partial").html("");
                            $("#partial").html(result);

                            searchReferrals(referralSpecialty, referralClinicName, referralClinicCode, referralPriority, referralStartDate, referralEndDate);
                            $('.nav-tabs a[href="#patientsReferral"]').tab('show');
                            $('.tab-pane a[href="#patientsReferral"]').tab('show');
                            $("#loading").hide();
                        },
                         error: function (jqXHR, textStatus, errorThrown) {
                            $("#partial").html("");
                            $('#partial').html('<p>status code: ' + jqXHR.status + '</p><p>errorThrown: ' + errorThrown + '</p><p>jqXHR.responseText:</p><div>' + jqXHR.responseText + '</div>');
                            console.log('jqXHR:');
                            console.log(jqXHR);
                            console.log('textStatus:');
                            console.log(textStatus);
                            console.log('errorThrown:');
                             console.log(errorThrown);

                        },
                    });

}

Baahubali
  • 4,604
  • 6
  • 33
  • 72
  • as you are rendering a list in the data table , you need to render each input with an Index - see this question to POST a list of values to the Controller (https://stackoverflow.com/questions/27925865/post-form-mvc-with-list-of-list) – Dawood Awan Aug 06 '19 at 08:29
  • second point is we don't see the Form element - look into @Html.BeginForm() - MVC model binder will bind data which is inside a Form element (also no submit button - how do you POST data to server)? – Dawood Awan Aug 06 '19 at 08:30
  • Hi @Baahubali, can you please include your code for the Post Action method? – Canica Aug 06 '19 at 12:55

1 Answers1

2

I think you are perhaps still thinking about Webforms and it's ViewState. With webforms you load data to an object, that data is then stored in a hidden input and send back to the server on a form post (PostBack).

But MVC does not retain the state. So even after a form is posted you will need to reload all the data again from the database and send it to the model. Otherwise the object will be null.

WEBFORMS

protected void Page_Load(object sender, EventArgs e)
{
    //load the data from a source
    DataTable dt = LoadFromDB();

    if (!IsPostBack)
    {
        //bind data to an object
        GridView1.DataSource = dt;
        GridView1.DataBind();
    }
}

protected void Button1_Click(object sender, EventArgs e)
{
    //do stuff here on form post (PostBack)

    //you don't have to rebind data to GridView1 here since the data is retained in ViewState 
}

MVC

public ActionResult Index()
{
    var model = new MyModel();

    //load the data from a source
    model.dt = LoadFromDB();

    return View(model);
}

[HttpPost]
public ActionResult Index(MyModel model)
{
    //do stuff here on form post

    //load the data again since it is not retained in a ViewSate
    //if you do not then dt will be null
    model.dt = LoadFromDB();

    return View(model);
}

On a side note, if your dataset is so large it throws a memory exception, you might want to thing about some form of paging instead of dumping all the data to the client.

VDWWD
  • 35,079
  • 22
  • 62
  • 79
  • may be i am not clear but before you call LoadFromDB() function, you are receiving the MyModel object from the Post or submit which is what i am after and is always null. – Baahubali Aug 02 '19 at 23:21
  • That is what i'm trying to say. It is null because it is not send with a PostBack. Only input controls that are bound to the properties are send to the server, usually like this `@Html.TextBoxFor(model => model.Email)`. Thaty is why you need to load the data again. – VDWWD Aug 03 '19 at 08:30
  • yes but then in the data tables, i have a input type of checkbox and a textbox, and i need these two fields posted back. however, they are all coming as null. – Baahubali Aug 04 '19 at 07:18
  • If you create those inputs yourself I guess you can get the values with `Request.Form` – VDWWD Aug 05 '19 at 06:23
  • if you see my question, i have already provided the code which contains the input elements. during the postback there is no data including in the request.form. – Baahubali Aug 05 '19 at 07:15