web-dev-qa-db-fra.com

Foreach dans une foreach dans MVC View

BIG EDIT: J'ai édité mon post complet avec la réponse que je suis venu avec l'aide de Von V et Johannes, UN GRAND MERCI GUY !!!!

J'ai essayé de faire une boucle foreach dans une boucle foreach dans ma vue d'index pour afficher mes produits dans un accordéon. Laissez-moi vous montrer comment j'essaie de faire cela.

Voici mes modèles:

public class Product
{
    [Key]
    public int ID { get; set; }

    public int CategoryID { get; set; }

    public string Title { get; set; }

    public string Description { get; set; }

    public string Path { get; set; }

    public virtual Category Category { get; set; }
}

public class Category
{
    [Key]
    public int CategoryID { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

C'est un un un relation un-plusieurs, un produit n'a qu'une catégorie mais une catégorie a plusieurs produits.

Voici ce que j'essaie de faire à mon avis:

@model IEnumerable<MyPersonalProject.Models.Product>   

    <div id="accordion1" style="text-align:justify">
    @foreach (var category in ViewBag.Categories)
    {
        <h3><u>@category.Name</u></h3>

        <div>

            @foreach (var product in Model)
            {
                if (product.CategoryID == category.CategoryID)
                {
                    <table cellpadding="5" cellspacing"5" style="border:1px solid black; width:100%;background-color:White;">
                        <thead>
                            <tr>
                                <th style="background-color:black; color:white;">
                                    @product.Title  
                                    @if (System.Web.Security.UrlAuthorizationModule.CheckUrlAccessForPrincipal("/admin", User, "GET"))
                                    {
                                        @Html.Raw(" - ")  
                                        @Html.ActionLink("Edit", "Edit", new { id = product.ID }, new { style = "background-color:black; color:white !important;" })
                                    }
                                </th>
                            </tr>
                        </thead>

                        <tbody>
                            <tr>
                                <td style="background-color:White;">
                                    @product.Description
                                </td>
                            </tr>
                        </tbody>      
                    </table>                       
                }
            }

        </div>
    }  
</div>

Je ne suis pas tout à fait sûr que ce soit la bonne façon de procéder, mais c'est à peu près ce que j'essaie de faire. Pour chaque catégorie, placez tous les produits de cette catégorie dans un onglet accordéon.

  • catégorie 1
    • produit 1
    • produit 3
  • catégorie 2
    • produit 2
    • produit 4
  • catégorie 3
    • produit 5

Ici, je vais ajouter mon mapping pour mon un un une relation plusieurs (merci Brian P):

public class MyPersonalProjectContext : DbContext
{
    public DbSet<Product> Product { get; set; }
    public DbSet<Category> Category { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<Product>();
        modelBuilder.Entity<Category>();
    }
}

Je vais aussi ajouter mon contrôleur afin que vous puissiez voir comment je l'ai fait:

public ActionResult Index()
    {
        ViewBag.Categories = db.Category.OrderBy(c => c.Name).ToList();
        return View(db.Product.Include(c => c.Category).ToList());
    }

BIG EDIT: J'ai édité mon post complet avec la réponse que je suis venu avec l'aide de Von V et Johannes, UN GRAND MERCI GUY !!!!

7
Guillaume Longtin

En supposant que la méthode d'action de votre contrôleur ressemble à ceci:

public ActionResult AllCategories(int id = 0)
{
    return View(db.Categories.Include(p => p.Products).ToList());
}

Modifiez vos modèles pour qu'ils ressemblent à ceci:

public class Product
{
    [Key]
    public int ID { get; set; }
    public int CategoryID { get; set; }
    //new code
    public virtual Category Category { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string Path { get; set; }

    //remove code below
    //public virtual ICollection<Category> Categories { get; set; }
}

public class Category
{
    [Key]
    public int CategoryID { get; set; }
    public string Name { get; set; }
    //new code
    public virtual ICollection<Product> Products{ get; set; }
}

Ensuite, votre contrôleur depuis prend en compte une catégorie en tant que modèle (au lieu d'un produit):

foreach (var category in Model)
{
    <h3><u>@category.Name</u></h3>
    <div>
        <ul>    
            @foreach (var product in Model.Products)
            {
                // cut for brevity, need to add back more code from original
                <li>@product.Title</li>
            }
        </ul>
    </div>
}

UPDATED: Ajoutez ToList () à la déclaration de retour du contrôleur.

8
Johannes Setiabudi

Tu as:

foreach (var category in Model.Categories)

et alors 

@foreach (var product in Model)

Sur la base de cette vue et de ce modèle, il semble que Model est de type Product si oui, alors la deuxième foreach n'est pas valide. En réalité, le premier pourrait être celui qui est invalide si vous renvoyez une collection de Product

METTRE À JOUR:  

Vous avez raison, je retourne le modèle de type Produit. Aussi, je fais Comprenez ce qui ne va pas maintenant que vous l'avez signalé. Comment suis-je censé faire ce que j'essaie de faire alors si je ne peux pas le faire de cette façon?

Je suis surpris que votre code compile lorsque vous dites que vous retournez un modèle de type Product. Voici comment vous pouvez le faire:

@foreach (var category in Model)
{
    <h3><u>@category.Name</u></h3>

    <div>
        <ul>    
            @foreach (var product in category.Products)
            {
                <li>
                    put the rest of your code
                </li>
            }
        </ul>
    </div>
}

Cela suggère qu'au lieu de renvoyer une Product, vous renvoyez une collection de Category avec Products . Quelque chose comme ça dans EF:

// I am typing it here directly 
// so I'm not sure if this is the correct syntax.
// I assume you know how to do this,
// anyway this should give you an idea.
context.Categories.Include(o=>o.Product)
2
von v.

Essaye ça:

On dirait que vous faites une boucle pour chaque produit à chaque fois, maintenant c'est une boucle pour chaque produit ayant le même ID de catégorie que la catégorie en cours de boucle.

<div id="accordion1" style="text-align:justify">
@using (Html.BeginForm())
{
    foreach (var category in Model.Categories)
    {
        <h3><u>@category.Name</u></h3>

        <div>
            <ul>    
                @foreach (var product in Model.Product.Where(m=> m.CategoryID= category.CategoryID)
                {
                    <li>
                        @product.Title
                        @if (System.Web.Security.UrlAuthorizationModule.CheckUrlAccessForPrincipal("/admin", User, "GET"))
                        {
                            @Html.Raw(" - ")  
                            @Html.ActionLink("Edit", "Edit", new { id = product.ID })
                        }
                        <ul>
                            <li>
                                @product.Description
                            </li>
                        </ul>
                    </li>
                }
            </ul>
        </div>
    }
}  

1
CR41G14

Manette  

public ActionResult Index()
    {


        //you don't need to include the category bc it does it by itself
        //var model = db.Product.Include(c => c.Category).ToList()

        ViewBag.Categories = db.Category.OrderBy(c => c.Name).ToList();
        var model = db.Product.ToList()
        return View(model);
    }


Vue

vous devez filtrer le modèle avec la catégorie donnée

comme: => Model.where (p => p.CategoryID == category.CategoryID)

essaye ça...

@foreach (var category in ViewBag.Categories)
{
    <h3><u>@category.Name</u></h3>

    <div>

        @foreach (var product in Model.where(p=>p.CategoryID == category.CategoryID))
        {

                <table cellpadding="5" cellspacing"5" style="border:1px solid black; width:100%;background-color:White;">
                    <thead>
                        <tr>
                            <th style="background-color:black; color:white;">
                                @product.Title  
                                @if (System.Web.Security.UrlAuthorizationModule.CheckUrlAccessForPrincipal("/admin", User, "GET"))
                                {
                                    @Html.Raw(" - ")  
                                    @Html.ActionLink("Edit", "Edit", new { id = product.ID }, new { style = "background-color:black; color:white !important;" })
                                }
                            </th>
                        </tr>
                    </thead>

                    <tbody>
                        <tr>
                            <td style="background-color:White;">
                                @product.Description
                            </td>
                        </tr>
                    </tbody>      
                </table>                       
            }


    </div>
}  
0
Ad Kahn