ajaxasp.net-core-mvcjquery-ui-sortableasp.net-core-6.0

ASP.NET Core MVC - VIew is not updated correctly - Ajax?


I have an ASP.NET Core 6 MVC application.

On one page I have a table; I want to support drag'n'drop for its rows. Afterwards the User is able to click on "Submit" and make the changes permanent.

The changes are sent to the controller and persisted to the database, however when I redirect to the GET to show the page again, a part of it is wrong!

@model MyViewModel

<form>
    @Html.HiddenFor(y=>y.Id)
    <table id="orderTable" class="table">
    <thead>
        <tr>
            <th>
                Name
            </th>
            <th>
              Order
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var data in Model.Data)
        {
            <tr id='@data.Id'>
                <td>@data.Name</td>
                <td>@data.Order</td>
            </tr>
        }
    </tbody>
</table>

<div class="form-group">
    <input type="submit" value="Save" id="SaveOrderButton" />

</div>
</form>

 <script>
     $(document).ready(function() {
        $('#orderTable tbody').sortable();
        $("#SaveOrderButton").click(function(e) {
           e.preventDefault();                  
                var newOrder =  $('#orderTable tbody').sortable('toArray');
                $.ajax({
                    url: '/Controller/Update',
                    type: 'POST',
                    data: { rowOrder: newOrder, id: @Html.Raw(Model.Id) },
                    success: function(response) {
                        console.log(response);        
                      },
                        error: function(xhr,status, error){
                             console.log("An error occurred: " + xhr.responseText);
                        }
                    });
            });
        });
    </script>

Backend:

[HttpGet]
public async Task<IActionResult> Order(int id)
{
    var data= await context.Data
                           .AsNoTracking()
                           .Where(x => x.Id== id)
                           .ToListAsync();

    data = data.OrderByDescending(y => y.Order.HasValue)
               .ThenBy(y => y.Order)
               .ToList();

    var viewModel = new MyViewModel()
                        {
                            Data = data,
                            Id = id,
                        };

    ModelState.Clear();   // found on SO, but does not change anything

    return View(viewModel);
}

[HttpPost]
public async Task<IActionResult> Update(int[] rowOrder, int id)
{
    var data= await context.Data
                           .Where(y => rowOrder.Contains(y.Id))
                           .ToListAsync();

    for (int i = 0; i < rowOrder.Count(); i++)
    {
        data.First(y => y.Id == rowOrder[i]).Order = i;
    }

    try
    {
        context.UpdateRange(data);
        await context.SaveChangesAsync();
    }
    catch (Exception ex)
    {
        logger.LogError("..........");
        return Json(500, "Could not update new order.");
    }

    return RedirectToAction(nameof(Controller.Order), new { id= id});
}

Okay, so I go the the view with GET and everything is shown correctly, then I change something and click on "Save". Everything in the POST will be correctly done. The database is updated.

I then redirect to the GET method again, there everything is loaded correctly from the database and in the correct order.

Then I set a breakpoint in the View and there the stuff in the for is correct too.

However, when I look in the browser, the "Order" column is wrong. The table still shows the data how it looked like after I reordered it and before I clicked on "Save".

What is happening here? Is the sortable lib using a cache in the background that I have to invalidate?

I don't use a cache anywhere in my project, btw.

Also, when I go to the console after a POST, the whole website's HTML is in there.

When I now reload the page with the GET, everything is shown how it is supposed to be.

Has it something to do with Ajax? I have already removed the success and error events, which doesn't change anything.


Solution

  • Has it something to do with Ajax? I have already removed the success and error events, which doesn't change anything.

    Yes, the issue relates the Ajax method.

    As we all known, when we use Ajax to update the part of view page, after calling the action method, it will return the response result to the success function, then in the success function, we get the updated data from the response, and then dynamic populate the table to update the page and achieve the part of page refresh behaviors.

    So, in your scenario, you can try to use the following methods to display the updated data.

    Method 1:

    In the Update Action method, return the updated data as result, instead of redirect to another action result. Then, in the Ajax success function, get the data from response, then clear the table content first and re-populate it using the response data.

    Method 2:

    In the Ajax success function, use location.reload(); method to reload current page, or use window.location.href to refresh the current page.