nickornotto
nickornotto

Reputation: 2156

Knockout viewmodel passed to action coming empty

I have a controller action where I'm trying to post a model from knockout:

    [HttpPost]
    public void AddItems(MyViewModel model)
    {
        [...]
    }

knockout action:

self.AddItems = function (data, event) {
    var url = "/MyController/AddItems";
    var target = event.target || event.srcElement;
    var model = ko.toJSON(self);
    $.post(url,
            model,
            function (result) {

            })
        .success(function () { console.log("AddItems second success"); })
        .error(function () { console.log("AddItems error"); })
        .complete(function () { console.log("AddItems complete"); });

    // this doesn't work either
    //var model2 = ko.toJSON({ model: self });
    //$.ajax(url, {
    //    data: model,
    //    type: "post",
    //    async: false,
    //    contentType: "application/json",
    //    success: function (data) {
    //        console.log("AddItems second success");
    //    },
    //    error: function (xmlHttpRequest, textStatus, errorThrown) {
    //        console.log("AddItems error");
    //    }
    //});
}

I have commented out another post action which I tried as well - this one doesn't reach the controller action at all returning a 500 error in js console.

The model:

public class MyViewModel
{
    public int Id { get; set; }

    public string Ref { get; set; }

    public List<ItemViewModel> Items { get; set; }

    public decimal PriceTotal { get; set; }
}

The model which gets posted to action has the correct structure but all properties are either empty or null.

How to pass a knockout viewmodel to the action with correct object data?

***** EDIT *****

I think the action doesn't get the json model.

Because when I pass a hand written raw object model:

var model4 = {
  "Ref": "sgsgsasg",
  "Id": 1,
  "PriceTotal": 382
}

it gets to the action nicely and with correct values.

While the knockout passes json and then the action cannot convert it to the mvc model.

Upvotes: 0

Views: 246

Answers (2)

tyler_mitchell
tyler_mitchell

Reputation: 1747

You haven't passed the parameter your url is expecting, hence the 500.

self.AddItems = function (data, event) {
    var url = "/MyController/AddItems";
    var target = event.target || event.srcElement;
    $.ajax(url , {
       type: "POST",
       cache: false,
       data: { model: ko.toJSON(self) }
    }).done(function () {
       console.log("AddItems second success");
    }).fail(function (jqXHR, textStatus, errorThrown) {
       console.log("AddItems complete");
    });
}

Controller

[HttpPost]
public void AddItems(string model)
{
    var audit = InsertAudit();
    try
    {
        MyViewModel data = JsonConvert.DeserializeObject<MyViewModel>(model);
        //Logic here
    }
    catch (Exception ex)
    {
         FailAudit(audit.ID, ex.ToString());
    }
}

Upvotes: 0

Tomalak
Tomalak

Reputation: 338148

I am pretty sure you are only missing a content type header.

By default jQuery posts data as application/x-www-form-urlencoded. You want application/json. jQuery $.ajax() lets you configure the content type:

self.AddItems = function () {
    return $.ajax({
        url: "/MyController/AddItems",
        data: ko.toJSON(self),
        contentType: "application/json"
    })
    .done(function () { console.log("AddItems success"); })
    .fail(function () { console.log("AddItems error"); })
    .always(function () { console.log("AddItems complete"); });
}

Side note: Returning the request from the function enables you to attach more behavior to it elsewhere:

self.something = function () {
    // do some work on the viewmodel
    self.AddItems().done(function () {
        // we are done
    });
}

Upvotes: 1

Related Questions