Rendering list of items inside bootstrap Grid correctly.
The bootstrap Grid system is heavily used to showcase products or items using rows and columns in the form of an image gallery. For static values using bootstrap Grid system is a piece of cake, but rendering a list of items inside a bootstrap Grid is always a challenge for beginners because the bootstrap Grid system consists of 12 columns, this means if you have to display 4 items in a row then you will need to close the row after rendering 4 columns and start a new row.
Beginners handle this scenario very immaturely as shown below.
@model IEnumerable<ProjectName.Models.Product >
@{
ViewBag.Title = "Product Page";
int counter = 0;
}
<div class="row">
@foreach (var product in Model)
{
if (counter != 0 && counter % 3 == 0)
{
@:</div>
@:<div class="row">
}<div class="col-md-3"> @*4 columns in each row*@ @*card design*@
<div class="card">
<img class="card-img-top img-fluid" src="@product.thumbnailUrl" alt="@product.Name">
<div class="card-body">
<h5 class="card-title text-center">@product.Name</h5>
<p class="card-text text-center">@product.price</p>
<a href="#" class="btn btn-primary btn-block">Buy now</a>
</div>
</div> @*end here*@
</div>
counter++;
}
</div>
Why is the above code bad?
Although the above code works as expected but is a very bad programming practice because the view is for pure Html and we should never write any type of logic inside it. It doesn’t matter the logic is purely presentation logic or business-specific logic. The point is, the requirement may change at any moment of time, today you are rendering 4 items in a Row, tomorrow the requirement may change to display 3 items in a row, in that case, you will have to change the whole user interface, thus it makes maintenance a little tough, also any type of logic in the view makes the rendering slower which is bad for SEO perspective, remember page speed is a key factor for Google ranking.
What is the solution?
If you want to display 4 items in a row then you will have to divide the list into groups, each group having 4 items. Similarly, if you have to display 3 items in a row then you will have to divide the List into groups having 3 items in each group. In short, to display n-items in a Row, we will have to divide the list into groups, where each group will have n-items. So the key is to divide a List into a List of List where each List will have n items. For this we can either use Group By or Skip() and Take () Linq operators.
As we will need this Logic in multiple projects, so better is to create a class library project and create an Extension method for the same.
What is an extension method?
Extension methods are used to add methods to an existing type without touching the actual class or recompiling them, for example, List is an existing .net class and we can’t add methods to this class directly, but we can easily extend the class by simply creating an extension method on this.
There are there 3 simple steps to create an extension method.
Step 1. Mark the class as static.
public static class ListExtension
{
}
Step 2.Mark the method as static.
public static IEnumerable<IEnumerable<T>> Split<T>()
{
}
Step 3.Pass the type which you have to extend as the first parameter to method prefix with ‘this’ keyword.
public static class ListExtension
{
public static IEnumerable<IEnumerable<T>> Split<T>(this List<T> list, int size)
{
}
}
The complete extension method is shown below.
public static class ListExtension
{
public static IEnumerable<IEnumerable<T>> Split<T>(this List<T> list, int size)
{
for (var i = 0; i < list.Count() / size; i++)
{
yield return list.Skip(i * size).Take(size);
}
}
}
Example: Display 3 products in each row using Bootstrap Grid system.
Step 1. Create a Model as shown below.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal price { get; set; }
public string thumbnailUrl { get; set; }
}
Step 2. Create an Action Method that exposes a view with a List of products.
public ActionResult GetProduct()
{
List<Product> productList = new List<Product>()
{
new Product(){Id=1,Name="product1",price=200,thumbnailUrl="/img/boot2.PNG"},
new Product(){Id=2,Name="product2",price=300,thumbnailUrl="/img/boot3.PNG"},
new Product(){Id=3,Name="product3",price=400,thumbnailUrl="/img/boot4.PNG"},
new Product(){Id=4,Name="product4",price=500,thumbnailUrl="/img/boot5.PNG"},
new Product(){Id=5,Name="product5",price=600,thumbnailUrl="/img/boot6.PNG"},
new Product(){Id=6,Name="product6",price=700,thumbnailUrl="/img/boot7.PNG"},
new Product(){Id=7,Name="product7",price=500,thumbnailUrl="/img/boot2.PNG"},
new Product(){Id=8,Name="product8",price=800,thumbnailUrl="/img/boot3.PNG"},
new Product(){Id=9,Name="product9",price=900,thumbnailUrl="/img/boot4.PNG"},
};
return View(productList);
}
Step3. Import the extension method in the view using the “using” statement and use the bootstrap Grid as usual.
@{
Layout = null;
}
<!DOCTYPE html>
@using jquery.Extensions
@model IEnumerable<jquery.Models.Product>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>GetProduct</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-
Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
@foreach (var group in Model.Split(3))
{
<div class="row mt-2">
@foreach (var product in group)
{ <div class="col-md-4"> @*3 columns in each row*@ @*card design*@
<div class="card">
<img class="card-img-top img-fluid" src="@product.thumbnailUrl" alt="@product.Name">
<div class="card-body">
<h5 class="card-title text-center">@product.Name</h5>
<p class="card-text text-center">@product.price</p>
<a href="#" class="btn btn-primary btn-block">Buy now</a>
</div>
</div> @*end here*@
</div>
}
</div>
}
</div>
</body>
</html>
Now, run the application, you will happily get three columns in each row. Learn Asp.Net MVC here.
references: https://www.sharpencode.com/