0

My model contains two lists of the Order entity type, but differentiating only by the value of the Status property. When Orders are created, the Status property is automatically set to In Progress and in the AdminOrders view, placed in the Orders In Progress table. The AdminOrders view has two tables: Orders In Progress table and Orders Dispatched table which will be filled by the Model's lists respectively.

When the Status value of new orders is changed from the drop down list to dispatched, and when the update button in the view is clicked, the Ajax post request should be triggered by the JavaScript click event - passing the list of all updated orders in the view to the Ajax post method. However, nothing seems to be happening when I run the application.

At each time, multiple Order objects can have their Status' changed which is why I thought a simple Ajax update post request would be suitable.

Here's the Model class:

public class AdminOrdersViewModel
{
    public List<Order> OrdersInProgress { get; set; }
    public List<Order> OrdersDespatched { get; set; }
    public List<Status> OrderStatuses { get; set; }
}

This is the controller GET action for the AdminOrders view:

[HttpGet]
[Authorize(Roles = "Admin")]
public ActionResult AdminOrders()
{
    var inProgressOrders = db.Orders.Where(o => o.Status == "In Progress").ToList();
    var despatchedOrders = db.Orders.Where(o => o.Status == "Despatched").ToList();
    var statuses = new List<Status> {
        new Status { StatusName = "In Progress" },
        new Status {StatusName = "Despatched" }
    };

    return View(new AdminOrdersViewModel { OrdersInProgress = inProgressOrders, OrdersDespatched = despatchedOrders, OrderStatuses = statuses });
} 

My post ajax method is here:

[HttpPost]
public ActionResult UpdateOrders(List<UpdatedOrder> UpdatedOrdersList)
{

    foreach (var item in UpdatedOrdersList)
    {
        db.Entry(item).State = EntityState.Modified;
        db.SaveChangesAsync();
    }

    return View("AdminOrders");
}

It should update every order that has had it's Status property changed and then update the view page.

This is the class for UpdatedOrder:

public class UpdatedOrder
{
    public int id { get; set; }
    public string newstatus { get; set; }
}

As you can see, there is a list which is being passed. This list is collected from the JavaScript method in the view:

<script type="text/javascript">
    $(document).ready(function () {

        $("#Order-Update-Button").click(function () {

            var ListOfUpdatedOrders = []

            @{

                foreach (var item in Model.OrdersInProgress)
                {
                    @:ListOfUpdatedOrders.push({ id: "@item.OrderId", newStatus: document.getElementById("@item.OrderId") });

                }

            }

            var dataJson = JSON.stringify({
                "UpdatedOrdersList": ListOfUpdatedOrders
            });

            alert("running");
            // Perform the ajax post
            $.ajax({
                contentType: "application/json; charset=utf-8",
                type: "POST",
                url: "@Url.Action("UpdateOrders", "Manage")",
                data: dataJson,
                dataType: "json",
                success: function (data) {
                    alert(data);
                },
                error: function () {
                    alert("an error has occured!!!");
                }
            });

        });
    });
</script>

The ListOfUpdatedOrders list will put together objects consisting of Order Id and Status attributes. The new Status is being extracted through getElementById and the id is set to the OrderId of each order object displayed in the view.

The full view page code is the following:

@model ValueVille.Models.AdminOrdersViewModel

@{
    ViewBag.Title = "Orders";

}
<script src="/Scripts/jquery-3.1.1.min.js"
        type="text/javascript"></script>

<script type="text/javascript">
    $(document).ready(function () {

        $("#Order-Update-Button").click(function () {

            var ListOfUpdatedOrders = []

            @{

                foreach (var item in Model.OrdersInProgress)
                {
                    @:ListOfUpdatedOrders.push({ id: "@item.OrderId", newStatus: document.getElementById("@item.OrderId") });

                }

            }

            var dataJson = JSON.stringify({
                "UpdatedOrdersList": ListOfUpdatedOrders
            });

            alert("running");
            // Perform the ajax post
            $.ajax({
                contentType: "application/json; charset=utf-8",
                type: "POST",
                url: "@Url.Action("UpdateOrders", "Manage")",
                data: dataJson,
                dataType: "json",
                success: function (data) {
                    alert(data);
                },
                error: function () {
                    alert("an error has occured!!!");
                }
            });

        });
    });
</script>

