I'm using Umbraco MVC to build a form four our webpage. I have a ViewModel which is actually a property to another ViewModel, and is populated using a partial-view in the razor-form below. For whatever reason, the sub-viewmodel (RequiredHealthInputData, se below) is always null after binding! The binder will successfully bind all the form values to my main viewmodel but my sub-viewmodel will remain null!
(I have research many similar questions regarding binding of complex types but I believe but none of the solutions I've found so far (prefixing, renaming my properties to support routing etc) works.
I have a PtjInsurancePickerViewModel.cs (the main viewmodel) which looks as follows:
public class PtjInsurancePickerViewModel : BaseViewModel, IValidatableObject
{
[Required]
public string InsuranceNameStr { get; set; } = "-1";
public HealthDeclarationModel RequiredHealthInputData { get; set; }
}
HealthDeclarationModel is a ViewModel as well and has the following values:
public class HealthDeclarationModel : BaseViewModel, IValidatableObject
{
[Display(Name = "Extra comment")]
public string ExtraComments { get; set; }
[Display(Name = "EnsurancePTName")]
public string EnsurancePTName { get; set; }
}
And I have the a view InsurancePicker.cshtml with the following form:
@using (Html.BeginUmbracoForm<InsurancePickerSurfaceController>("ProcessSelections"))
{
<h3>Select insurance</h3>
@Html.Partial("../Partials/InsurancePicker/_vsFamilyInsuranceProtection", Model)
<h3>Select extra options</h3>
@Html.Partial("../Partials/_Healthdeclaration", Model.RequiredHealthInputData)
<h3>Send!</h3>
<input type="submit" class="btn btn-success" value="Send!" title="Confirm choices"/>
}
Note that the form consists of two partials, one which gets the PtjInsurancePickerViewModel and one which gets the HealthDeclarationModel which is a property of PtjInsurancePickerViewModel
Here is the partial for my HealthDeclarationModel:
<div class="HealthDeclarationModel-Panel">
<strong>2. Är du fullt arbetsför?</strong>
@Html.DropDownListFor(x => x.EnsurancePTName, Model.YesNoLista, new { @class = "form-control", @id = "EnsurancePTNameSelect" })
@Html.ValidationMessageFor(x => x.EnsurancePTName)
@Html.TextAreaFor(x => x.ExtraComments, new { @class = "form-control", style = "max-width:100%; min-width: 100%;" })
@Html.ValidationMessageFor(x => x.ExtraComments)
</div>
(Note. I give the input fields in my partial special IDs (used by jquery for statemanagement). Perhaps this could be part of the issue? I've tried submitting with the Ids prefixed with the model name "HealthDeclarationModel .EnsurancePTNameSelect" instead of just "EnsurancePTNameSelect" for example, but to no avail)
The submit function leads to the follow method:
[Authorize(Roles = "Forsakrad")]
public class InsurancePickerSurfaceController : BaseSurfaceController
{
[HttpPost]
public ActionResult ProcessSelections(PtjInsurancePickerViewModel filledModel)
{
//Checks if the very important RequiredHealthInputData submodel is null
if (filledModel.RequiredHealthInputData == null)
{
throw new ApplicationException("Critical data missing!!");
}
else
{
DoImportantStuffWithRequiredHealthInputData(filledModel.RequiredHealthInputData)
}
return CurrentUmbracoPage();
}
}
Now here's my problem. RequiredHealthInputData will always be null as the MVC binder for can't bind HealthDeclarationModel to PtjInsurancePickerViewModel. The result of the default binder will look something like this:
{IndividWebb.Models.PtjInsurancePickerViewModel}
InsuranceNameStr: "0"
HalsodeklarationDataModel: null
However, the form collection will look something like this:
controllerContext.HttpContext.Request.Form.AllKeys
{string[17]}
[2]: "InsuranceNameStr"
[9]: "EnsurancePTName"
[12]: "ExtraComments"
14]: "HalsodeklarationDataModel"
(Some results have been excluded)
Also note that EnsurancePTName which is an input that belongs to HalsodeklarationDataModel has the id EnsurancePTName and not HalsodeklarationDataModel.EnsurancePTName.
I have really no idea how to proceed with this or even how to debug it. I've just a customed helper to verify that the binding does indeed exclude all values from HalsodeklarationDataModel