Question

Without the ajax call, My main view binds to my parent class and the partial view on main view, binds to a child member of the parent class

parent...

public class Client
{
    [ScaffoldColumn(false)]
    public int Id { get; set; }

    [DisplayName("Name")]
    [Required]
    [StringLength(120)]
    public string Name { get; set; }

    // etc...

    public virtual Address Address { get; set; }
}

child of parent...

public class Address
{
    [ScaffoldColumn(false)]
    public int AddressId { get; set; }

    [DisplayName("Address")]
    [Required]
    [StringLength(200)]
    public string Street { get; set; }

    // etc...

    [ForeignKey("Client")]
    public int? Id { get; set; }
    public virtual Client Client { get; set; }

}

the main view

@using (Html.BeginForm("Create", "Client", FormMethod.Post, new Dictionary<string, object> { { "data-htci-target", "addressData" } }))
{
    @Html.AntiForgeryToken()


    <div class="row">
        @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
        <div class="col-sm-4 col-md-4 col-lg-4">
            @Html.Kendo().AutoCompleteFor(model => model.Name).HtmlAttributes(new { style = "width:100%" })
            @Html.ValidationMessageFor(model => model.Name)
        </div>
    </div>

    @{ var vdd = new ViewDataDictionary(ViewData) { TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = "Address" } };}

    @Html.Partial("_AddressPartial", Model.Address, @vdd)

// yada yada...you can imagine the rest of the very standard view

The partial view's model is Address and all hooks up. When I post back to the server the Address member is properly filled with entered data from the partial view...

So now...in my partial view, I now load the js to call the async routine to load the IP GEO data for the user - so it pre-fills the city, province, country

Any example of an ajax call will suffice...mine calls an AddressControl, returns a partialview result and replaces a div named addressData with the updated partialview :

$(function() {

var urlGeoIeoip = "http://ip-api.com/json/?callback=?";

$.ajax({
    url: urlGeoIeoip,
    type: "GET",
    dataType: "json",
    timeout: 5000,
    success: function (geoipdata) {


        $.ajax({
            url: "/getlocationdata/" + geoipdata.country + "/" + geoipdata.regionName + "/" + geoipdata.city,
            type: "GET",
            timeout: 5000,
            success: function (data) {
                //alert(data);
                //var $form = $(this);
               // var $target = $($form.attr("data-htci-target"));
                var $newHtml = $(data);
                //alert($target);
                $("#addressData").replaceWith($newHtml);
                $("#City").data("kendoComboBox").value(geoipdata.city);
                $("#State").data("kendoComboBox").value(geoipdata.regionName);
                $("#Country").data("kendoComboBox").value(geoipdata.country);
            }
        });


    }
}).fail(function(xhr, status) {
    if (status === "timeout") {
         // log timeout here
    }
});
});

All works great!

BUT

Now, when I post back to the user via the submit button, the Address child member of the parent class is null....

How do I get it to rebind the Address member of the parent class after return of the ajax call?

Was it helpful?

Solution

By generating your input fields in the partial view, the HTML helpers are unaware that your Address model is a property of your initial Client model, so it's generating HTML inputs like:

<input type="text" id="City" name="City" />
<input type="text" id="State" name="State" />

If your POST action method is accepting a Client model then the model binder will look for the properties City and State of the Client model, which don't exist.

You need your HTML input to look like:

<input type="text" id="Address_City" name="Address.City" />
<input type="text" id="Address_State" name="Address.State" />

Instead of using a partial for your Address fields, you should use an Editor Template which will then preserve the parent property as you need in this case.

@Html.EditorFor(x => x.Address)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top