loop of buttons ASP.NET - c#

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>

Related

Add <li> to <ul> tag from code behind C# ASP NET

well how the title says, how can I add various <li> tags to a <ul> tag from code behind. I tried this Add to List from codebehind C# Asp.net this is my example code.
ASP
<body>
<form id="form1" runat="server">
<div>
<ul id="menu" runat="server"> </ul>
</div>
</form>
And code behind.
protected void Page_Load(object sender, EventArgs e)
{
CreateMenu();
}
protected void CreateMenu()
{
HtmlGenericControl li = new HtmlGenericControl("li");
menu.Controls.Add(li);
HtmlGenericControl anchor = new HtmlGenericControl("a");
anchor.Attributes.Add("href", "login.aspx");
anchor.InnerText = "login";
li.Controls.Add(anchor);
}
Well it works perfectly but maybe this gonna be a dumb question, how can I add more than one element to the <ul> tag? I need to create an new object for each item (I think this is wrong) or exist a better way to do this?
I searched but any example satisfies my doubt, sorry if you think is a repeated question.
If your datas(menu items) are not coming from a source(something like database), you need to repeat the same process over and over again unfortunately. Or you can create a function which is taking 2 parameters, text and link. This way you can do this job with 1 line.
private void AddMenuItem(string text, string link)
{
HtmlGenericControl li = new HtmlGenericControl("li");
menu.Controls.Add(li);
HtmlGenericControl anchor = new HtmlGenericControl("a");
anchor.Attributes.Add("href", link);
anchor.InnerText = text;
li.Controls.Add(anchor);
}
AddMenuItem("text","link");
AddMenuItem("text2","link2");
AddMenuItem("text3","link3");
You can improve this for your specific needs.
You can use ListView. It's easier format. I also found a good tutorial about it (http://weblogs.asp.net/scottgu/the-asp-listview-control-part-1-building-a-product-listing-page-with-clean-css-ui)
<asp:ListView ID="ListView1" runat="server">
<LayoutTemplate>
<ul>
<asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<div>
<p class="name"><%# Eval("author") %></p>
<p class="date"><%# Eval("insertDate") %></p>
</div>
<p class="comment"><span class="<%# Eval("icon") %>"></span><%# HttpUtility.HtmlEncode(Eval("comment")) %></p>
</li>
</ItemTemplate>
</asp:ListView>

Change order of listview based on Control inside listviewitem

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.

How to show/hide a nested list using JavaScript in ASP.NET?

