Бритва MVC @foreach


82

Я чув, що наявність @foreach всередині подання - це ні-ні. Це означає, що погляд не повинен мати в собі жодної логіки. Яка найкраща практика щодо того, де повинна бути логіка для @foreach?

    @foreach.. 

5
Де ви це читали? Логіка - це те, для чого призначена бритва!
Микола Кінг

4
будь-ласка, прочитайте наступний підручник з ms asp.net/web-pages/tutorials/basics/…
Ніколас Кінг

Відповіді:


162

Яка найкраща практика щодо того, де повинна бути логіка для @foreach?

Ніде, просто позбудься цього. Ви можете використовувати редактор або шаблони відображення.

Так наприклад:

@foreach (var item in Model.Foos)
{
    <div>@item.Bar</div>
}

цілком можна замінити шаблоном відображення:

@Html.DisplayFor(x => x.Foos)

і тоді ви визначите відповідний шаблон відображення (якщо вам не подобається шаблон за замовчуванням ). Отже, ви визначите шаблон для багаторазового використання, ~/Views/Shared/DisplayTemplates/Foo.cshtmlякий автоматично відображатиметься фреймворком для кожного елемента колекції Foos ( IEnumerable<Foo> Foos { get; set; }):

@model Foo
<div>@Model.Bar</div>

Очевидно, що ті самі правила застосовуються до шаблонів редакторів, які слід використовувати на випадок, якщо ви хочете показати деякі поля введення, що дозволяють редагувати модель подання на відміну від простого відображення її як лише для читання.


3
@DarinDimitrov це правда, якщо це сувора модель MVC, проти якої ви кодуєте, однак, якщо виникає обставина, коли колекція повинна бути переглянута, чого немає в моделі, я не бачу проблеми з використанням foreach
Ніколас Кінг

6
@NicholasKing, така обставина ніколи не повинна виникати. Подання не повинно торкатися нічого іншого, крім того, що присутнє в моделі подання, переданої дією контролера. Якщо його немає в моделі подання, то вам слід помістити його туди, якщо подання це потребує. Саме для цього призначені моделі перегляду.
Дарін Димитров

1
@MihaiLabo, так, це те, що я кажу.
Дарін Димитров

2
Що робити, якщо типу елемента в колекції недостатньо для визначення відображення? Наприклад, моя модель має колекцію рядків, але іноді я хочу мати по одному рядку на рядок, а в іншому випадку я хочу, щоб вони були розділені комами?
Марк Стобер

6
Отже, в чому саме проблема foreach? Щонайменше шаблон відображення (хоча цілком прийнятний підхід, незалежно від цього) вимагає надання нового подання, яке не є безкоштовним. Велику частину часу це не буде помітно впливати на час завантаження вашого сайту, але зроблено достатньо, це може призвести до досягнення продуктивності. foreachНавколо трохи HTML і завжди буде практично миттєво. Як я вже говорив, в будь-якому випадку це не велика угода, але якщо що, є аргумент для використання foreach.
Chris Pratt

98

Коли люди кажуть, що не вкладайте логіку у погляди, вони, як правило, мають на увазі ділову логіку, а не візуалізацію логіки. На мою скромну думку, я думаю, що використання @foreach у переглядах є цілком нормальним.


22
Домовились. Мені нагадує старі семантичні дебати в HTML, які врешті-решт привели людей до спроб використовувати div і CSS для створення "таблиці" для фактичних табличних даних, оскільки вони були настільки антитабличними.
Chris Pratt

1
Я згоден. Люди погано сприймають неправильні вказівки. Чи справді мені потрібна нова папка з новим поданням, лише для відображення речей у списку в моїй viewmodel?
Дон Чідл,

1
Чи не буде використання div / css для створення табличного подання даних необхідним для створення адаптивного подання?
frostshoxx

13

Я використовую, @foreachколи надсилаю сутність, що містить список сутностей (наприклад, для відображення 2 сіток в 1 поданні)

Наприклад, якщо я посилаю як модель сутність Foo, яка містить Foo1(List<Foo1>)іFoo2(List<Foo2>)

Я можу звернутися до першого списку за допомогою:

