1

I'm having issues refreshing data that has been POSTed using Ajax. The POST is successfully being executed, but the data on the VIEW does not get refreshed with the new data. When I debug, the values from the Ajax POST are successfully being passed to my Search controller. When the controller returns the view model return View(model);, my VIEW is not refreshing the new data. How do I get the new data to show in my VIEW?

Ajax/jQuery

$(document).ready(function () {
$("#typeId, #scorecardId, #dateId").on('change', function () {
        $.ajax({
            url: "/StaffChange/Search",
            type: "POST",
            dataType: "json",
            data: {
                typeSelected: $('#typeId').val(),
                scorecardSelected: $('#scorecardId').val(),
                effectiveDateSelected: $('#dateId').val()
            }
        })
});
});

View

<table class="table table-condensed table-hover table-responsive table-striped">
<tr>
    <th>
        <a href="@Html.GetUrlAndRouteObject(Model.Sort, "change_date")">
            Change Date
            @Html.AddSortArrow(Model.Sort, "change_date")
        </a>
    </th>
    <th>
        @Html.EditorFor(model => model.effectiveDate, new { htmlAttributes = new { @class = "datepicker", @placeholder = "Effective Date", @id = "dateId" } })
    </th>
    <th>
        @Html.DropDownListFor(model => model.type, new SelectList(Model.type), "-Type-", new { @id = "typeId" })
    </th>
    <th>
        @Html.DropDownListFor(model => model.type, new SelectList(Model.scorecard), "-Scorecard-", new { @id = "scorecardId" })
    </th>
</tr>

@foreach (var item in Model.get_staff_changelog_results)
{
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Change_Date)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Effective_Date)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Type)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Scorecard)
            </td>
        </tr>
}

Controller

public ActionResult Search(string sort, string typeSelected, string scorecardSelected, DateTime? effectiveDateSelected)
    {
        //TO DO: Implement MVC way of permissions...
        if (System.Web.HttpContext.Current.Session["ConnectelligenceAdmin"].ToString() != "true")
        {
            return View("AccessDenied");
        }
        //Get sort order for Change Date using BLL
        var staffChangeSort = (String.IsNullOrEmpty(sort)) ? SortOptions.change_date_desc : (SortOptions)Enum.Parse(typeof(SortOptions), sort);

        //Execute sort order for Change Date using BLL
        var sortResults = _changeLogSort.SortStaffChangeLog(staffChangeSort,typeSelected, scorecardSelected, effectiveDateSelected);

        //Get list of dropdown results which is used for filtering
        var dropdownResults = _staffChangeFilter.StaffChangeFilter();

        var model = new Hierarchy_AdjustmentViewModel { get_staff_changelog_results = sortResults.get_staff_changelog_results, Sort = staffChangeSort, type = dropdownResults.type, scorecard = dropdownResults.scorecard};

        return View(model);
    }
