Display category once in repeater - c#

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();

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;
}
}
}
}

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.

Related

How Can add I selected value of DropDownList inside a Repeater to the listbox control in ASP.Net

How can I get the value of the selected item inside the repeater object that I filled from the database, again in the dropdownlist object that I filled from the database?
How can I transfer the values ​​of the items I selected from these dropdownlist objects to a listbox?
For example, there are 3 dropdownlists in the repeater. I want to transfer the values ​​selected from these dropdownlists to the listbox when I press the button.
Thank you...
Ilan.aspx
<asp:Repeater ID="rptNitelikler" runat="server" OnItemDataBound="rptNitelikler_ItemDataBound">
<ItemTemplate>
<div class="control-group form-group">
<label class="form-label text-dark"><%#Eval("nitelik") %></label>
<asp:Label ID="id" runat="server" Visible="false" Text='<%#Eval("nid") %>'></asp:Label>
<asp:Label ID="lblItem" Visible="false" runat="server" Text="Label"></asp:Label>
<asp:DropDownList ID="ddl" CssClass="form-control select2-show-search" data-placehodler="Seç" Width="100%" runat="server">
</asp:DropDownList>
</div>
</ItemTemplate>
</asp:Repeater>
Ilan.aspx.cs
private void NitelikGetir()
{
int ana, alt, kat;
ana = int.Parse(Session["AnaId"].ToString());
alt = int.Parse(Session["AltId"].ToString());
kat = int.Parse(Session["KatId"].ToString());
using (BayUniEntities ent = new BayUniEntities())
{
var birlestir = (from nk in ent.NITELIKKATEGORI
join an in ent.ANANITELIKLER
on nk.AnaNitelikId equals an.AnaNitelikId
where nk.AnaKategoriId==ana && nk.AltKategoriId==alt && nk.IlanKategoriId==kat
select new { nitelik=an.AnaNitelik, nid=an.AnaNitelikId }).ToList();
rptNitelikler.DataSource = birlestir;
rptNitelikler.DataBind();
}
}
protected void rptNitelikler_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
int id = Convert.ToInt32(DataBinder.Eval(e.Item.DataItem, "nid"));
DropDownList selectList = e.Item.FindControl("ddl") as DropDownList;
if (e.Item.ItemType==ListItemType.Item || e.Item.ItemType==ListItemType.AlternatingItem)
{
using (BayUniEntities ent = new BayUniEntities())
{
var birlestir = (from an in ent.ALTNITELIKLER
where an.AnaNitelikId == id
select an).ToList();
selectList.DataSource = birlestir;
selectList.DataTextField = "AltNitelik";
selectList.DataValueField = "AltNitelikId";
selectList.DataBind();
}
}
}
To get the selected values from your dropdownlists you need to iterate over the items in the repeater. In your button-handler-code do something like this:
foreach (RepeaterItem repeaterItem in rptNitelikler.Items)
{
DropDownList ddl = (DropDownList)repeaterItem.FindControl("ddl");
if (ddl != null)
{
string selectedValue = ddl.SelectedValue;
// insert code to add value to listbox here.
string selectedText = ddl.SelectedItem.Text;
// Insert code to add Text to listbox here.
}
}

Nested repeater will not display bound information from list

