Reputation: 2227
I have a repeater wanting to display Categories and products. Category should appear once and products would appear the number of products i have. Below is my markup
<asp:Repeater ID="rpt1" runat="server" OnItemDataBound="rpt1_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblCategory" runat="server"></asp:Label>
<asp:Label ID="lblProductName" runat="server"></asp:Label>
</ItemTemplate>
</asp:Repeater>
I bind the products at page load
if (!Page.IsPostBack)
{
LoadData();
}
My codebehind
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Product p = (Product)e.Item.DataItem;
Label lblCategory = e.Item.FindControl("lblCategory") as Label;
Label lblProductName = e.Item.FindControl("lblProductName") as Label;
lblProductName.Text = p.ProductName;
lblCategory.Text = p.Category.CategoryName;
}
}
Everything works but my category text is repeated more than once (its shown the number of products i have). How could i display the category just once?
Edit
Cat 20 is Stationery
Cat 30 is Computer Items
Cat 40 is Toiletry
**Id CatId ProductName**
1 20 Pencil
1 20 Pen
1 30 Compact Disc
1 30 USB
1 30 Hard drive
1 40 Toothpaste
1 40 Toothbrush
I get my data in an
Iqueryable<Product> LoadData = myContext.GetProducts();
Upvotes: 0
Views: 509
Reputation: 5380
I think using nested repeater would be better in that case. I mean first repeater for Categories
and the nested repeater for Products
of it's category. See: Nested repeater.
<asp:Repeater runat="server" id="Categories">
<ItemTemplate>
Category: <%# Eval("CategoryName") %>
Products:
<asp:Repeater runat="server" DataSource='<%# Eval("Products") %>'>
<ItemTemplate><%# Eval("ProductName") %></ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
But to do this you need to work on data model a bit, your model should be like this:
public class Category
{
public string CategoryName {get; set;}
public IEnumerable<Product> Products {get; set;}
}
public class Product
{
public string ProductName {get; set;}
}
Or dirty-quick solution is that by comparing category name to previous row for each repeater item. If category name is changed then display new category name, otherwise set empty:
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Product p = (Product)e.Item.DataItem;
Label lblCategory = e.Item.FindControl("lblCategory") as Label;
Label lblProductName = e.Item.FindControl("lblProductName") as Label;
lblProductName.Text = p.ProductName;
if(e.Item.ItemIndex > 0)
{
RepeaterItem previousRepeaterItem = rpt1.Items[e.Item.ItemIndex - 1];
var previousCategoryName = (previousRepeaterItem.FindControl("lblCategory") as Label).Text;
if(previousCategoryName != p.Category.CategoryName)
{
lblCategory.Text = p.Category.CategoryName;
}
}
}
}
Upvotes: 2
Reputation: 4587
I am not sure about the complexity of the product data that you wish to display. Yet I would like to suggest you using the nested Repeaters
, one repeater will have category name and the second would have the products. On Page_Load
, you should fetch all distinct categories and bind the first repeater And on ItemDataBound
of first repeater you must fetch products relevant to the category and bind the nested repeater.
e.g:
<asp:Repeater ID="rpt1" runat="server" OnItemDataBound="rpt1_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblCategory" runat="server" Text='<%# Eval("Category") %>'></asp:Label>
<asp:Repeater ID="rpt2" runat="server">
<ItemTemplate>
<asp:Label ID="lblProductName" runat="server" Text='<%# Eval("ProductName")%>'></asp:Label>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Page Load:
protected void Page_Load(object s, EventArgs e)
{
// Fetch All the Categories, Distinct Elements
DataTable dt = new DataTable();
dt.Columns.Add("Category");
dt.Rows.Add("Sanatizers");
dt.Rows.Add("Soaps");
rpt1.DataSource = dt;
rpt1.DataBind();
}
Item Data Bound:
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lblCategory = (Label)e.Item.FindControl("lblCategory");
Repeater rpt2 = (Repeater)e.Item.FindControl("rpt2");
if (lblCategory != null)
{
// Fetch products by category
var dt = new DataTable();
dt.Columns.Add("ProductName");
dt.Rows.Add("Dettol");
dt.Rows.Add("Safeguard");
dt.Rows.Add("Fair and Lovely");
rpt2.DataSource = dt;
rpt2.DataBind();
}
}
}
PS: The code is not tested, it might need some love.
Upvotes: 0