MVC Razor @foreach

79

Ich habe gehört, dass es ein Nein-Nein ist, @foreach in einer Ansicht zu haben. Das heißt, die Ansicht sollte keine Logik enthalten. Was ist die beste Vorgehensweise, wo sich die Logik für @foreach befinden sollte?

    @foreach.. 
Nate Pet
quelle
5
Wo hast du das gelesen? Logik ist, wofür Rasierer gedacht ist!
Nicholas King
4
Bitte lesen Sie das folgende MS
Nicholas King

Antworten:

159

Was ist die beste Vorgehensweise, wo sich die Logik für @foreach befinden sollte?

Nirgendwo, lass es einfach los. Sie können Editor- oder Anzeigevorlagen verwenden.

Also zum Beispiel:

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

könnte durchaus durch eine Anzeigevorlage ersetzt werden:

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

und dann definieren Sie die entsprechende Anzeigevorlage (wenn Ihnen die Standardvorlage nicht gefällt ). Sie würden also eine wiederverwendbare Vorlage definieren ~/Views/Shared/DisplayTemplates/Foo.cshtml, die vom Framework automatisch für jedes Element der Foos-Sammlung ( IEnumerable<Foo> Foos { get; set; }) gerendert wird :

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

Offensichtlich gelten für Editor-Vorlagen genau dieselben Konventionen, die verwendet werden sollten, wenn Sie einige Eingabefelder anzeigen möchten, mit denen Sie das Ansichtsmodell bearbeiten können, anstatt es nur als schreibgeschützt anzuzeigen.

Darin Dimitrov
quelle
3
@DarinDimitrov das ist wahr, wenn es ein striktes MVC-Modell ist, gegen das Sie codieren. Wenn jedoch ein Umstand auftritt, in dem eine Sammlung durchlaufen werden muss, die nicht im Modell enthalten ist, sehe ich kein Problem bei der Verwendung von foreach
Nicholas King
6
@NicholasKing, solche Umstände sollten niemals auftreten. Eine Ansicht sollte nichts anderes berühren als das, was in dem von der Controller-Aktion übergebenen Ansichtsmodell vorhanden ist. Wenn es nicht im Ansichtsmodell enthalten ist, sollten Sie es dort einfügen, wenn die Ansicht es benötigt. Genau dafür sind Ansichtsmodelle gedacht.
Darin Dimitrov
1
@ MihaiLabo, ja, das sage ich.
Darin Dimitrov
2
Was ist, wenn der Typ des Elements in der Sammlung nicht ausreicht, um die Anzeige zu bestimmen? Zum Beispiel hat mein Modell eine Sammlung von Zeichenfolgen, aber manchmal möchte ich eine Zeichenfolge pro Zeile und in einem anderen Fall möchte ich, dass sie durch Kommas getrennt werden?
Marc Stober
6
Also, womit genau liegt das Problem foreach? Zumindest für eine Anzeigevorlage (obwohl dies ein durchaus akzeptabler Ansatz ist) muss eine neue Ansicht gerendert werden, die nicht kostenlos ist. Die meiste Zeit wirkt sich dies nicht merklich auf die Ladezeit Ihrer Website aus, aber wenn Sie dies genug tun, kann dies zu Leistungseinbußen führen. Ein foreachbisschen HTML ist und bleibt praktisch augenblicklich. Wie ich schon sagte, es ist zwar keine große Sache, aber wenn überhaupt, gibt es ein Argument für die Verwendung foreach.
Chris Pratt
96

Wenn Leute sagen, dass sie keine Logik in Ansichten einfügen, beziehen sie sich normalerweise auf Geschäftslogik und nicht auf Renderlogik. Meiner bescheidenen Meinung nach ist die Verwendung von @foreach in Ansichten vollkommen in Ordnung.

JonoW
quelle
21
Einverstanden. Erinnert mich an die alten semantischen HTML-Debatten, die schließlich dazu führten, dass Leute versuchten, mit divs und CSS eine "Tabelle" für tatsächliche Tabellendaten zu erstellen, weil sie so tabellenfeindlich waren.
Chris Pratt
1
Genau. Menschen sind schlecht in Fehlleitung. Benötige ich wirklich einen neuen Ordner mit einer neuen Ansicht, um Dinge in einer Liste in meinem Ansichtsmodell anzuzeigen?
Don Cheadle
1
Wäre die Verwendung von div / css zum Erstellen einer tabellarischen Datenansicht nicht erforderlich, um eine reaktionsfähige Ansicht zu erstellen?
Frostshoxx
13

Ich verwende, @foreachwenn ich eine Entität sende, die eine Liste von Entitäten enthält (z. B. um 2 Raster in einer Ansicht anzuzeigen).