Edit: Found the solution, and posted the answer below.
In my ASP.NET c# project, I have a ListView (ParentList) bound to a DataSource. Within the ParentList, inside the ItemTemplate, I have another Repeater (ChildList) bound to an attribute of each ListViewDataItem.
<asp:ListView ID="ParentList" runat="server" DataSourceID="objectDataSourceID" DataKeyNames="ID">
<ItemTemplate>
<tr>
<td>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("Attribute1") %>' />
</td>
<td valign="top">
<asp:Repeater ID="ChildList" runat="server" DataSource='<%# Eval("Attribute2ReturnsAnotherList") %>'>
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%# DataBinder.Eval(Container.DataItem, "childAttribute") %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
...
</LayoutTemplate>
</asp:ListView>
The code above works just fine, everything renders great. Now I want to add a link that will show/hide the ChildList. Something like the below:
<td valign="top">
<a href="javascript:ToggleListVisibility()" >Show/Hide</a>
<asp:Repeater ID="ChildList" runat="server" DataSource='<%# Eval("Attribute2ReturnsAnotherList") %>'>
</asp:Repeater>
</td>
How can I achieve this? I can't just use getElementById as I normally would, as the ul lists are within a Repeater nested inside the ListView. I tried obtaining the parentNode, then accessing the children and toggling the visibility of the ul element within:
function ToggleListVisibility(source) {
var childrenlist = source.parentNode.children;
for (var i = 0; i < childrenlist.length; i++) {
if (childrenlist[i].tagName == 'ul') {
if (childrenlist.style.display == "none") {
childrenlist.style.display = "block";
} else {
childrenlist.style.display = "none";
}
}
}
}
<a href="javascript:ToggleListVisibility(this)" >Show/Hide</a>
but that didn't work. IE's 'error on page' gave me this error:
The parentNode is null or not an object.
I also tried setting the a runat="server" attribute to my ul element, then using <%# ulID.ClientID %> to pass the ul id to the Js function, but visual studio complained:
Server elements cannot span templates.
Finally, I tried just passing the ul object into the Js function, like this:
function ToggleListVisibility(src) {
if (src.style.display == "none") {
src.style.display = "block";
} else {
src.style.display = "none";
}
}
<a href="javascript:ToggleListVisibility(ulID)" >Show/Hide</a>
...
<ul id="ulID">
which works, but it toggles the visibility for the ChildList in all rows within my ParentList. I want it to only toggle the visibility for the ChildList in its own row.
I'm at a loss of what to do. JavaScript is not my forte, and I would appreciate if someone can provide some pointers. Thanks in advance.
Ok hopefully this will get you going - it worked for me in hiding a list. My source HTML looks like this:
<table>
<tbody>
...
<tr>
<td>
Hide
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
</td>
</tr>
...
</tbody>
</table>
<script type="text/javascript">
function toggleListVisibility(src) {
var childrenList = src.nextSibling.nextSibling;
childrenList.style.display = "none";
}
</script>
Note I had to use two "nextSibling"'s due to a text node that is created right after the "hide" anchor. Depending on how you structure your HTML, that bit will be different.
I found the painfully simple answer that makes me feel like a doofus. All I needed to do is wrap my Repeater in a <div> element, then show/hide the entire thing.
<a href="javascript:ToggleListVisibility('<%# Container.FindControl("divWrapper").ClientID %>')" >Show/Hide</a>
<div id="divWrapper" runat="server">
<asp:Repeater ID="ChildList" runat="server">
</asp:Repeater>
</div>
function ToggleListVisibility(id) {
var wrapper = document.getElementById(id);
if (wrapper.style.display == "none") {
wrapper.style.display = "block";
} else {
wrapper.style.display = "none";
}
}
Hooray for overthinking!

jQuery star rating and binding with repeater control

I am binding the star rating jQuery in a repeater control.
The rating value is taken from the database.The issue which I face is,the repeater control displays only the last rating value from database.
I tried by the method given here Turn a number into star rating display using jQuery and CSS
jQuery added to the example:
$(document).ready(function () {
$('#chk').click(function () {
$('input[type=hidden]').each(function () {
var hiddenValue = $(this).val();
document.getElementById('span1').html = hiddenValue;
$("#span1").text(hiddenValue);
});
My design code is:
<asp:repeater id="RepDetails" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
Rating:<td align="left">
<span class="stars" id="span1"></span>
</td>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%#Eval("Rating") %>' />
<a id="chk">Click</a>
</td>
</ItemTemplate>
<FooterTemplate>
</FooterTemplate>
</asp:repeater>
Code file
protected void Page_Load(object sender, EventArgs e)
{
partnerid = "1";
productid = "2";
DataSet ds = ServiceObj.GetComments(partnerid, productid);
RepDetails.DataSource = ds.Tables[0];
RepDetails.DataBind();
}
Any suggestions to bind the rating for each value from database?
At first look you have one error which can be responsible for your problem:
$("#span1").text(hiddenValue);
If I'm right your jQuery selector will find DOM element with ID, which means that only one element should be found. Thus you have propably only last #span1 found in jQuery. Try change this to another selector for example:
$(".aClass").text(hiddenValue);
$(this).find('input[type="hidden"]').text(hiddenValue);

Change repeater li item class if first or last

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

Categories

Resources