eyeballpaul
eyeballpaul

Reputation: 1735

MVC 3 issue when model binding checkbox through AJAX rather than postback

I have an issue with model binding a checkbox from a form to an action on the server with a custom object containing a boolean.

Doing a google there seems to be a lot of problems with this, and no good solution. I have tried multiple things, and the problem seems to only happen when it is sent through an ajax call rather than a normal postback.

I have the following in my project (cut down for brevity):

View

@Html.LabelFor(model => model.TillAccess)
@Html.CheckBoxFor(m => m.TillAccess)

Model

public class CreateUserModel 
{
    public Boolean TillAccess { get; set; } 
}

Controller Action

[HttpPost]
public virtual ActionResult CreateUserWizard(CreateUserModel model)
{
   ...
}

I have added 2 buttons to the form, one sends as a postback and works. It sends the following with a postback if I check it on fiddler2:

TillAccess=true&TillAccess=false

It sends the following if I send it with the ajax button, and doesnt work:

{"TillAccess":["true","false"]}

Is there an issue with the way MVC model binds JSON that stops this working??

I can't get this working through AJAX (which I will be using heavily), every other field binds fine, just not the checkbox, and the fact this works perfect as a normal postback suggests its an issue with the JSON serialiser or model binder for MVC?

UPDATE

The ajax call is as follows:

function CreateUser() {
        var FormData = JSON.stringify($('#CreateUserWizardForm').serializeObject());

        $.ajax({
            url: '@Url.Action(MVC.User.User.ActionNames.CreateUserWizard)',
            data: FormData,
            contentType: "application/json",
            dataType: "json",
            type: 'POST',
            cache: 'false',
            success: function (response) {
                alert('successfully created user!');
            },
            error: function (xhr) {
                alert('There was an error creating a user');
            }
        });
    }

Full ajax post is as follows just fyi:

{"BusinessUnitId":"cd56b710-0171-11e1-be50-0800200c9a66","Person.Salutation":"","Person.FirstName":"","Person.LastName":"","‌​TillAccess":["true","false"],"OfficeAccess":"false","TillLoginId":"","OfficeEmail‌​Address":"","OfficePassword":""}

UPDATE

The serializeObject method was downloaded from the internet (as I was having json issues with the post) and is as follows:

$.fn.serializeObject = function () {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function () {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

UPDATE

The reason I used this serializeObject method was due to an error I received if I used the inbuilt call of:

$('#CreateUserWizardForm').serialize()

It created a post of:

BusinessUnitId=cd56b710-0171-11e1-be50-0800200c9a66&Person.Salutation=&Person.FirstName=&Person.LastName=&TillAccess=true&TillAccess=false&OfficeAccess=false&TillLoginId=&OfficeEmailAddress=&OfficePassword=

Which gave me an error as follows:

System.ArgumentException: Invalid JSON primitive: BusinessUnitId.

UPDATE - ANSWER (I tried to add my answer at the bottom, but it won't let me)

I found the solution. It was my AJAX call that was wrong. I changed it to the following and it is working.

$.ajax({
            url: '@Url.Action(MVC.User.User.ActionNames.CreateUserWizard)',
            data: $('#CreateUserWizardForm').serialize(),
            type: 'POST',
            cache: 'false',
            success: function (response) {
                alert('successfully created user!');
            },
            error: function (xhr) {
                alert('There was an error creating a user');
            }
        });

The old AJAX call:

var FormData = JSON.stringify($('#CreateUserWizardForm').serializeObject());

        $.ajax({
            url: '@Url.Action(MVC.User.User.ActionNames.CreateUserWizard)',
            data: FormData,
            contentType: "application/json",
            dataType: "json",
            type: 'POST',
            cache: 'false',
            success: function (response) {
                alert('successfully created user!');
            },
            error: function (xhr) {
                alert('There was an error creating a user');
            }
        });

Upvotes: 3

Views: 2244

Answers (2)

eyeballpaul
eyeballpaul

Reputation: 1735

I found the solution. It was my AJAX call that was wrong. I changed it to the following and it is working.

$.ajax({
            url: '@Url.Action(MVC.User.User.ActionNames.CreateUserWizard)',
            data: $('#CreateUserWizardForm').serialize(),
            type: 'POST',
            cache: 'false',
            success: function (response) {
                alert('successfully created user!');
            },
            error: function (xhr) {
                alert('There was an error creating a user');
            }
        });

The old AJAX call:

var FormData = JSON.stringify($('#CreateUserWizardForm').serializeObject());

        $.ajax({
            url: '@Url.Action(MVC.User.User.ActionNames.CreateUserWizard)',
            data: FormData,
            contentType: "application/json",
            dataType: "json",
            type: 'POST',
            cache: 'false',
            success: function (response) {
                alert('successfully created user!');
            },
            error: function (xhr) {
                alert('There was an error creating a user');
            }
        });

Upvotes: 3

Jakub Konecki
Jakub Konecki

Reputation: 46008

You need to send

{"model":{"TillAccess":["true","false"]}}

The model binder is not binding your model because it cannot match model parameter with any property.

UPDATE:

TillAccess property is of type bool, but you're sending an array of 2 strings. I think this is a problem

Upvotes: 0

Related Questions