-1

I want to select multiple rows and then click on a button to approve/deny those rows. I have successfully updated the rows I want to approve in db. But when ajax callback, I ran table.draw() and it doesn't show the saved result. I don't know how to take the saved result and refresh back to the DataTable.

Also I am new to MVC and jQuery, I was fumbling around to make it barely work. Could you help point out what do I need to improve/fix to make this work better?

Here are my codes:

View (table part):

<table id="myDataTable" class="display">
            <thead>
                <tr>
                    <th>Clearance Name</th>
                    <th>Approved</th>
                    <th>Approver</th>
                    <th>DateTime</th>
                    <th>Deny Reason</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in Model.Request.RequestClearances)
                {
                    <tr id="@item.RequestClearanceID">
                        <td>@item.Clearance.ClearanceName</td>
                        <td>@item.IsApproved</td>
                        <td>@item.ApprovedUser</td>
                        <td>@item.ModifiedDate</td>
                        <td>@item.DenialReason</td>
                    </tr>
                }
            </tbody>
</table>
<div><input type="button" id="btnApprove" value="Approve" /><input type="button" id="btnDeny" value="Deny" /></div>

View (jQuery part):

<script>
    $(function () {
        var table = $("#myDataTable").DataTable();

        $("#myDataTable tbody").on('click', 'tr', function () {
            var tr = $(this).closest("tr");
            var rowText = tr.children("td").text();

            if (! rowText.match("True") ) {
                $(this).toggleClass('selected');
            }

        });

        $("#btnApprove").click(function () {
            var idArray = $.map(table.rows('.selected').ids(), function (item) {
                return item;
            });

            $.ajax({
                type: "POST",
                url: '@Url.Action("UpdateApproveDeny")',
                cache: false,
                dataType: 'json',
                contentType: 'application/json; charset=utf-8',
                data: JSON.stringify({ requestClearanceIDs: idArray, isApproved: "true" }),
                success: function () {
                    table.draw();
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    $("#message").text(JSON.stringify(jqXHR).toString());
                    alert("AJAX error: " + textStatus + ' : ' + errorThrown);
                }
            });
        });
    });
</script>

Control:

public JsonResult UpdateApproveDeny(string[] requestClearanceIDs, string isApproved)
        {
            if (requestClearanceIDs == null) return Json("fail",JsonRequestBehavior.AllowGet);
            int? requestID = 0;
            foreach (var requestClearanceID in requestClearanceIDs)
            {
                int id = 0;
                Int32.TryParse(requestClearanceID, out id);              
                requestID = rc.RequestID;
                rc.IsApproved = Convert.ToBoolean(isApproved);
                rc.ModifiedBy = User.Identity.Name;
                rc.ModifiedDate = DateTime.Now;
                rc.ApprovedUser = User.Identity.Name;
                db.SaveChanges();
            }

            return Json("success",JsonRequestBehavior.AllowGet);
        }
Meidi
  • 562
  • 1
  • 8
  • 28
  • Since you're using DataTables in a static fashion you'll need to [replace your table content in the AJAX callback](http://stackoverflow.com/questions/19392212/how-to-use-jquery-or-ajax-to-update-razor-partial-view-in-c-asp-net-for-a-mvc-p/19410973#19410973) then rebind `$("#myDataTable").DataTable()` because the original table has been replaced. I haven't used DataTables before but it appears to have [built-in AJAX support](http://datatables.net/manual/ajax) -- Which will require you to provide an AJAX action that returns your table data in JSON format. – Jasen Dec 24 '15 at 19:10

1 Answers1

1

Since you're using DataTables in a static fashion you'll need to replace your table content in the AJAX callback then rebind $("#myDataTable").DataTable() because the original table will be replaced.

Add a partial view

Adjust your main view to fill your table with a partial view.

<div id="tableData">
    @Html.Partial("_ClearancesTable", Model.Request.RequestClearances)
</div>
<div>
    <input type="button" id="btnApprove" value="Approve" />
    <input type="button" id="btnDeny" value="Deny" />
</div>

_ClearancesTable.cshtml

@model IEnumerable<RequestClearances>

<table id="myDataTable" class="display">
    @foreach (var item in Model)
    {
        ...
    }
</table>

You can either make a second AJAX call to retrieve new table data or alter your first response to return the new data.

Replace the JSON result to take advantage of the partial view and to reduce this to one server call.

public ActionResult UpdateApproveDeny(string[] requestClearanceIDs, string isApproved)
{
    ...
    db.SaveChanges();
    var clearances = db.GetClarances();
    return PartialView("_ClearancesTable", clearances);
}

Replace and Rebind

 success: function(partialResult) {
     $("#tableData").html(partialResult)
     $("#myDataTable").DataTable();
 }
Jasen
  • 14,030
  • 3
  • 51
  • 68
  • I am almost there. I got an error "AjaxError:Syntax Error:parseerror:Inavlid character" and the status return was 200. Do you happen to know why? thank you! – Meidi Dec 24 '15 at 21:42
  • 1
    If you changed the response to a partial view the request options will need to change also. Just drop the `dataType: "json"` option and let jQuery automatically figure it out ("html" in this case). – Jasen Dec 24 '15 at 23:08
  • Hi Jasen, after Rebind the table, the table was refreshed however I was not able to select other rows unless I hit F5 to refresh. Could you help? thank you! – Meidi Jan 13 '16 at 16:32
  • You'll need to use a [delegate](http://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) and bind the click selection to a static parent. `#tableData` would make a good choice. – Jasen Jan 13 '16 at 17:53
  • I don't quite understand how this works. So I changed my Approve Button click event to $("#btnApprove").on("click","#tableData",function(){....}); wasn't working. – Meidi Jan 13 '16 at 21:21
  • If you're moving the selection handler it would be `$("#tableData").on("click", "#myDataTable tbody tr", function(e) { ... })`. Where `#tableData` is the static parent element. – Jasen Jan 13 '16 at 22:15
  • Hi Jasen, after using a delegate I was able to select other rows. However, selecting other rows and click on approve button again end up changing the previous selected rows. I was thinking after approve/deny button clicking, the selected rows are cached. Should I use toggleClass("selected") after ajax succeeded? I also tried to search something to clear cache but wasn't successful. Thank you so much. – Meidi Jan 14 '16 at 18:32
  • I assign my global data table variable and it worked. table = $("#myDataTable").DataTable(); – Meidi Jan 14 '16 at 18:40
  • If you still have problems I think it's time for a new question. This morphing into a different problem and more people would be able to see it and offer help on a new post. – Jasen Jan 14 '16 at 19:14