knockout.jsasp.net-coreknockout-mapping-plugin

Return Json data from POST action in Core/knockout


I am working with the Knockout JavaScript library in .NET Core. I have the following POST action that successfully receives and handles the Json data from my view. What I cannot get to work is the return to the client:

1) Ideally I want it to return the updated back to the view. However there seems to be a fault with this .NET Core which means the mapping does not work. None of the following work:

        return Json(JsonConvert.SerializeObject(salesOrderViewModel));
        return Json(salesOrderViewModel);
        return Json( new { salesOrderViewModel });

2) But no other return seems to have any effect either. For example:

        //return NotFound();
        //return RedirectToAction("Index");
        //return View("Index");
        //return DoSomething();
    }

    private IActionResult DoSomething()
    {
        return RedirectToAction("Index", "Bird");
    }

Below I have pasted the View, the client side viewmodel, and the full controller action. Can anyone give me any insight into why I cannot return anything from my controller action?

View:

@model Birder2.ViewModels.SalesOrderViewModel
@using Newtonsoft.Json
@{
    ViewBag.Title = "Sales Order Details";
}
@{
string data = JsonConvert.SerializeObject(Model);
}
@section scripts{
<script src="~/js/knockout-3.4.2.js"></script>
<script src="~/js/knockout.mapping-latest.js"></script>
<script src="~/js/salesorderviewmodel.js"></script>
<script type="text/javascript">
    var salesOrderViewModel = new SalesOrderViewModel(@Html.Raw(data));
    ko.applyBindings(salesOrderViewModel);
</script>
}
<p data-bind="text: MessageToClient"></p>
<div>
    <div>
        <label>Customer Name:</label>
        <input data-bind="value: CustomerName" />
    </div>
       <div>
        <label>P.O. Number:</label>
        <input data-bind="value: PONumber" />
   </div>
</div>
<p><button data-bind="click: save">Save</button></p>

The client-side view model:

SalesOrderViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);

    self.save = function () {
        $.ajax({
            url: "/SalesOrders/Save/",
            type: "POST",
            data: ko.toJSON(self),
            headers:
            {
                "content-type": "application/json; charset=utf-8"
            },
            success: function (data) {
                if (data.salesOrderViewModel)
                    ko.mapping.fromJS(data.salesOrderViewModel, {}, self);
            },
        });
    };
};

The full controller action is here:

    //[HttpPost]
    //public JsonResult Save([FromBody]SalesOrderViewModel salesOrderViewModel)
    [HttpPost]
    public IActionResult Save([FromBody]SalesOrderViewModel salesOrderViewModel)
    { 
        SalesOrder salesOrder = new SalesOrder();
        salesOrder.CustomerName = salesOrderViewModel.CustomerName;
        salesOrder.PONumber = salesOrderViewModel.PONumber;

        _context.SalesOrders.Add(salesOrder);
        _context.SaveChanges();

        salesOrderViewModel.MessageToClient = string.Format("{0}’s sales order has been added to the database.", salesOrder.CustomerName);

        return Json(JsonConvert.SerializeObject(salesOrderViewModel));
        //return Json(salesOrderViewModel);
        //return Json( new { salesOrderViewModel });

        //return NotFound();
        //return RedirectToAction("Index");
        //return View("Index");
        //return DoSomething();
    }

The data are successfully bound and the database is updated). Nothing is returned to the client.


Solution

  • Made changes to View such that we bind knockout properly and also use proper objects in success method.