0

I have a model I am passing to a view and using Html.Raw to encode it into a JSON object:

 var model = @Html.Raw(Json.Encode(Model));

On the page I fill various portions of the model from fields in the page:

 model.ProductId = $("#txtProductId").val();

and then try to post it to the controller that way with ajax:

 $.ajax({
   type: 'POST',
   url: '@Utl.Action("AddProducts"),
   data: JSON.stringify(model),
   dataType: 'json',
     //etc

but it is never making it to the controller method:

 [HttpPost]
 public ActionResult AddProducts(ProductModel, model)
 {
       //do stuff with the model data
 }

Can anyone help me out here and explain how I have to changs things to get the model to post?

My models, simplified:

 public class OrderModel {
    public ProductModel Product {get;set;}
    public PersonModel Person {get;set;}
    public List<ProductModel> Products {get;set;}
 }

 public class ProductModel {
    public string Partno {get;set;}
    public int Quantity {get;set;}
      /// etc
  }

  public class PersonModel {
     public string Surname {get;set;}
     public string GivenName {get;set;}
     public string Address {get;set;}
       /// etc
  }
Dean.DePue
  • 1,013
  • 1
  • 21
  • 45
  • Why are you calling stringify? that not needed – Adrian Salazar Jan 22 '15 at 18:01
  • OK, so what is my problem? I tried to send just the model but I get the same result, not making it to the controller method. – Dean.DePue Jan 22 '15 at 18:06
  • Yes and the content type should be "application/json; charset=utf-8" – Adrian Salazar Jan 22 '15 at 18:08
  • @AdrianSalazar the contentType is already set to that and it still fails. Any other ideas? – Dean.DePue Jan 22 '15 at 18:17
  • have you tried to send a simple string and see if that makes it across? – krilovich Jan 22 '15 at 18:24
  • the only way I've been able to do it is to reconstruct the entire model in JS like function ProductModel () { blah} and then for the AJAX I just set a new instance of the ProductModel and load it with values from the page and it goes just fine. I don't understand why I cannot send the model I encoded from loading the page. – Dean.DePue Jan 22 '15 at 18:27
  • Can you show the output of your JSON and please forgive the question but... Are you executing this var something = JSON.encode? – Adrian Salazar Jan 22 '15 at 18:56
  • Yes, the var does get filled with the data from the controller upon initialization of the page. There are two lists in the model and they are intact. What else do you need to know? – Dean.DePue Jan 22 '15 at 21:39

1 Answers1

3

Change you code to

$.ajax({
   type: 'POST',
   url: '@Url.Action("AddProducts")',
   data: model, // not stringified
   dataType: 'json',
   ....

or

$.post('@Url.Action("AddProducts")', model, function(data) {
  // do stuff with returned data
});

which will post back to

[HttpPost]
public ActionResult AddProducts(ProductModel model)
{
   //do stuff with the model data
}

assuming the model in your view is ProductModel

However, if your just wanting to post back the form, you can use var model = $('form').serialize(); rather than manually setting the properties of the object.

  • This is getting there! It is now getting to the controller, however, the model is empty for the values set, such as the ProductId loaded from the text field. The lists are intact so I know the model is OK. Is there a better way to load the various fields? – Dean.DePue Jan 23 '15 at 09:49
  • Works fine for me. Not sure what you mean by _the lists are intact_? Suggest you post the model definition to see if the problem might be elsewhere (typical issues are: no getter/setter, a property with the same name as the controller parameter(s), no default constructor,...). And is there a reason why you would not just serialize the form? –  Jan 23 '15 at 10:00
  • The model is composed of a PersonModel, which contains fields for name and address, etc, and a ProductModel, which contains fields for product name, etc, and a ProductModels entry which is supposed to be a collection of the products ordered. So in the page I am loading model.PersonModel.Surname = $("#txtSuranem").val(), etc. That data never gets to the controller, although I can clearly see it in the page model right before posting. The product model is added to the array of Product models model.ProductModesl[cnt] = model.ProductModel, but ends up empty. I'm trying to add one at a time – Dean.DePue Jan 23 '15 at 10:05
  • and display a partial view with a list of the products ordered in a separate DIV of the form. So I don't think the solution would be to serialize and post the entire form, at least not until the user is finished ordering, right? – Dean.DePue Jan 23 '15 at 10:06
  • But you POST method is `ProductModel` (the binder will not bind any values associated with `PersonModel`). Also I suspect you might be going about this the wrong way (and certainly creating invalid html with the duplicate `ids` if your adding multiple Products using a partial). You need to post some more details of your view and the model you are passing to the view (a new question might be better) –  Jan 23 '15 at 10:19
  • The questions/answers [here](http://stackoverflow.com/questions/28047465/inserting-multiple-entities-into-many-to-many-linking-table/28080391#28080391) and [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) might give you some alternatives to think about - i.e. dynamically creating collection objects and posting back the whole model at once –  Jan 23 '15 at 10:20
  • I am posting the entire order, which contains the person information, the product, and the products collection. Is there a better way to do that? I've looked at your examples and they do not apply, I think. – Dean.DePue Jan 23 '15 at 10:25
  • If you are wanting to render `OrderModel` with details of `Person` and add new `Product`'s, then I think those examples are probably what you want. However, with your approach maybe just `var model = JSON.parse('@Html.Raw(Json.Encode(Model.Product))');` and post this plus the ID of the person (assuming that's all you need to save the new product) - then the controller might be `ActionResult AddProducts(ProductModel model, int person)` - but still hard to tell without seeing more of your view. –  Jan 23 '15 at 10:34
  • What I mean by lists are like Container, such as keg or case. These are intact in the JS model as well as the model as posted to the controller. What is not there when posted are the values set in the page. How do I set those values so that they are included in the model posted to the controller? Like I said, they are there in the page in the $.post function. – Dean.DePue Jan 23 '15 at 10:34
  • I just tried something that might help, I've added the field Surname to the top level order model - when I set it in the page it is returned to the controller. Somehow the various sub-models are not getting set. – Dean.DePue Jan 23 '15 at 10:39
  • Without more code its hard to tell, but `model.ProductId = $("#txtProductId").val();` wont do anything because your model is `OrderModel` which does not have property `ProductId`. It would need to be `model.Product.ProductId` (I think - but can be sure). The real question is why would you return all that data. You seem to want to save a new product to the order so you should only be posting the product details and the order ID (or whatever is the minimum to save the data). But I'm not sure if its `ActionResult AddProducts(ProductModel model)` or `ActionResult AddProducts(OrderModel model)`? –  Jan 23 '15 at 10:52
  • Stephen - thank you for steering me in the right direction. What is happening, and I don't know why, is that I cannot post the entire model back to the controller. I can, however, post portions of the overall model. I can post the Person sub model and the Product sub model, one at a time. I store each one in Cache and then when the order is complete, create the transaction. Each portion is displayed in a partial view inside a div an I simply show or hide the div i want. The page is smooth and pleasing to the user. THANK YOU! – Dean.DePue Jan 24 '15 at 10:25