Knockout.js & list of checkboxes: post to mvc controller
Asked Answered
S

1

6

I have an MVC view model that looks like this:

public class DirectorySearchModel
{
    [Display(Name = "First name contains")]
    public string FirstName { get; set; }

    [Display(Name = "Last name contains")]
    public string LastName { get; set; }

    public CountriesCollection Countries { get; set; }
    public IEnumerable<Country> SelectedCountries { get; set; }
    public IEnumerable<Country> AllCountries { get; set; }
}

The CountriesCollection object (line 9) looks like this:

public class CountriesCollection
{
    [Display(Name = "Countries")]
    public int[] arrCountries { get; set; }
}

Now, I'm creating a new, blank instance of CountriesCollection and then adding it to a blank instance of the DirectorySearchModel view model and then serialising it all into a javascript view model for Knockout.js:

{
"FirstName":null,

"LastName":null,

"Countries":{"arrCountries":[]},

"SelectedCountries":[{"RelationshipManager":{},"CountryId":1,"CountryName":"UK"},{"RelationshipManager":{},"CountryId":2,"CountryName":"France"},{"RelationshipManager":{},"CountryId":3,"CountryName":"Spain"}],

"AllCountries":[{"RelationshipManager":{},"CountryId":1,"CountryName":"UK"},{"RelationshipManager":{},"CountryId":2,"CountryName":"France"},{"RelationshipManager":{},"CountryId":3,"CountryName":"Spain"}]
}

My checkboxes are rendered as: <input checked="checked" data-bind="checked: Countries.arrCountries" id="Countries_arrCountries30" name="Countries.arrCountries" type="checkbox" value="1">. Checking a couple means you end up with this Knockout.js view model:

{
"FirstName":null,

"LastName":null,

"Countries":{"arrCountries":["1", "3"]},

"SelectedCountries":[{"RelationshipManager":{},"CountryId":1,"CountryName":"UK"},{"RelationshipManager":{},"CountryId":2,"CountryName":"France"},{"RelationshipManager":{},"CountryId":3,"CountryName":"Spain"}],

"AllCountries":[{"RelationshipManager":{},"CountryId":1,"CountryName":"UK"},{"RelationshipManager":{},"CountryId":2,"CountryName":"France"},{"RelationshipManager":{},"CountryId":3,"CountryName":"Spain"}]
}

Submitting my view normally (i.e. via a submit button and not with Knockout.js) to an MVC action that expects a DirectorySearchModel, I'm able to ask for model.Countries.arrCountries to get a list of the checked items, but when I use...

$.post("/MyController/MyAction", ko.toJS(viewModel), function(returnData) {
    $("#resultCount").html(returnData);
});

or...

$.post("/MyController/MyAction", viewModel, function(returnData) {
    $("#resultCount").html(returnData);
});

to another action that expects the same DirectorySearchModel, model.Countries.arrCountries is always null! I wondered if it's due to Knockout.js posting the arrCountries entries as string[]s when MVC is expecting int[]s, but changing my MVC code to expect string[]s doesn't seem to change much..! The CountriesCollection object within the DirectorySearchModel appears to exist, but it's the arrCountries within that's always null.

Any ideas? Any help much appreciated!

Edit

The action that receives the Knockout.js viewModel:

public MvcHtmlString ResultCount(DirectorySearchModel model)
{
    return new MvcHtmlString(getResultCount(model).ToString());
}

The getResultCount method:

public int getResultCount(DirectorySearchModel model)
{
    IUserRepository userRepository = new UserRepository();
    int count = userRepository.Search(model, null).Count();
    return count;
}

FIXED!

Thanks to Konstantin for pointing out that a simple switch from $.post to $.ajax to send my Knockout.js view model back to my mvc action was all that was needed! Here's the $.ajax code I'm using:

$.ajax({  
    type: "POST",
    url: "/MyController/MyAction",
    data: ko.toJSON(viewModel),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (data) {
        $("#resultCount").html(data);
    }
});
Sloshy answered 22/5, 2012 at 8:35 Comment(9)
Can you use Fiddler or a built-in browser debugging tool to see what is actually going across the network?Multifaceted
or even just a console.log(ko.toJS(viewModel)) to confirm what is being postedGamopetalous
Thanks for the replies, guys! Paul's console.log suggestion reveals that upon checking a checkbox, you end up with: Countries (Object) containing arrCountries (Array[1]), which contains 0: "2", so it does look like the Knockout.js viewModel does contain the data... Just a case of getting my c# to accept it, it seems!Sloshy
@Sloshy are you still looking for an answer for this? If so, can you show your controller methodGamopetalous
Hi Paul, I am. Here's my controller: public MvcHtmlString ResultCount(DirectorySearchModel model) { return new MvcHtmlString(getResultCount(model).ToString()); } which calls: public int getResultCount(DirectorySearchModel model) { IUserRepository userRepository = new UserRepository(); int count = userRepository.Search(model, null).Count(); return count; } userRepository.Search is a standard query = query.Where(...) deal that adds clauses depending on what info was entered/is in the model.Sloshy
@Sloshy can you include it in the question, so it's formatted better?Gamopetalous
@Sloshy can you also post the DirectorySearchModel class structure?Gamopetalous
@Gamopetalous Done! The DirectorySearchModel class is the first code block in my question. Really appreciate you taking a look at this for me!Sloshy
@Sloshy hmmm... Could you pass the Countries object stringified? e.g. var obj = ko.toJS(viewModel); obj.Countries = ko.toJSON(obj.Countries); .... then .... $.post("/url", ko.toJSON(obj), function(data) { /*...*/ });Gamopetalous
A
2

You cant use $.post you need to go for the underlying $.ajax and add the correct contenttype to make mvc accept the posted json and do the model binding (contenttype should be "application/json; charset=utf-8") google for it and you will se lots of examples

Asco answered 23/5, 2012 at 21:30 Comment(3)
I know this applies to asp.net forms, but I don't think it does for MVCGamopetalous
Thanks Konstantin! This sorted it! Days of messing around and my original setup works perfectly simply by switching from $.post to $.ajax!Sloshy
Thanks to paul and Holf for their help - very, very much appreciate all your work on this! Will update my question with the $.ajax code I'm using.Sloshy

© 2022 - 2024 — McMap. All rights reserved.