I am trying to get a page to display information in a row layout using repeaters. I have one working that allows me to dynamically create hyperlinks, however i cant get my nested repeater to work to display the date the file was created. Is it possible to use repeaters to dynamically display multiple variables from lists as i'm trying to do below?
.aspx
<asp:Repeater id="repLinks" runat="server">
<ItemTemplate>
<tr><td>
<asp:HyperLink runat="server" NavigateUrl='<%# Container.DataItem.ToString() %>' Text="<%# Container.DataItem.ToString().Split('\\').Last() %>" />
<td>
<asp:Repeater ID="Repeater2" runat="server" OnItemDataBound="Repeater2_ItemDataBound" >
<ItemTemplate>
<%# Container.DataItem.ToString()%>
</ItemTemplate>
</asp:Repeater>
</td>
<td>
Submitted By <!--add repeater-->
</td>
<td>
Mark as Billed <!--add repeater-->
</td>
</td></tr>
</ItemTemplate>
</asp:Repeater>
.aspx.cs
public List<string> CD = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
//Welcomes User
string Uname = Environment.UserName;
UserName.Font.Size = 17;
UserName.Text = "Welcome: " + Uname;
//gives path and constructs lists for directory paths and file links
string root = "C:\\Users\\James\\Documents\\Visual Studio 2015\\WebSites";
List<string> lLinks = new List<string>();
//adds files to list
foreach (var path in Directory.GetDirectories(#root))
{
foreach (var path2 in Directory.GetFiles(path))
{
lLinks.Add(path2);
CD.Add(File.GetCreationTime(path2).Date.ToString("yyyy-mm-dd"));
}
}
//Define your list contents here
repLinks.DataSource = lLinks;
repLinks.DataBind();
}
protected void Repeater2_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater Repeater2 = (Repeater)(e.Item.FindControl("Repeater2"));
Repeater2.DataSource = CD;
Repeater2.DataBind();
}
}
The issue with your code is that you are binding the nested repeater control (Repeater2) in the ItemDataBound event of Repeater2 repeater itself which will never get fired because ItemDataBound event is fired for each item in collection when it is bounded to the repeater control.
You should write the logic in ItemDataBound event of your parent repeater like this:-
<asp:Repeater id="repLinks" runat="server" OnItemDataBound="Repeater1_ItemDataBound">
Then, write the logic in this event handler:-
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater Repeater2 = (Repeater)(e.Item.FindControl("Repeater2"));
Repeater2.DataSource = CD;
Repeater2.DataBind();
}
}
Also, In the Page_Load event you should bind the Parent Repeater Repeater1 on just the initial page load so wrap it inside !IsPostBack and populate your datasource lLinks & CD from a separate method intead of doing it in Page_Load event.

Items are looping all items in Repeater's ItemDataBound event

I have a normal Repeater Control in my aspx page
<asp:Repeater ID="rpt1" runat="server" OnItemDataBound="rpt1_ItemDataBound">
<ItemTemplate>
<asp:CheckBox ID="chks" runat="server" />
<asp:TextBox ID="txtName" runat="server" CssClass="form-control" Text='<%# DataBinder.Eval(Container,"DataItem.Name").ToString()%>'></asp:TextBox><asp:Label ID="lblValue" runat="server" Visible="false" Text='<%# DataBinder.Eval(Container,"DataItem.Id").ToString() %>'></asp:Label>
</ItemTemplate>
</asp:Repeater>
On the button click I'm binding data to the Repeater as
rpt1.DataSource = GetData();
rpt1.DataBind();
After binding the ItemDataBound event is called. In that I'm looping through the repeater items for some manipulations
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
foreach (RepeaterItem item in rpt1.Items)
{
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
string val = ((Label)item.FindControl("lblValue")).Text;
// Some Stuff
}
}
}
The problem is that the loop is getting started from first every time.
For Ex if my data is as 1 2 3 so on.....
It is iterarting as
1
1 2
1 2 3
How can I make it as
1
2
3
What am I doing wrong
ItemDataBound is already called for every item in the repeater, so you don't need a loop there.
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
string val = ((Label)e.Item.FindControl("lblValue")).Text;
// Some Stuff
}
}
Side-Note: that applies to all Data-Bound Web Server Controls.

DataBind dropdownlist and the textbox inside the repeater from the database