Zum Beispiel, wenn ich als Modell die Entität Foo sende, die Foo1(List<Foo1>)und enthältFoo2(List<Foo2>)

Ich kann auf die erste Liste verweisen mit:

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

eine Antwort an @DarinDimitrov für einen Fall, in dem ich foreach in einer Rasiermesseransicht verwendet habe.

<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>
Nicholas King
quelle
6
WOW Mann, würdest du so etwas in einer Ansicht schreiben? Warum nicht einen wiederverwendbaren benutzerdefinierten Helfer à la schreiben Html.DropDownListFor, der einfach den Titel berücksichtigt? Es ist trivial und verwandelt Ihre Ansichten nicht in Spaghetti-Code: stackoverflow.com/a/7938038/29407
Darin Dimitrov
7
@DarinDimitrov Ja, wir arbeiten in einer sehr agilen Umgebung, was bedeutet, dass solche Szenarien uns manchmal daran hindern, Dinge wie DropDownFor zu verwenden, da wir nicht immer eine klar definierte Anforderung haben. Ich glaube, in diesem Fall brauchte das Dropdown zunächst nicht "alles", dann aber nur in einem DropDown in der Ansicht. Da diese Seite Ajax verwendet, um das nicht strenge MVC-Muster zu aktualisieren, können Sie ein Produkt nicht gemäß den Anforderungen in alle Kategorien hochladen. Nicht ideal, aber manchmal unvermeidlich.
Nicholas King
Vielleicht wäre ein besseres Beispiel, dies zu verwenden, um optgroupElemente in der Auswahlliste zu rendern , da dies in den HtmlHelpers nicht unterstützt wird. Wenn Sie der Auswahlliste nur ein zusätzliches Element hinzufügen müssen, gibt es bessere Möglichkeiten, dies zu erreichen und dann den Helfer weiterhin zu verwenden.
Chris Pratt
Das wäre nicht meine Definition von Agile - ich muss @DarinDimitrov
Luis Filipe
3

Die Antwort funktioniert nicht, wenn die Überladung zum Anzeigen der Vorlage verwendet wird @Html.DisplayFor(x => x.Foos, "YourTemplateName).

Scheint so gestaltet zu sein, siehe diesen Fall . Auch die Ausnahme, die das Framework gibt (über den Typ war nicht wie erwartet), ist ziemlich irreführend und hat mich beim ersten Versuch getäuscht (danke @CodeCaster)

In diesem Fall müssen Sie verwenden@foreach

@foreach (var item in Model.Foos)
{
    @Html.DisplayFor(x => item, "FooTemplate")
}
Tiberiu Craciun
quelle
Diese Antwort wurde von jemandem geschrieben, der an MVC arbeitet. Ich denke, er weiß, was er sagt. MVC iteriert das IEnumerable<T>und ruft die Vorlage für den Typ Tfür jedes Element auf.
CodeCaster
In Bezug auf Ihre Bearbeitung: Entweder ist Ihr Code falsch oder ein Fehler in dieser bestimmten MVC-Version (in 5.2.2 funktioniert es für mich). Es soll wie in der akzeptierten Antwort beschrieben funktionieren. Anstatt zu sagen, dass es falsch ist, öffnen Sie Ihre eigene Frage zu dem Problem, wenn Sie möchten.
CodeCaster
@CodeCaster Ich glaube, meine Antwort bringt einige Hinweise für diesen speziellen Fall (es hat einen Teil meiner Zeit verschwendet, um herauszufinden, was schief gelaufen ist). Würden Sie bitte eine Erklärung hinzufügen, um die Ablehnung aufrechtzuerhalten? (Danke übrigens für Ihre Zeit, ich möchte nur den Dingen auf den Grund gehen)
Tiberiu Craciun
Ich denke nicht, dass es eine gute Antwort ist, da es den Fehler nicht verifiziert. Dies hilft Gerüchten in der Welt wie "Ein DisplayTemplate kann nicht iterieren" - es soll, also sollte es funktionieren. Wenn dies nicht der Fall ist, melden Sie einen Fehler und öffnen Sie eine separate Frage, in der Sie das Problem reproduzieren und erwähnen, dass diese bestimmte Version im Gegensatz zu Fragen und Antworten, die das behandeln, was normalerweise passieren sollte.
CodeCaster
@CodeCaster Ich hatte inzwischen eine weitere Bearbeitung, nachdem ich meinen speziellen Fall verstanden hatte (ich habe den gesamten Beitrag geändert). In meiner letzten Bearbeitung habe ich die genaue Bedingung angegeben, unter der die akzeptierte Antwort nicht mit einem Backup-Link auf eine relevante Frage zutrifft, die von demselben Mann beantwortet wurde, um zu beweisen, dass dies beabsichtigt und kein Fehler ist.
Tiberiu Craciun