Генерировать различные идентификаторы клиентов в ASP.NET MVC3 при повторении над списком элементов

#asp.net-mvc #asp.net-mvc-3 #razor

#asp.net-mvc #asp.net-mvc-3 #razor

Вопрос:

У меня есть ASP.NET MVC3 Razor view, который отображает редакторы для списка клиентов внутри jQuery UI accordion. На данный момент все идентификаторы на стороне клиента для аналогичных свойств клиента одинаковы в отображаемом html. По очевидным причинам я хотел бы это изменить.

Мой основной вид заключается в следующем:

 <div id="accordionKlanten">
@foreach (var customer in Model.Customers)
{
    <h3><a href="#">@customer.Name</a></h3>
    <div>@{ Html.RenderPartial("CustomerData", customer); }</div>
}
</div>
  

И на мой CustomerData взгляд (значительно упрощенный):

 @using (Ajax.BeginForm("UpdateCustomer", ajaxOptions))
{
    @Html.LabelFor(model => model.Name)
    @Html.TextBoxFor(model => model.Name)
    <input type="submit" value="Opslaan" />
}
  

Все это работает отлично: я могу опубликовать в своем UpdateCustomer методе действия, объект модели привязан и возвращается частичное представление, которое отображается обратно клиенту.

Но когда у меня три клиента, это отображает три поля ввода в моем html с id="Name" . Одна из ошибок заключается в том, что <label for="Name">...</label> не работает, поскольку Name это не уникальный идентификатор.

Есть ли какой-либо способ сообщить, что ASP.NET MVC3 для отображения различных id атрибутов (оставляя name атрибуты нетронутыми, поскольку они используются для привязки к модели)?

Для полноты картины, вот два задействованных метода действия:

 // Returns view that renders editor for each customer.
public ActionResult Index()
{
    var customers = _customerService.GetCustomers();
    return View(new CustomersViewModel { Customers = customers });
}

// Updates a customer and returns a partial view.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateCustomer(CustomerDto customer)
{
    // Update customer in database.
    return PartialView("CustomerData", customer);
}
  

Ответ №1:

Вместо написания уродливых циклов в представлении:

 <div id="accordionKlanten">
@foreach (var customer in Model.Customers)
{
    <h3><a href="#">@customer.Name</a></h3>
    <div>@{ Html.RenderPartial("CustomerData", customer); }</div>
}
</div>
  

используйте шаблоны редактора:

 <div id="accordionKlanten">
    @Html.EditorFor(x => x.Customers)
</div>
  

и в соответствующем шаблоне редактора ( ~/Views/Shared/EditorTemplates/Customer.cshtml ):

 @model Customer
<h3>
    <a href="#">@customer.Name</a>
</h3>
<div>
    @Html.EditorFor(x => x.FirstName)
</div>
<div>
    @Html.EditorFor(x => x.LastName)
</div>
...
  

Теперь шаблон Customer редактора будет выполняться автоматически для каждого элемента Customers свойства collection в вашей модели. Единственное требование — соблюдать соглашение об именовании: оно должно быть расположено в ~/Views/Shared/EditorTemplates папке и должно быть названо в соответствии с типом элемента коллекции. Так, например, если свойство равно IEnumerable<CustomerViewModel> , шаблон редактора должен иметь имя CustomerViewModel.cshtml и, очевидно, быть строго типизированным для CustomerViewModel .

Вот и все. Теперь вы не только очистили свое представление, но и будете использовать собственные имена.

Комментарии:

1. Хорошо, это работает в том смысле, что теперь генерируются уникальные идентификаторы. Однако моя модель больше не привязана к. У меня есть обновление для каждого Customer , поэтому у меня также есть форма (Ajax) для каждого клиента. Правильный метод действия ( UpdateCustomer ) по-прежнему вызывается, но его customer параметр не содержит значений.

2. Причина в том, что model binder ожидает свойство с именем Name , но получает свойство с именем Customers[0].Name . Могу ли я исправить это, не прибегая к пользовательской модели binder?

3. Да, пусть ваше действие post принимает тип параметра, который совпадает с вашей моделью представления.

4. Я понимаю это, но я хотел бы иметь действие post для каждого клиента, а не для всего списка клиентов. Никогда не будет обновляться более одного клиента одновременно, так зачем тратить пропускную способность на публикацию списка клиентов?

5. У меня такая же проблема, и я не вижу способа обойти ее, не вникая в глубины mvc, на что у меня нет времени.

Ответ №2:

Используйте for цикл вместо foreach loop в вашем основном представлении.

 @for (var i = 0; i < Model.Customers.Count; i  )
{
    <h3><a href="#">@customer.Name</a></h3>
    <div>@{ Html.RenderPartial("CustomerData", Model.Customers[i]); }</div>
}
  

Вам нужно будет настроить это, чтобы использовать a List<Customer> или an Customer[] .

Комментарии:

1. Нет, не используйте никаких циклов в представлении.

2. потому что, поскольку ASP.NET 2.0 существуют шаблоны редактирования / отображения. Смотрите мой ответ для получения более подробной информации. Таким образом, циклы были необходимы только в ASP.NET MVC 1.0. С этого времени представления могут быть намного чище.