GRU119
  • 1,028
  • 1
  • 14
  • 31
  • Wouldn't be easier to return a PartialView with the data? Because with this the AJAX call is never refreshing something you just get the response (_result_) but do nothing with it. – William-H-M Dec 01 '17 at 16:27
  • You understand that one of the points of performing ajax vs a normal submit is that the page does not inheriently transition for an ajax call, right? So if you want the page to change dependent upon the response of an ajax call, you have to do those changes yourself. Otherwise, perhaps it's better to make it a normal form submit so the page reloads and does it automatically. – Taplar Dec 01 '17 at 16:27
  • Possible duplicate of [View not refreshing after AJAX post](https://stackoverflow.com/questions/17742514/view-not-refreshing-after-ajax-post) – William-H-M Dec 01 '17 at 16:31

2 Answers2

1

Because you're not responding to the AJAX call in any way. Add a .done() callback handler to the AJAX call:

$.ajax({
    /*...*/
}).done(function (response) {
    // update the page in here
});

At that point the question becomes... What sort of updates do you plan to do? It looks like you're returning a view from the controller:

return View(model);

So the data you're getting back in the AJAX response is a bunch of raw HTML. If it's a subset of a full page (that is, no additional <head>, <body>, etc. tags) then you could replace an existing container element with the contents of the response:

$('#someContainer').html(response);

However, this tends to be a bit sloppy and can cause other problems. (For example, replacing DOM elements which have handlers attached to them or plugins initialized on them, requiring you to re-think how you approach some things.) Instead, for AJAX calls it's common to return JSON data:

return Json(model);

This returns just the data instead of all the HTML surrounding this. This is useful for a couple of reasons:

  1. It's easier to manipulate if you only want to do small and specific things.
  2. It uses less network bandwidth.
  3. It's just plain silly to return a bunch of HTML that the page already has.

With that data you can then update the specific elements on the page. For example, maybe you want to update the value of an input:

$('#someInput').val(response.SomeProperty);

Or the text of a display element:

$('#someElement').text(response.AnotherProperty);

How you handle the response and what you need to do to your page to "update it" is up to you. The point is that the system doesn't automatically do this for you. You need to handle the AJAX response and write your logic accordingly.

David
  • 208,112
  • 36
  • 198
  • 279
  • Thank you David for your response and quick response. I was resolve my issues using Shyju's answer. Much appreciated. – GRU119 Dec 02 '17 at 19:12
1

You need to use the response you receive from your ajax call. Currently your Search method is returning a view result. What you can do is, if the method is invoked from an xhr call ,you may return a partial view result which has only the markup for table rows (with the new set of data) and in your ajax call's done event, update the DOM (replace the existing table rows with this new markup).

So first create a partial view called _List.cshtml and have the code to render the table rows there

@model Hierarchy_AdjustmentViewModel 
@if(Model.get_staff_changelog_results!=null)
{
    foreach (var item in Model.get_staff_changelog_results)
    {
        <tr>
            <td> @item.Change_Date </td>
            <td> @item.Effective_Date </td>
            <td> @item.Type </td>
            <td> @item.Scorecard </td>
        </tr>
    }
}

You can use the same partial view in your main view as well to reduce duplicate code

Now update your action method to return this partial view when the request was made from ajax code

public ActionResult Search(string sort, string typeSelected)
{
    // Your existing code to get data goes here
    var model = new Hierarchy_AdjustmentViewModel();
    mode.get_staff_changelog_results = sortResults.get_staff_changelog_result;
    if (Request.IsAjaxRequest())
    {
        return PartialView("_List", model);
    }
    return View(model);
}

Now all you have to do is, use this response to update the table. Since you are returning view result (HTML markup), you do not need to specify dataType as json.

$("#typeId, #scorecardId, #dateId").on('change', function () {
    var $tbl = $(this).closest("table");
    $tbl.find("tbody").find("tr:gt(0)").remove();

    $.ajax({
        url: "@Url.Action("Search","StaffChange")",
        type: "POST",
        data: {
            typeSelected: $('#typeId').val(),
            scorecardSelected: $('#scorecardId').val(),
            effectiveDateSelected: $('#dateId').val()
        }
    }).done(function(res) {
        $tbl.find("tbody").append(res);
    }).fail(function(x, a, e) {
        alert(e);
    });
});

Another option is returning the data as a JSON array, and the done handler has to parse it (loop through it) and create markup for each row and append to the table (after clearing existing rows).

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • Thanks Shyju for the response. So i'm working your answer now, but the data still does not seem to be loading. I noticed you have references to "tbody" in your jQuery. I tried adding in the view (starting after the foreach loop), but no luck. – GRU119 Dec 01 '17 at 19:43
  • So what is happening now ? Are you getting the expected result in the `done` event handler ?`$tbl.find("tbody").append(res);` should work with the markup you shared. – Shyju Dec 01 '17 at 21:09
  • @GRU119 Take a look at this working fiddle and compare your code. https://dotnetfiddle.net/lK3jhr – Shyju Dec 01 '17 at 21:24
  • thanks for this demo. very nice of you to do this. I'm working through your demo now. So when I added the similar logic, when I select an item from the dropdown (in my code on my local box), ALL HTML is getting removed. I'm left with a blank window after I select an item. I feel like var $tbl = $(this).closest("table"); $tbl.find("tbody").find("tr:gt(0)").remove(); is removing the wrong table. Still working on it now... – GRU119 Dec 02 '17 at 02:43
  • Also, i noticed you have debug statements in the Ajax call. How do I see those in VS? I'm looking in the output window, but don't seem to see them ex. $("#msg").html("Response from search received"); To answer your question about getting the expected results in the done event handler, I cannot tell at this time. I'm not sure how to debug/output the results in my debugger. Still working on it – GRU119 Dec 02 '17 at 02:46
  • I added that `$("#msg").html("Response from search received")` to give the user(you) an idea when the ajax call started and when it got the response. You can think of it like a progress bar /loading message. Open up your browser dev tools (F12 in chrome) and check your network tab and see you are getting the expected result for the xhr call to `Search`. It should return a 200OK with the partial view result markup in your response. Add console.log/alert in your client side code to do debugging. – Shyju Dec 02 '17 at 14:29
  • I think i'm getting closer. I was able to get some of this code working in my project. So if i'm understanding this correctly, I will be constructing the new table with the new results in my controller method "Search". I need to pass in the Html helpers. The first one I have is...........using (Html.BeginForm("Index", "StaffChange", FormMethod.Post, new { id = "myform" })) { Html.Hidden("sso", item.SSO) Html.Hidden("name", item.Agent_Name) } ...Is it possible to add this in Search method too? – GRU119 Dec 02 '17 at 16:03
  • 1
    I think I have it working. THANK YOU SO MUCH FOR YOUR HELP. YOU ARE AWESOME!! – GRU119 Dec 02 '17 at 16:47