Как правильно связать с частичными видами без отправки всей модели
Мне нравится брать части моего представления и разбивать их на несколько частичных представлений, и я хотел бы передать только ту часть модели, которая интересует частичное представление. В общем, я хотел бы поместить модель специально для частичного представления как свойство модели, которое передается в основной вид.
Проблема, однако, заключается в том, что я думаю, что это приводит к тому, что помощники html не отображают таким образом, что средство связывания модели может правильно собрать его обратно, поскольку оно не осознает частично, что оно является свойством другого объекта.
Мне действительно нравится делать это таким образом, потому что это делает код таким образом намного более организованным, и менее опытным программистам труднее приходить и показывать весь мой код, поскольку все для них уже очень структурировано. И до сих пор это не было проблемой для меня, потому что я либо не нуждался в вводе формы из партиалов, либо обрабатывался с помощью вызовов ajax. На этот раз я хотел бы просто использовать обычный DefaultBinder, и мне интересно, есть ли способ заставить эту работу работать без отправки всей модели во все частичные представления?
Пример:
Основной вид содержит следующую строку кода:
@{ Html.RenderPartial("_Registrants", Model.Registrants); }
Частичная регистрация владельцев выглядит следующим образом:
@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>
}
Основная модель выглядит так:
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; }
}
А вот RegistrantsModel и 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; }
}
1 ответ
Ваш частичный генерирует элементы управления формы с name
атрибуты, которые относятся к коллекции RegistrantModel
например
<input name="[0].FirstName" ... />
который будет привязан к методу POST с параметром IList<RegistrantModel>
, Для того, чтобы привязать к вашему CourseRegistrationModel
, вы должны быть
<input name="Registrants[0].FirstName" ... />
Есть 2 варианта, чтобы добавить правильный префикс к name
приписывать.
Один из них - добавить префикс, передав его как AdditionalViewData
в RenderPartial()
метод
@{ Html.RenderPartial("_Registrants", Model.Registrants,
new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "Registrants" }}); }
См. Также получение значений из вложенного сложного объекта, который передается в частичное представление, для метода расширения, который можно использовать для упрощения кода в представлении.
Предпочтительным методом является использование EditorTemplate
для typeof RegistrantModel
, Вам нужно назвать частичное то же самое, что и имя класса (в вашем случае RegistrantModel.cshtml
) и найдите его в /Views/Shared/EditorTemplates
папка (или в /Views/YourControllerName/EditorTemplates
если вы хотите использовать разные шаблоны для разных контроллеров). Ваш шаблон тогда основан на единственном экземпляре модели
@model RegistrantModel
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName, new { @placeholder = "enter first name" })
@Html.ValidationMessageFor(m => m.FirstName)
....
и на главном экране используйте
@Html.EditorFor(m => m.Registrants)
EditorFor()
Метод имеет перегрузки, которые принимают как один T
а также IEnumerable<T>
и в случае коллекции методы генерируют правильный html для каждого элемента в коллекции.