2

I'm having trouble getting a model to bind on my action when I post from ajax (via jquery).

Model:

public class NoteEditViewModel 
{
    public bool AddMode { get; set; }
    public int ID { get; set; }
    public int PersonID { get; set; }
    public string Note { get; set; }        

    public NoteEditViewModel()
    {

    }
}

Action:

 [HttpPost]
 public ActionResult Edit(NoteEditViewModel note)
 {
     ...
 } 

JS: (actually typescript)

 $.ajax({
    url: this.options.editUrl,
    method: 'POST',
    data: JSON.stringify(this.convertFormToJSON(this.options.noteFormElement)),
    //data: $(this.options.noteFormElement).serialize(),
    //data: JSON.stringify({
    //  AddMode: $("#AddMode").val(),
    //  ID: $("#ID").val(),
    //  PersonID: $("#PersonID").val(),
    //  Note: $("#Note").val()
    //}),
    //dataType: 'json',
    //traditional:true,
    //contentType: 'application/json; charset=utf-8',
    success: (partialResult) => {
      this.options.noteModalElement.modal('hide');
    }
  });

convertFormToJSON(form : JQuery) {
  var array = form.serializeArray();
  var json = {};

  jQuery.each(array, function () {
    json[this.name] = this.value || '';
  });

  return json;
}

You can see what I've tried here. The action would either receive an empty instance of the model or null.

I did managed to get this to work with a custom ModelBinder, thus:

 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var body = controllerContext.RequestContext.HttpContext.Request.Form[0];
        var model = JsonConvert.DeserializeObject<NoteEditViewModel>(body);
        return model;
    }

This may not be the best/safest, but at least it works.

I cant see what I've done wrong here but creating a model binder for each model seems crazy. Non-ajax posts seem to work fine.

Thanks

1
  • Try data: JSON.stringify({ note: this.convertFormToJSON(this.options.noteFormElement})), Commented Aug 28, 2016 at 3:29

1 Answer 1

4

You do not need a custom ModelBinder. Your values will be successfully submitted using

$.ajax({
    url: this.options.editUrl,
    method: 'POST',
    data: $('form').serialize(),
    success: (partialResult) => {
      this.options.noteModalElement.modal('hide');
    }
});

The reason your model is not binding in the POST method is because the name of your parameter (note) is also the name of a property in your model and the DefaultModelBinder sets the value of property Note to the posted value, but also attempts to set the instance of NoteEditViewModel to that value (a string) which fails and the model becomes null

Change the signature of the method to

[HttpPost]
public ActionResult Edit(NoteEditViewModel model)

and you model will be correctly bound

Sign up to request clarification or add additional context in comments.

2 Comments

OMG. I should have guessed it was something stupid/simple like that. Ive been thrashing on this for days. I owe you beer! :)
Wow - I read this answer and ignored it and finally came back and actually read it for comprehension and yes it is exactly the issue I've been having :face_palm:

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.