I have a textbox and a DropDownList inside a Repeater. And I want to populate values from the database in the TextBox and DropDownList. In PageLoad, I have CategoryList.GetList which is:
SELECT ID, Name, ActiveName, ActiveID
FROM category
I have 10 values in that table and CategoryList.GetList returns a datatable with values something similar to below:
1, 'A', 'Active', 1
2, 'B', 'Active', 1
3, 'C', 'Inactive', 0
4, 'D', 'Active', 1
Now I need to bind the values to the textbox and the DropDownList. Meaning 'A' needs to be in the TextBox and 'Active' in the DropDownList. And I want the DropDownList to have the values as only 'Active' or 'Inactive'. When I run the code below I see the DropDownList contains Active and Inactive multiple times. Can you please help me avoid that and have only unique values in the DropDownList? Thanks
<asp:Repeater ID="rpt" runat="server" OnItemDataBound="ca_temDataBound">
<ItemTemplate>
<tr>
<td style="width: 35%; text-align: left">
<asp:TextBox ID="NameTextBox" runat="server" Width="230px" Text='<%#Eval("CategoryName")%>' />
</td>
<td style="width: 35%; text-align: left">
<asp:DropDownList ID="Active" runat="server" Width="80px" />
</td>
<asp:HiddenField runat="server" Value='<%# Eval("ID") %>' ID="IDHiddenField" />
</tr>
</ItemTemplate>
</asp:Repeater>
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
rpt.ItemDataBound += new RepeaterItemEventHandler(ca_ItemDataBound);
rpt.DataSource = CategoryList.GetList(1, 100); // Gets id, name, activeid and activename (activeid and active name are the text and value fields for dropdownlist )
rpt.DataBind();
}
}
protected void Category_ItemDataBound(object source, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
DropDownList ddl = (DropDownList)e.Item.FindControl("ActiveDropDown");
ddl.DataSource = CategoryList.GetList(1, 100); // Gets id, name, activeid and activename for the dropdownlist
ddl.DataBind();
}
}
public static ReadOnlyCollection<Category> GetList(int pageIndex, int pageSize)
{
DataTable dataTable = CategoryDB.GetData(pageIndex, pageSize);
List<Category> list = new List<Category>();
foreach (DataRow dataRow in dataTable.Rows)
{
list.Add(new Category(
dataRow["categoryID"].ToString(),
dataRow["categoryName"].ToString(),
dataRow["activeID"].ToString(),
dataRow["activeName"].ToString()));
}
return new ReadOnlyCollection<Category>(list);
}
If you want static items inside the DropDownList, you don't have to bind it. So change it to this:
<asp:DropDownList ID="Active" runat="server" Width="80px">
<asp:ListItem Value="1" Text="Active" />
<asp:ListItem Value="0" Text="Inactive" />
</asp:DropDownList>
In code behind change your Category_ItemDataBound method like this:
protected void Category_ItemDataBound(object source, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
Category ct = (Category)e.Item.DataItem;
DropDownList ddl = (DropDownList)e.Item.FindControl("Active");
ddl.SelectedValue = ct.ActiveID.ToString(); // I don't know if this is the right property.
}
}
i think as i got your question:
ok i will explain using a sql query:
"SELECT id, name, activeid,activename FROM categorylist"
so insted of filling the dropdownlist with databind just add:
foreach(var item in CategoryList.GetList(1, 100))
{
dd1.Items.Add(new ListItem("text","Value");
}
get the text and the value from the item.
Or you can use a dataset if you like.
if you want any help with the dataset just send me the database type.
hope it helped

ChildRepeater getting value from ParentRepeater in CodeBehind

What i'm trying to do is this
<asp:Repeater ID="ParentRepeater" runat="server" OnItemDataBound="ItemBound">
<ItemTemplate>
<asp:Repeater ID="Repeater_SideMenu_Guides_Medlem" runat="server">
<ItemTemplate>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Codebehind
ParentRepeater.DataSource = CraftGuides.GetAllGroups();
ParentRepeater.DataBind();
protected void ItemBound(object sender, RepeaterItemEventArgs args)
{
if (args.Item.ItemType == ListItemType.Item)
{
Repeater childRepeater = (Repeater)args.Item.FindControl("ChildRepeater");
childRepeater.DataSource = CraftGuides.GetGuidesByGroupID( Insert ID from Parent Here );
childRepeater.DataBind();
}
}
Now, the thing is I don't know to get the ID from the parent inside the child to collect the data from the database
Providing that you have a Group object, you can use the following:
var item = args.Item;
var dataItem = item.DataItem as Group;
Then you easily grab the id of the group object and pass it into your GetGuidsByGroupID().
I like to use the as keyword since it will return null if the cast fails. Using (Group)item.DataItem would throw an exception if it failed.

Categories