I like to take sections of my view and break them out in to multiple partial views, and I like to only pass in the part of the model that partial view is interested in. Generally I like to put a model specifically for the partial as a property on the model that gets passed into the main view.
The problem though is I think this causes the html helpers not to render in a way that the model binder can properly put it back together since it doesn't realize in the partial that it is a property of another object.
I really like doing it this way cause it keeps the code soooo much more organized and harder for less experienced programmers to come and poop all over my code since everything is very structured for them already. And up till now this hasn't been a problem for me because I either didn't need to take form input from partials or else it was handled with ajax calls. This time I would like to just use the regular DefaultBinder though and am wondering if there is a way to make this work without having to send the entire model into all the partial views?
Example:
Main view has this line of code in it:
@{ Html.RenderPartial("_Registrants", Model.Registrants); }
The registrants partial looks like this:
@model Models.Order.RegistrantsModel
// stuff...
// important part:
@for(int i = 0; i < Model.Count(); i++)
{
@Html.HiddenFor(o => o[i].Enabled)
<ul class="frmRow@(Model[i].Enabled ? "" : " disabled")">
<li>
<span class="title">First Name</span>
@Html.TextBoxFor(o => o[i].FirstName, new { @placeholder = "enter first name" })
@Html.ValidationMessageFor(o => o[i].FirstName)
</li>
<li>
<span class="title">Last Name</span>
@Html.TextBoxFor(o => o[i].LastName, new { @placeholder = "enter last name" })
@Html.ValidationMessageFor(o => o[i].LastName)
</li>
<li>
<span class="title">Email Address</span>
@Html.TextBoxFor(o => o.First().Email, new { @placeholder = "enter email address" })
@Html.ValidationMessageFor(o => o[i].Email)
</li>
</ul>
}
Main model looks like this:
public class CourseRegistrationModel
{
public CourseRegistrationModel() { }
public CourseRegistrationModel(RegistrationItemModel itemModel, PaymentModel paymentModel)
{
Item = itemModel;
Payor = new PayorModel();
Registrants = new RegistrantsModel();
Shipping = new ShippingModel();
Payment = paymentModel;
}
public RegistrationItemModel Item { get; set; }
public PayorModel Payor { get; set; }
public RegistrantsModel Registrants { get; set; }
public ShippingModel Shipping { get; set; }
public PaymentModel Payment { get; set; }
}
And here are RegistrantsModel and RegistrantModel:
public class RegistrantsModel : IEnumerable<RegistrantModel>
{
public RegistrantsModel()
{
_registrants = new List<RegistrantModel>();
for(int i = 0; i < 5; i++)
_registrants.Add(new RegistrantModel());
_registrants.First().Enabled = true; // Show one registrant on form by default
}
List<RegistrantModel> _registrants { get; set; }
public decimal PricePerPerson { get; set; }
public int NoOfRegistrants { get; set; }
public RegistrantModel this[int i]
{
get { return _registrants[i]; }
}
public IEnumerator<RegistrantModel> GetEnumerator() { return _registrants.GetEnumerator(); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _registrants.GetEnumerator(); }
}
public class RegistrantModel: IEnabled
{
[RequiredIfEnabled]
public string FirstName { get; set; }
[RequiredIfEnabled]
public string LastName { get; set; }
[RequiredIfEnabled]
[EmailAddress(ErrorMessage = "Please Enter a Valid Email Address")]
public string Email { get; set; }
public bool Enabled { get; set; }
}