#asp.net-core #model-view-controller #c#-4.0 #asp.net-core-mvc #partial-views
#asp.net-core #model-view-controller #c #-4.0 #asp.net-core-mvc #частичные представления
Вопрос:
Я не могу привязать коллекцию дочерних объектов, созданных динамически с использованием свойства частичного представления к view-model IEnumerable
.
Я успешно привязал объекты, созданные динамически с использованием частичных представлений, к view-model, используя метод, который я нашел в этом блогеhttps://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx /. Я следовал той же технике, но я не могу привязать коллекцию к IEnumerable
свойству в view-model.
[BindRequired]
public class EmployeeViewModel
{
other properties....
public IEnumerable<ContactDetailViewModel> EmployeeContact { get; set; }
}
[BindRequired]
public class ContactDetailViewModel
{
// I use this as my indexer for dynamic elements
public string RecordId { get; set; } = Guid.NewGuid().ToString();
public string Telephone { get; set; }
public string EmailAddress { get; set; }
public string ContactDescription { get; set; }
}
Я вызываю этот метод действия через ajax для добавления динамических элементов контактной информации, и он возвращает частичный просмотр в виде html, и он отлично работает.
[Route("[action]", Name = "BlankEmployeeContactDetail"), HttpGet("AddBlankContactDetail")]
public PartialViewResult AddBlankContactDetail()
{
return PartialView("_ContactInformation", new ContactDetailViewModel());
}
Первоначальная контактная информация добавляется в основной вид с помощью следующего, пожалуйста, перейдите по этой ссылкеhttps://1drv.ms/u/s !AkRSHVUtFlKhuHaxH96Ik4ineATE для загрузки файлов основного вида и частичного просмотра cshtml. Также следует отметить, что привязка модели не выполняется для всех других свойств, когда я включаю этот частичный просмотр, но работает, когда я его комментирую. Я сбит с толку и был бы очень признателен за любую помощь, которую вы можете мне предоставить.
<section id="widget-grid" class="">
<div class="row contactContainer">
@{ await Html.RenderPartialAsync("_ContactInformation", new ContactDetailViewModel()); }
</div>
</section>
Это метод действия контроллера, к которому я пытаюсь привязать опубликованные данные:
[Route("[action]"), HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
public IActionResult Register([FromForm] EmployeeViewModel model, [FromQuery] string returnUrl = null)
{
if (ModelState.IsValid)
{
}
return View(model);
}
Комментарии:
1. Я не понимаю, где вы моделируете привязку чего-либо здесь. Ваше действие не имеет параметров, и вы создаете экземпляр своей модели представления напрямую.
2. Добрый день, спасибо за комментарий, я прикрепил контроллер по ссылке выше, но я отредактирую, чтобы включить метод action, который получает опубликованные данные.
Ответ №1:
Для привязки входные имена в значительной степени соответствуют определенному соглашению, которое соответствует тому, к чему вы привязываетесь. Хотя из вашего вопроса неясно, я предполагаю, что вы пытаетесь в конечном итоге привязаться к экземпляру EmployeeViewModel
, что означает, что для ввода вашей контактной информации потребуются имена типа: EmployeeContact[0].Telephone
, но когда вы передаете экземпляр ContactDetailViewModel
в качестве «модели» частичного просмотра, имена будут просто Telephone
, и, что еще хуже, эти одни и те же имена будут повторяться снова и снова, т. Е. каждый созданный вами набор полей контактной информации будет иметь вход с именем просто Telephone
.
Короче говоря, вам нужен контекст всей модели для генерации правильных входных имен. У вас есть несколько вариантов.
Поскольку вы извлекаете набор полей с помощью запроса AJAX, можно было бы передать «префикс» для использования вместе с этим запросом. Другими словами, вы можете отслеживать значение индекса, подсчитывая, сколько из этих разделов вы добавили, а затем отправлять вместе с запросом на новый раздел что-то вроде
prefix: 'EmployeeContact[' (i 1) ']',
Затем в вашем частичном представлении:
@{ await Html.RenderPartialAsync("_ContactInformation", new ContactDetailViewModel(), new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = ViewBag.Prefix } } ); }
Это немного халтурно и, честно говоря, вероятно, довольно подвержено ошибкам. Лучшим вариантом было бы использовать совершенно другой подход. Вместо обратного вызова для получения частичного представления определите его только один раз в качестве шаблона:
<script type="text/html" id="ContactInformationTemplate">
<!-- HTML for contact information inputs -->
</script>
Затем, используя библиотеку, такую как Vue, React, Angular и т.д., Вы можете настроить конструкцию «foreach», привязанную к определенному массиву JavaScript, который использует этот шаблон для отображения элементов в этом массиве. Затем добавление нового набора входных данных так же просто, как добавление нового элемента в массив. Вам придется выполнить некоторые работы, чтобы настроить входные имена на основе индекса элемента в массиве, но у всех этих клиентских фреймворков есть способы сделать это. Это также имело бы побочное преимущество в том, что не нужно было бы отправлять AJAX-запрос каждый раз, когда вы хотите добавить новый раздел.
Комментарии:
1. Добрый день, спасибо за ваш любезный комментарий, я сделал это, и теперь он работает нормально. Из-за этого это не работало
name="EmployeeContact[@(Model.RecordId)].ContactDescription"
, я использовалname="model[@(Model.RecordId)].ContactDescription"
, поэтому использование имени свойства помогает связующему модели понять, как связать какие элементы с какими свойствами. Я целый день боролся с этим, и у меня даже развилась мучительная головная боль, которую я сейчас лечу.2. Я использую
public string RecordId { get; set; } = Guid.NewGuid().ToString();
для создания индексатора, и он работает как шарм, и это объясняет эту строку кодаnew ContactDetailViewModel()