I'm using repeater to create dynamic ul li list
Is it possible to control class whether item is first or last?
Something like:
class="<%# if(Container.ItemIndex == 0)
{
class = ...
}
) %>"
by the way what does it really mean: <%# in ASP.NET
What is the difference between <%# and <%=?
It is quite easy to determine whether the item is first or not (Container.ItemIndex == 0), but to determine whether the element is last or not you have to use a custom property which will be initialized right with data binding:
protected int ItemCount { get; set; }
Here is a repeater example:
<asp:Repeater runat="server" ID="repeater">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li class="<%# GetItemClass(Container.ItemIndex) %>">
<%# Container.DataItem %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
here is an example of data binding:
public override void DataBind()
{
var data = new string[] { "first", "second", "third" };
this.ItemCount = data.Length;
repeater.DataSource = data;
repeater.DataBind();
}
and finally a helper method:
protected string GetItemClass(int itemIndex)
{
if (itemIndex == 0)
return "first";
else if (itemIndex == this.ItemCount - 1)
return "last";
else
return "other";
}
This will produce:
<ul>
<li class="first">
first
</li>
<li class="other">
second
</li>
<li class="last">
third
</li>
</ul>
I typically use something like the following:
<asp:Repeater ID="rptItems" runat="server" ViewStateMode="Disabled">
<ItemTemplate>
<li<%# Container.ItemIndex == ((IList)((Repeater)Container.Parent).DataSource).Count-1 ? " class='last'" : ""%>>
...
</li>
</ItemTemplate>
</asp:Repeater>
If possible, I'd recommend using something like jQuery for this as it makes implementing this type of functionality very easy. For example, you could have something like this:
<asp:Repeater id="MyRepeater" runat="server">
<HeaderTemplate><table class="MyRepeater"></HeaderTemplate>
<FooterTemplate></table></FooterTemplate>
<ItemTemplate><tr><td>My Data</td></tr></ItemTemplate>
</asp:Repeater>
$("table.MyRepeater tr:last").attr("class", "last");
Try somwthing like this, if you are not using jQuery
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:Label ID="Label1" CssClass='<%# Container.ItemIndex == 0 ? "first" : "notFirst" %>' runat="server" Text="Label"></asp:Label>
</ItemTemplate>
</asp:Repeater>
I modified nelsestu's solution and came up with:
<%# Container.ItemIndex == ((System.Data.DataTable)((Repeater)Container.Parent).DataSource).Rows.Count-1 ? "</div>" : string.Empty %>
As for your question on the difference between <%= and <%#, please see the following links:
Code Render Blocks:
http://msdn.microsoft.com/en-us/library/k6xeyd4z(v=vs.71).aspx
Data Binding Expression Syntax:
http://msdn.microsoft.com/en-us/library/bda9bbfx(v=vs.71).aspx
I wasn't able to use Alex's answer directly. Here are the modifications I made that worked for me. Using Alex's "repeater example" for the asp:Repeater tag, use this in the code behind:
private string[] data = new string[] { "first", "second", "third" };
protected int ItemCount { get; set; }
private void Page_Load(object sender, EventArgs e)
{
// normally one would fetch the data here right before binding like this:
// data = SomeService.SomeMethodToGetData();
repeater.DataSource = data;
repeater.DataBind();
}
public override void DataBind()
{
ItemCount = data.Count();
}
protected string GetItemClass(int itemIndex)
{
if (itemIndex == 0)
return "first";
else if (itemIndex == this.ItemCount - 1)
return "last";
else
return "other";
}
I usually do it like this for the last item
Public m_recordCount As Integer
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
ltrlTitle.Text = m_title
Using Context As New MyEntities
Dim m_lst = Context.getHotRecords(m_location).ToList
m_recordCount = m_lst.count()
rptListings.DataSource = m_lst
rptListings.DataBind()
End Using
End Sub
and here is how I use it in HTML markup
<div <%# IIf(m_recordCount - 1 = Container.ItemIndex, "class='clearBorder'", "")%>>
For those needing this in VB, here's what works for me.
<span runat="server" class='divider'
Visible="<%# Container.ItemIndex < DirectCast(DirectCast(Container.Parent,Repeater).DataSource,List(Of IList)).Count()-1 %>">|</span>
I needed a divider to show for all items except for the last one.
If your are using controls within your ItemTemplate you can do something like the following, add OnItemDataBound event.
<asp:Repeater ID="RptId" runat="server" OnItemDataBound="OnItemDataBound">
<ItemTemplate>
<asp:Panel runat="server" ID="PnlCtrlItem">
<%#Eval("Content") %>
</asp:Panel>
</ItemTemplate>
</asp:Repeater>
protected void OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemIndex == 0)
((Panel) e.Item.FindControl("PnlCtrlItem")).CssClass = "first";
//or the following to have your control indexed
((Panel) e.Item.FindControl("PnlCtrlItem")).CssClass = string.Format("item-{0}",e.Item.ItemIndex);
}
Related
I've been stuck for the last two hours and need help. I've tried every single example I could find online and none of them work. I'm building a web page in ASP.NET and want to make a list of buttons. Doesn't seem too hard right? It's been causing me issues though.
This is my code:
<ul>
<form id="tagloop" runat="server">
<% foreach (string i in data)%>
<%Response.Write("<li><button runat=\"server\" type=\"submit\" onserverclick=\"ClickTag\">" + i + "</button></li>");%>
</form>
</ul>
If I remove the Response.Write() it only loops once but the one button it does generate actually works and calls the method on click. Also, the variable i doesn't apply.
<ul>
<form id="tagloop" runat="server">
<% foreach (string i in data)%>
<li><button runat="server" type="submit" onserverclick="ClickTag"> i </button></li>
</form>
</ul>
Is there anyway I can get it to loop, have the text of i in data, and also call the correct function on click? I haven't been able to find a balance of all three yet and any help will be appreciated.
If you want to create server side controls, you're better off using an asp:Repeater:
<asp:Repeater runat="server" ID="Repeater1" OnItemCommand="Repeater1_ItemCommand">
<ItemTemplate>
<li>
<asp:Button runat="server" ID="RepeaterButton" Text="<%# Container.DataItem %>" OnClick="RepeaterButton_Click"/>
</li>
</ItemTemplate>
</asp:Repeater>
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack) return;
var data = new List<string> { "Test1", "Test2", "Test3", "Test4" };
Repeater1.DataSource = data;
Repeater1.DataBind();
}
You have to write a bit more code, but you avoid adding to much logic into your markup and do not have to use Response.Write, which is prone to errors and typos.
You can even do this with strongly typed objects!
Let's assume you have a person class:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
And you have a method in your .cs file that returns a list of Persons:
IEnumerable<Person> Persons()
{
for (int i = 0; i < 10; i++)
{
yield return new Person { FirstName = $"Foo{i}", LastName = $"Bar{i}" };
}
}
You can then reference your object properties in your repeater control:
<asp:Repeater runat="server" ID="Repeater1" ItemType="WebFormsSandbox.Person">
<ItemTemplate>
<li>
<asp:Button runat="server" ID="RepeaterButton" Text="<%#: Item.FirstName %> <%#: Item.LastName %>" OnClick="RepeaterButton_Click"/>
</li>
</ItemTemplate>
</asp:Repeater>
Reference: https://msdn.microsoft.com/en-us/library/x8f2zez5(v=vs.100).aspx
Something like this?
<form id="tagloop" runat="server">
<%
List<int> data = new List<int>();
data.Add(1);
data.Add(2); %>
<% foreach (int i in data)%>
<%Response.Write("<li><button runat=\"server\"
type=\"submit\"onclick=\"ClickTag\">" + i + "</button></li>");%>
</form>
I'm trying to create a blog page using a ListView. I am creating a reply function which adds a other css style to the listview when the message contains a parentmessageid.
This is working. Now I need to change the order of the message so the reply message will be placed under the parentmessage. Below you will find my implementation:
Function for datasource to fill the Listview:
protected void LoadMessages(int userid)
{
Bericht berichten = new Bericht();
if (berichten.LaadBerichten(userid).Tables.Count > 0)
{
ListViewMessages.DataSource = berichten.LaadBerichten(userid);
ListViewMessages.DataBind();
}
}
Function to add css style on items where LabelMessageID contains a value:
protected void ListItemMessages_Load(object sender, EventArgs e)
{
HtmlGenericControl li = (HtmlGenericControl)sender;
ListViewItem container = (ListViewItem)li.NamingContainer;
Label LabelParentMessageID = (Label)container.FindControl("LabelParentMessageID");
if (LabelParentMessageID.Text != string.Empty)
{
li.Attributes.Add("class", "reply");
}
}
ASP.NET ListView Source:
<asp:ListView ID="ListViewMessages" runat="server">
<ItemTemplate>
<li id="ListItemMessages" runat="server" onload="ListItemMessages_Load">
<img src="<%# Eval("[imagelocation]")%>" alt="image" />
<div class="top-pointer"></div>
<div class="pointer"></div>
<!--Hidden Controls-->
<asp:Label ID="LabelMessageID" runat="server" Text='<%# Eval("[messageid]")%>' Visible="false"></asp:Label>
<asp:Label ID="LabelParentMessageID" runat="server" Text='<%# Eval("[parentmessageid]")%>' Visible="false"/>
</li>
</ItemTemplate>
</asp:ListView>
Can someone help me out with changing the order of the items? Because I have no idea how to accomplish this.
try something like ds.Tables[0].DefaultView.Sort = "SortField DESC";
Solved using a SQL stored procedure.
Here is the deal,
I got a list of documents which is generated by the repeater and his databinding. In my markup i got a class for "li" tag when active or not.
What i just need is to set class="active" on the Li parent tag of my linkbutton when the document is selected.
<asp:Repeater ID="Repeater1" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:LinkButton ID="lnk" runat="server" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "Id") %>' OnCommand="Get_carte"><%# Container.FindControl("lnk").ClientID %> <%# DataBinder.Eval(Container.DataItem, "Name") %> - <%# DataBinder.Eval(Container.DataItem, "id") %> - <%# DataBinder.Eval(Container.DataItem, "compteur") %></asp:LinkButton></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
I've finally found a solution for my issue.
#Kapil : Your code works but got issue with the reload of the aspx page, then i can't use this method.
#Aghilas : I based my solution on your code.
In fact i can't use ItemDataBound event because i bind only 1 time my repeater, then i use my OnCommand event on the linkbutton. Here is my aspx code:
<asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Rpt_DataBound">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li runat="server" ID="li">
<asp:LinkButton ID="lnk" class="linkButton" runat="server" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "Id") %>' OnCommand="Get_carte"><%# Container.FindControl("lnk").ClientID %> <%# DataBinder.Eval(Container.DataItem, "Name") %> - <%# DataBinder.Eval(Container.DataItem, "id") %> - <%# DataBinder.Eval(Container.DataItem, "compteur") %></asp:LinkButton></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
And my GetCarte Method:
protected void Get_carte(object sender, CommandEventArgs e)
{
LinkButton lnk = (LinkButton)sender;
ViewState["liactive"] = lnk.UniqueID.ToString().Substring(0, lnk.UniqueID.ToString().Length - 4);
lbl_carte.Text = lnk.UniqueID + " " + e.CommandArgument.ToString();
foreach (RepeaterItem rI in Repeater1.Items)
{
if (rI.ItemType == ListItemType.Item || rI.ItemType == ListItemType.AlternatingItem)
{
string liactiv = "";
if (ViewState["liactive"] != null)
liactiv = ViewState["liactive"].ToString();
var li = (HtmlControl)rI.FindControl("li");
if (li.UniqueID.ToString().Substring(0, li.UniqueID.ToString().Length - 3) == liactiv) //Adjust your condition
li.Attributes.Add("class", "active");
else
li.Attributes.Remove("class");
}
}
}
Thanks for your help.
PS: I put ID in ViewState in case of needing the value in another part of my code. I also can replace my substring by lastindexof method.
Code Behind - C# :
You can add runat="server" and id="" to your li, in order to modify in your code behind
void Repeater_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var li = (HtmlControl)e.Item.FindControl("IdOfYourLI");
if(condition) //Adjust your condition
{
li.Attributes.Add("class", "active");
}
}
}
You can also modify with JavaScript :
You add to element id and use GetElementById method
youIdOfControlLI.className = 'active';
Using jQuery:
jsFiddle working link
Set class="linkButton" to you LinkButtons.
<asp:LinkButton ID="lnk" class="linkButton" />
Use the following jQuery Code to to set the Class on the li:
$(function () {
$(".linkButton").each(function (index) {
$(this).on("click", function () {
$(".linkButton").each(function (index) {
$(this).closest("li").removeClass("active");
});
$(this).closest("li").addClass("active");
});
});
});
I used repeater in asp.net. My problem is don't know how to hide a fields in repeater. There is a regular price and now price if regular price is equal to zero it will hide the fields and if not it will show the value of the regular price. i hope you can help on this.
here my code in asp:
<a href="<%=Utility.GetSiteRoot() %>/BookInfo.aspx?SKU=<%# Utility.SKUMask(Eval("lb_sku").ToString()) %>">
<img width="150px" src='<%# Eval("lb_picturepath")%>'>
</td>
<td valign="top">
<asp:Label ID="lb_titleLabel" runat="server" CssClass="center-head" Text='<%# Eval("lb_title") %>' />
<p><asp:Label ID="lb_descriptionLabel" runat="server" Text='<%# Eval("lb_description") %>' /></p>
<div class="price"><%# "Price: " + decimal.Round((decimal)Eval("lb_sellingprice"),2)%></div>
</td>
</tr>
<tr>
<td></td>
<td>
<a class="addtocart" href="<%=Utility.GetSiteRoot() %>/AddToCart.aspx?SKU=<%# Utility.SKUMask(Eval("lb_sku").ToString()) %>" >Add To Cart</a>
<a href="<%=Utility.GetSiteRoot() %>/BookInfo.aspx?SKU=<%# Utility.SKUMask(Eval("lb_sku").ToString()) %>" class="readmore">
View Details
</a></td>
thanks!
You would need to handle the OnItemDataBound event, and then change the visibility of the control. An example of this is shown below:
ASPX Page
<asp:Repeater ID="MyRepeater" OnItemDataBound="MyRepeater_OnItemDataBound" runat="server">
<ItemTemplate>
<asp:Label ID="RegularPriceLabel" runat="server" />
<br/>
<asp:Label ID="BuyNowPriceLabel" runat="server" />
</ItemTemplate>
</asp:Repeater>
Code Behind
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
MyRepeater.DataSource = GetDataSource();
MyRepeater.DataBind();
}
}
protected void MyRepeater_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
// This will be your data object
MyEntity o = (MyEntity) e.Item.DataItem;
// Get the labels
Label RegularPriceLabel = (Label) e.Item.FindControl("RegularPriceLabel");
Label BuyNowPriceLabel = (Label) e.Item.FindControl("BuyNowPriceLabel");
// Only show regular price if it is set
RegularPriceLabel.Visible = (o.RegularPrice > 0);
// Populate labels
RegularPriceLabel.Text = o.RegularPrice.ToString();
BuyNowPriceLabel.Text = o.BuyNowPrice.ToString();
}
}
I would take a look at the ItemDataBound event of the Repeater. It will fire for every item in the repeater and allow you to do any code-behind (like hiding labels) more easily.
Edit: For your specific example, since you are formatting the price as well, it may be easier to just call a custom method to to render the price, like so:
ASPX:
<%#RenderPrice((decimal)Eval("lb_sellingprice"))%>
Method:
protected string RenderPrice(decimal price) {
if (price > 0) {
return "Price: $" + decimal.Round(price);
} else {
return string.Empty;
}
}
It's quick-and-dirty but it works.
aspx file
<ul>
<asp:Repeater runat="server" ID="rpt1" OnItemDataBound="rpt1_ItemDataBound">
<HeaderTemplate>
<li><a id="a1" href="javascript:void(0);" runat="server">Text</a></li>
</HeaderTemplate>
<ItemTemplate>
<li><a id="name" runat="server" href="javascript:void(0);">
<%# Eval("Name").ToString() %></a>
<asp:Label runat="server" ID="lblID" Visible="false" Text='<%#Eval("ID") %>'></asp:Label>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
Now there are five items in the ItemTemplate of this repeater..what i want is to set class of each of the anchor tags as "mySprite id1,mySprite id2 , mySprite id3 and so on.."
for that I did this in code behind...
for (int i = 1; i < 6; i++)
{
Name.Attributes.Add("class", "sprite id" + i);
}
Now when I view page source, ALL my anchor tags have got class set as class="sprite id5"
what am I doing wrong ? Plz help..thnx
Try something like this in your OnItemDataBound event handler:
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
HtmlAnchor nameAnchor = (HtmlAnchor)e.Item.FindControl("name");
nameAnchor.Attributes.Add("class", "sprite id" + (e.Item.ItemIndex + 1));
}
}
At the end of the for loop, Name has the value "id5". The for loop in code behind is evaluated first, then the end result value of "id5" is bound to the repeater (5 times).
Since the <asp:Repeater> is designed to display data from a DataSource, you could add the class names "id1, id2, id3, id4, id5, etc." to each row of your data, and bind that field to the class name.
Or, unless you are using GUIDs, you can Concat() the id field of the table to "id"