Rui Miguel Pinheiro
Rui Miguel Pinheiro

Reputation: 112

Properties of Class Properties of Model not binding

EDIT

This question had to be edited in some points due to the new findings after some help of John H putting me in the right direction in understanding this problem.

END OF EDIT

I have these Models:

public class SearchModel
{
    public SearchModel()
    {
        Filters = new SearchFiltersModel();
    }

    [Display( ... )]
    public string Field1 { get; set; }

    public SearchFiltersModel Filters { get; set; };
}

public class SearchFiltersModel
{
    [Display( ... )]
    public string Field2 { get; set; }
}

Then in the View:

@model SearchModel

@using ( Html.BeginForm( ... ) )
{
    @Html.TextBoxFor( m => m.Field1, null, new { @class = "form-control" } )
    @Html.TextBoxFor( m => m.Filters.Field2, null, new { @class = "form-control" } )
    (...)
}

I can see in the generated HTML:

  1. Field1 is rendered with "Field1" in both id and name attributes.
  2. Field2 is rendered with "Filters_Field2" in both id attribute and "Filters.Field2" in name attribute (note that one uses underscore and the other uses a dot as separator).

Now, I wrote some values in Field1 and Field2 ("123" and "456", respectively).

Then I clicked the Submit button.

EDIT

I should add that this Submit button is not a regular submit button: it's a button that executes a javascript function that collects the fields, then send them AJAX'ly, as we are using https://datatables.net/:

    $("#Search_Execute").click(() => {

        table.destroy();

        config.ajax = {
            url: "@Url.Action( ... )",
            type: "POST",
            data: function (d) {
                d.Field1 = $("#Field1").val();
                d.Filters_Field2 = $("#Filters_Field2").val();
            }
        };

        table = $("...").DataTable(config);

Note that I wrote d.Filters_Field2 instead of d.Filters.Field2. If I change the underscore to a dot, I will need to add...

        d.Filters = new Object();

...before setting d.Filters.Field2. It won't work too (see below).

END OF EDIT

I could see (e.g. using Chrome's Developer Tools -> Network) the values being POST'ed this way:

  1. Field1: 123
  2. Filters_Field2: 456

EDIT

If I use the object-oriented alternative of Filters.Field2 mentioned above, POST will appear like this:

  1. Field1: 123
  2. Filters[Field2]:

So, that alternative not only continues doing it wrong (see below!) but it also leaves the field empty.

END OF EDIT

So far, it seemed to be working: I fill values in the inputs, they are POST'ed.

Then, in the Controller\Action, which signature is, btw:

    public ActionResult Search( SearchModel model )
    {
        (...)
    }

I added a watch to the model parameter and saw that:

  1. model.Field1 is filled with "123".
  2. model.Filters.Field2 is empty.

EDIT

Before John H comment, at this point, I was wondering the problem was on the POST to Model binding side.

After examining John H's solution I understood that the problem was in the javascript AJAX call rendering the POST's key name the wrong way (it must be Filter.Field2, not Filter_Field2).

So the question below was refactored to:

END OF EDIT

==> How can I effectively POST a Filters.Field2 field using javascript and have it binding correclty to Filters.Field2 in the Model?

Upvotes: 1

Views: 122

Answers (1)

John H
John H

Reputation: 14630

Edit

I've never used https://datatables.net before, but it looks to me like you just need to change how you're sending the data in the AJAX call. Something like:

var model = {
    Field1: $("#Field1").val(),
    Filters: {
        Field2: $("#Filters_Field2").val()
    }
};

config.ajax = {
    url: "@Url.Action( ... )",
    type: "POST",
    data: model
};

public fields cannot be used for model binding. You need to use a property instead:

public class SearchModel
{
    [Display( ... )]
    public string Field1 { get; set; }

    public SearchFiltersModel Filters { get; set; }
}

Upvotes: 1

Related Questions