@foreach (var item in Model.Foo.Foo1)
{
    @Html.DisplayFor(modelItem=> item.fooName)
}

11

відповідь @DarinDimitrov на випадок, коли я використовував foreach у вигляді бритви.

<li><label for="category">Category</label>
        <select id="category">
            <option value="0">All</option>
            @foreach(Category c in Model.Categories)
            {
                <option title="@c.Description" value="@c.CategoryID">@c.Name</option>
            }
        </select>
</li>

6
WOW, ти міг би написати щось подібне у поданні? Чому б не написати спеціальний помічник багаторазового використання, Html.DropDownListForякий просто враховуватиме заголовок? Це тривіально і не перетворює ваші погляди на код для спагетті: stackoverflow.com/a/7938038/29407
Дарін Димитров

7
@DarinDimitrov так, ми працюємо в дуже рухливих умовах, а це означає, що подібні сценарії іноді заважають нам використовувати такі речі, як DropDownFor, оскільки у нас не завжди є чітко визначені вимоги. Я вважаю, що у цьому випадку в розкривному меню спочатку не потрібно було "все", тоді це було потрібно, але лише в одному DropDown у поданні. Оскільки ця сторінка використовує ajax для оновлення свого не суворого шаблону MVC, і ви не можете завантажувати продукт у всі категорії відповідно до вимог. Не ідеальний, але часом неминучий.
Микола Кінг

Можливо, кращим прикладом було б використовувати це для візуалізації optgroupелементів у списку вибору, оскільки в HtmlHelpers для цього немає підтримки. Якщо вам просто потрібно додати додатковий елемент до вибраного списку, є кращі способи досягти цього, а потім все одно використовувати помічник.
Chris Pratt

Це не було б моїм визначенням Agile - я повинен погодитися з @DarinDimitrov
Luis Filipe

3

Відповідь не буде працювати при використанні перевантаження для позначення шаблону @Html.DisplayFor(x => x.Foos, "YourTemplateName).

Здається, розроблений таким чином, див. Цей випадок . Також виняток, який дає фреймворк (про тип не був таким, як очікувалось), є досить оманливим і звів мене з першої спроби (спасибі @CodeCaster)

У цьому випадку вам доведеться використовувати@foreach

@foreach (var item in Model.Foos)
{
    @Html.DisplayFor(x => item, "FooTemplate")
}

Цю відповідь пише той, хто працює над MVC, тому, мабуть, вони знають, що говорять. MVC виконає ітерацію IEnumerable<T>та викличе шаблон для типу Tдля кожного елемента.
CodeCaster

Щодо вашого редагування: це або ваш код, який помиляється, або помилка у цій конкретній версії MVC (у 5.2.2 це працює для мене). Це повинно працювати, як описано у прийнятій відповіді. Замість того, щоб казати, що це неправильно, відкрийте власне запитання щодо проблеми, якщо хочете.
CodeCaster

@CodeCaster Я вважаю, що моя відповідь додає кілька підходів до цієї конкретної справи (це витратило трохи мого часу, щоб з'ясувати, що пішло не так). Будь ласка, додайте якесь пояснення щодо збереження голосу проти? (спасибі за ваш час, до речі, просто хочу докластися до суті справи)
Тіберіу Краціун

Я не думаю, що це хороша відповідь, оскільки вона не перевіряє помилку, це допомагає чуткам у світі на кшталт "DisplayTemplate не може повторюватись" - це повинно, отже, це має спрацювати. Якщо це насправді не так, подайте помилку та скоріше відкрийте окреме запитання, де ви відтворюєте проблему, та згадайте, що ця конкретна версія, на відміну від запитань та відповідей, які розглядають те, що зазвичай має статися.
CodeCaster

@CodeCaster Тим часом у мене було ще одне редагування після того, як я зрозумів свій конкретний випадок (я змінив всю публікацію). У своєму останньому редагуванні я вказав точну умову, коли прийнята відповідь не стосується резервного посилання на відповідне запитання, на яке відповів той самий хлопець, що підтверджує, що це за задумом, а не помилка.
Tiberiu Craciun
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.