5

I'm trying to do a post of the mapped KnockoutJS model. I can see when debugging it, the JSON is correct. But the server shows that Product is 0 (empty). While it does contain 1 item.

MVC Controller:

[HttpPost]
public ActionResult Test(MyModel model, FormCollection fc)
{
   return RedirectToAction("index");
}

The AJAX submit:

$('#btnSubmit').click(function (event) {
        var theModel = ko.mapping.toJSON(viewModel);
        debugger;
        $.ajax({
            type: 'POST',
            url: "@Url.Action("Test", "Home")",
            data: theModel,
            contentType: 'application/json; charset=utf-8',
            success: function (result) {
                if (!result.success) {
                    //alert(result.error);
                }
                else { }
            }
        });
    });

This is a partial JSON object:

"Products":[{"Id":2,"Name":"bread"}]

What am I doing wrong?

EDIT:

public class MyModel
{
   public int User { get; set; }
   public string Address { get; set; }
   public string ZipCode { get; set; }
   public List<Product> Products { get; set; }

}

public class Product
{
   public int Id { get; set; }
   public string Name { get; set; } 
}
7
  • Could you post MyModel ? Commented Dec 9, 2013 at 16:31
  • we use ko.dataFor stackoverflow.com/questions/14968565/… Commented Dec 9, 2013 at 16:35
  • @JoffreyKern, MyModel added Commented Dec 9, 2013 at 16:56
  • As we can see your Product has no notion of TypeId. It has a property of Id. But, the JSON you have posted contains a TypeId Commented Dec 9, 2013 at 17:13
  • Try fixing you javascirpt model that represents Product. Replace TypeId with Id or the vice versa. Commented Dec 9, 2013 at 17:20

2 Answers 2

3

Here is a full working tested example (sending a model back from the controller and posting):

Controller

public ActionResult Test()
{
    var model = new MyModel();
    model.Products = new List<Product> { new Product { Id = 2, Name = "bread" } };
    return View(model);
}

[HttpPost]
public ActionResult Test(MyModel model, FormCollection fc)
{
    // Count equals one
    var count = model.Products.Count();
    return RedirectToAction("index");
}

Model

public class MyModel
{
    public int User { get; set; }
    public string Address { get; set; }
    public string ZipCode { get; set; }
    public List<Product> Products { get; set; }
}
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

View

@model MyModel
<form method="post">
    <input id="btnSubmit" type="submit" value="submit" />
</form>
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/knockout-2.2.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script type="text/javascript">

    var Product = function (Id, Name) {
        self = this;
        self.Id = Id;
        self.Name = Name;
    }

    var mapping = {
        'Products': {
            create: function (options) {
                return new Product(options.data.Id, options.data.Name);
            }
        }
    }


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

    var viewModel = new MyModel(@Html.Raw(Json.Encode(Model)));

    $('#btnSubmit').click(function (event) {
        event.preventDefault();
        var theModel = ko.mapping.toJSON(viewModel);
        debugger;
        $.ajax({
            type: 'POST',
            url: "@Url.Action("Test", "Home")",
            data: theModel,
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function (result) {
                if (!result.success) {
                    //alert(result.error);
                }
                else { }
            }
        });
    });

    </script>
Sign up to request clarification or add additional context in comments.

8 Comments

I had the dataType: 'json', defined there as well, but that didn't work. I got it from this post: stackoverflow.com/questions/11050523/… but that didn't work. And in this case it should not return anything. Just redirect back to the index page. I rather do a normal post in stead of an AJAX one. But couldn't find a good example on how to do that with KnockoutJS.
Please try the rest of my suggestions too. I had a working example by following those steps. I know what u mean, a standard post back can be used but you have to know all the form settings that the model binder expects & make sure knockout keeps them in sync.
All the js object values have to match. The final thing for me was the data type for the model binder to map it.
They all match, I didn't touch any other object, just filling the Products List<>. But it's still not binding the model. Did what you said except for the mapping part. That doesn't work some how. But shouldn't matter for this case.
First I had to change the js types to match. From your earlier question they differed & I used the same project to get it working. It wouldn't work until I set the data type though. That was the key part for me. It might be caching in the browser if you have followed the above & it's not working. Have u tried hard refreshing?
|
0

After investigating some more with fiddler, it turned out that I was getting a 500 error with this message:

System.MissingMethodException: No parameterless constructor defined for this object.

After adding the parameterless constructor in the model, I still got the error message. This was caused because I had a few SelectList in my model. So that's why It couldn't be bound to the model.

Found the solution on this SO post (look for the answer of Chris S). Hope it helps others when facing this issue too.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.