<div class="main-content-container">

    <h1>New Orders In Progress<span id="update-order-test"></span></h1>

        @Html.AntiForgeryToken()

        <table class="panel panel-default table cart-table">
            <tr>
                <th>
                    Order ID
                </th>
                <th>
                    Total
                </th>
                <th>
                    Date
                </th>
                <th>
                    Status
                </th>
            </tr>
            @foreach (var item in Model.OrdersInProgress)
            {
                <tr>
                    <td>
                        <a href="@Url.Action("OrderDetails", "Home", new { id = item.OrderId })">
                            @item.OrderId
                            @Html.HiddenFor(x => item.OrderId)
                        </a>
                    </td>
                    <td>
                        £@item.Total
                        @Html.HiddenFor(x => item.Total)
                    </td>
                    <td>
                        @item.OrderDate
                        @Html.HiddenFor(x => item.OrderDate)
                    </td>
                    <td>
                        @Html.DropDownListFor(m => item.Status, new SelectList(Model.OrderStatuses, "StatusId", "StatusName"), new { @id=item.OrderId })
                    </td>
                </tr>
                            }

        </table>

        <h1>Orders Despatched</h1>

        <table class="panel panel-default table cart-table">
            <tr>
                <th>
                    Order ID
                </th>
                <th>
                    Total
                </th>
                <th>
                    Date
                </th>
                <th>
                    Status
                </th>
            </tr>
            @foreach (var item in Model.OrdersDespatched)
            {
                <tr>
                    <td>
                        <a href="@Url.Action("OrderDetails", "Home", new { id = item.OrderId })">
                            @item.OrderId
                            @Html.HiddenFor(x => item.OrderId)
                        </a>
                    </td>
                    <td>
                        £@item.Total
                        @Html.HiddenFor(x => item.Total)
                    </td>
                    <td>
                        @item.OrderDate
                        @Html.HiddenFor(x => item.OrderDate)
                    </td>
                    <td>
                        @Html.DropDownListFor(m => item.Status, new SelectList(Model.OrderStatuses, "Id", "StatusName"))
                    </td>
                </tr>
                            }

        </table>

        <div class="panel-body form-group">
            <div class="col-md-offset-2 col-md-10">
                <input id="Order-Update-Button" type="submit" value="Update" class="btn btn-success" />
            </div>
        </div>

</div>

Chrome Console Error:

AdminOrders:60 Uncaught TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>)
    at HTMLInputElement.<anonymous> (AdminOrders:60)
    at HTMLInputElement.dispatch (jquery-3.1.1.js:5201)
    at HTMLInputElement.elemData.handle (jquery-3.1.1.js:5009)

naz786
  • 485
  • 1
  • 5
  • 22
  • 1
    There are multiple problems with your code. You cannot use a `foreach` loop to generate form controls - refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943). If posting an array you need to stringify the data and set `contentType: 'application/json'`. Your `newStatus: document.getElementById(item.OrderId)` makes no sense and does not return the Status because of you invalid html –  Apr 19 '17 at 22:43
  • 1
    But why are you making an ajax call to post this anyway. Create a view model representing what you want that displays all orders with an associated dropdownlist (or just a checkbox if you only have 2 possible Status values - e.g. `bool IsDespatched`) and postback the collection. –  Apr 19 '17 at 22:45

1 Answers1

1

You do not have item.OrderId. You can not get values like this

  for (var item = 0; item < @Model.OrdersInProgress.Count(); item++){
            var UpdatedOrder = { id: item.OrderId, newStatus: 
          document.getElementById(item.OrderId) };
            ListOfUpdatedOrders.push(UpdatedOrder);
  }

it should be

   @foreach (var d in Model.OrdersInProgress)
   {
            @:ListOfUpdatedOrders.push({ id: "@d.OrderId", newstatus: 
                "@d.Status.StatusName" });
   }

   var dataJson = JSON.stringify({
            'UpdatedOrdersList': ListOfUpdatedOrders,
    });

         //Perform the ajax post
        $.ajax({
            contentType: "application/json; charset=utf-8",
            type: "POST",
            url: '@Url.Action("UpdateOrders", "AdminOrders")',
            data: dataJson,
            dataType: "json",
            success: function (data) {
                alert(data);
            },
            error: function () {
                alert("An error has occured!!!");
            }
        });

Update

Change your dropDownlist

 @Html.DropDownListFor(m => item.Status, new SelectList(Model.OrderStatuses, 
 "StatusName", "StatusName", item.Status), new { @id = item.OrderId })

and you should get newStatus like this

newstatus: $("#@item.OrderId").val()
caner
  • 721
  • 5
  • 21