is it wrong to use a repeater within a repeater? - c#

I have a list of parents, that have children. I am trying to output this on my website doing the following. It works, but is it right? What is the best alternative?
<ul id="example">
<asp:Repeater ID="monkey" runat="server" >
<ItemTemplate>
<li>
<span class="folder">
<%# GetPlantName((string)Container.DataItem) %>
</span>
<ul>
<asp:Repeater id="moo" runat="server" DataSource="<%# GetTagList((string)Container.DataItem) %>">
<ItemTemplate>
<li>
<asp:LinkButton ID="d" runat="server" Text='<%# Eval("ReportNo")%>'></asp:LinkButton>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>

Nested repeaters are acceptable. Just be careful with things like RowDataBound events. It's not always obvious, especially to junior developers, that these methods are essentially nested loops. I've seen mistakes like a trip to the database in the nested repeater, which results in a lot of overhead.
Just keep in mind that what you're doing is essentially a nested loop and design code accordingly and it's perfectly fine.

I hope no
I have a repeater in a repeater in a repeater in a repeater in something :-p

No, it is not wrong! On the contrary, it is what we have to do more often than not.
Sometimes there are better solutions but that always depends on the requirements.
hth,
\ ^ / i l l

I see nothing wrong here at all. You have a list (repeater 1) with a nested list (repeater 2).

Is it wrong? No. It's only 'wrong' (and that's basically a pseudonym for inefficient) if you plan on doing something with a repeater that could be done easier with something else.

Related

Access a control in Codebehind that's in a Template

In my ASP.NET WebForms application using Scafolding I have many pages where I need to restrict certain links based on user's role.
For instance, in my Site.Master in my <LoggedTemplate> along with other <li>, I have a <li> for Admin page also. By default, that is not visible, but if the user is logged as an Admin, then I want it to make visible. Which I am not able to do. Here's the code for it :
<LoggedInTemplate>
<ul class="nav navbar-nav">
<li><a runat="server" id="adminLink" visible="false" href="~/Admin/Admin_Page">Admin</a></li>
<li><a runat="server" href="~/Inquiries/Default.aspx">Inquiry</a></li>
In my Codebehind, in Page_Load I am not able to access adminLink only.
Simialrly, in one of the Default page of a Model, the list has links to View, Insert & Delete. If the user is admin, then only I want to show Insert & Delete links. Here's the code for it :
<td>
<asp:HyperLink runat="server" NavigateUrl='<%# FriendlyUrl.Href("~/Channels/Details", Item.ChannelId) %>' Text="View" /> |
<asp:HyperLink runat="server" ID="editLink" NavigateUrl='<%# FriendlyUrl.Href("~/Channels/Edit", Item.ChannelId) %>' Text="Edit" /> |
<asp:HyperLink runat="server" NavigateUrl='<%# FriendlyUrl.Href("~/Channels/Delete", Item.ChannelId) %>' Text="Delete" />
</td>
</tr>
</ItemTemplate>
I tried adding
<% if (CommonUtilities.IsUserAdmin) { %>
hyperlinks for Insert & delete & finally
<% } %>
but this was giving error. I added ID to editLink, but again cannot access it in Page_Load method.
I am sure, their must be some method to work out with this which I am not able to find yet.
How to deal with this problem ?? Please help me, I have several pages & links to hide & show based on admin role.
Any help is highly appreciated.
Thanks
I think you are looking for FindControl. For example:
Label adminLabel = LoggedInTemplate.FindControl("adminLink") as Label;
adminLabel.visible = true;
Works for me in a few templates, dont know about LoggedInTemplate tho, but can't see why not.
edit: didn't realize ur using <a>. Not sure why you mix asp hyperlink and html but anyway, logic is still the same.
Thanks WEDEBE for pointing out to mix <a> and .
That point gave me a way out. In my design, I change <a> to <asp:HyperLink> & removed code from Codebehind. In design only I tried checking hte role of user & then adding full <li>. Like this :
<LoggedInTemplate>
<ul class="nav navbar-nav">
<% if (VincitoreCRMApplication.CommonUtilities.IsCurrentUserAdmin)
{ %>
<li> <asp:HyperLink runat="server" id="adminLink" NavigateUrl="~/Admin/Admin_Page.aspx">Admin</asp:HyperLink> </li>
<% } %>
<li><a runat="server" href="~/Inquiries/Default.aspx">Inquiry</a></li>
With the other 2 HyperLink's also I did the same way :
<% if (VincitoreCRMApplication.CommonUtilities.IsCurrentUserAdmin)
{ %>
<asp:HyperLink runat="server" ID="editLink" NavigateUrl='<%# FriendlyUrl.Href("~/Channels/Edit", Item.ChannelId) %>' Text="Edit" /> |
<asp:HyperLink runat="server" NavigateUrl='<%# FriendlyUrl.Href("~/Channels/Delete", Item.ChannelId) %>' Text="Delete" />
<% } %>
And this worked. But I realized one thing, when If I add
<% if (VincitoreCRMApplication.CommonUtilities.IsCurrentUserAdmin) { %>
like this, in a single line, it's not working. But on adding the curly braces in new line, it works. I know this sounds very strange, I also can't make out why it happens so. But it is fact, that what I have faced & learned.
I know this is quiet simple thing, but just in case my code helps anyone, have shared here.
Thanks

Calling nested RepeaterItem

I constructed a Repeater for my XML file roughly like so:
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="samplexml.xml" XPath="level1/level2" />
<asp:Repeater id="category" runat="server" DataSourceID="XmlDataSource1">
<ItemTemplate>
<div class="category">
<h2><%#XPath("#name") %></h2>
<asp:Repeater id="group" runat="server" DataSource='<%# XPathSelect("group") %>'>
<ItemTemplate>
...
</ItemTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
And now I'm working on how to get the data inside of each on postback. I learned roughly how to get into a RepeaterItem:
foreach (RepeaterItem items in category.Items)
{
Output.Text += items.UniqueID + "<br />";
}
But after a lot of searching MSDN, this site, and others, I haven't been able to figure out how to get into the group repeater.
Am I missing something obvious here? I'm in .NET 2.0.
You aren't missing anything obvious. In my experience working with nested Repeaters/ListViews/Etc is a nightmare.
If you have the option to do this using MVC I would recommend that. If not.... Your best bet is probably to get familiar with FindControl. Typically your code will look something like this:
protected void category_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Repeater level2 = e.Item.FindControl("group") as Repeater;
//you are now working with the nested repeater in a single row... Do what you will!
}
So when a row in the parent repeater binds, you will have to use FindControl to find it's nested repeater. Good luck!

What is the simplest way i can page a nested data repeater control?

I am working with a two nested data repeaters, and I want to allow paging for the outer repeater.
Here is what I have so far:
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="LinqDataSource1" OnItemDataBound="Repeater1_ItemDataBound">
<HeaderTemplate>
<div class="group">
</HeaderTemplate>
<ItemTemplate>
<div class="question"><%#Eval("QText") %></div>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# setQID(Eval("QID"))%>' />
<%-- THE INNER REPEATER--%>
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="LinqDataSource2">
<HeaderTemplate>
<div class="answer">
</HeaderTemplate>
<ItemTemplate>
<%# (GetAnswer(Eval("AnsQID"))) != 1 ? (displayAnswer(Eval("AText"))) : ""%>
</ItemTemplate>
<FooterTemplate>
</div>
</FooterTemplate>
</asp:Repeater>
<%-- THE INNER REPEATER ENDS HERE--%>
</ItemTemplate>
<FooterTemplate>
</div>
</FooterTemplate>
</asp:Repeater>
I have googled for this, searched everywhere and found a lot of ways to approach this. I am using LinqDatasources and two repeaters. What is the best way to do this ?
To page the outer repeater i have used the method outlined in this post in the past. I don't think it should make much difference to the outcome if your repeater is nested. Your inner repeater will count as one row.
Repeaters generally though don't have great support for paging. You could consider using ListView (if using ASP.Net 3.5 or greater) or GridView (ASP.Net 2.0 or greater) which have more support for paging out of the box.
I have used this control in my Project.
http://www.codeproject.com/KB/custom-controls/CollectionPager.aspx
optional
http://www.codeproject.com/KB/webforms/SQLPager_For_Everything.aspx
and for Nested you have to use Databoud event and bound the child repeater.

asp.net calling a method from front end

i have a method in my back end that i would like to call from my front end, but can't seem to get it working. here is my code:
<% foreach(string item in Plants){ %>
<li>
<span class="folder">
<asp:label ID="lblPlantName" runat="server" Text='<% GetPlantName(item) %>'></asp:label>
</span>
</li>
<%} %>
the getplantName method should return a string and fill the text in. But this is not getting called for some reason.
Anyone have any ideas or suggestions?
Please use <%= GetPlantName(item) %> instead of <% GetPlantName(item) %> and method should be Public or Protected.
To return a string you need Response.Write which is written in shorthand as <%=%> so:
<%= GetPlantName(item) %>
While your code might be working (with the fix suggested by others) it's not good practice. It's the classic ASP way while you're using ASP.NET - it's like driving 10 MPH with sport car on the highway.
One good practice can be to use the Repeater Control - it's still simple and it's much more elegant.
The .aspx will now look like this:
<asp:Repeater ID="rptPlants" runat="server">
<HeaderTemplate><ol></HeaderTemplate>
<FooterTemplate></ol></FooterTemplate>
<ItemTemplate>
<li>
<span class="folder">
<%# Container.DataItem %>
</span>
</li>
</ItemTemplate>
</asp:Repeater>
And to bind the data have such code in the Page_Load function in your code behind:
string[] arrPlants = new string[] { "Sacred Datura", "Kambroo", "Wallflower", "Beech 'Retroflexa'", "Zephyr Flower" };
rptPlants.DataSource = arrPlants;
rptPlants.DataBind();
In your case just replace arrPlants with your real array, Plants.
Feel free to ask for further details or explanations. :)

Creating a three level ASP.NET menu with SiteMap, how do i do it?

I want to create a three level menu, I have got a recursive function today that works with three levels. But the thing is how do i output the third lever? Using two repeaters i have managed to get a hold of the first two levels through the ChildNodes property. But that only gives me the second level. What if a want the third level? Example code below. How do i get the third level? :)
<asp:Repeater ID="FirstLevel" DataSourceID="SiteMapDataSource" runat="server" EnableViewState="false">
<ItemTemplate>
<li class="top">
<span class="down"><%#Eval("Title")%></span><!--[if gte IE 7]><!--><!--<![endif]-->
<asp:Repeater runat="server" ID="SecondLevel" DataSource='<%#((SiteMapNode)Container.DataItem).ChildNodes%>'>
<HeaderTemplate><!--[if lte IE 6]><table><tr><td><![endif]--><ul class="sub"></HeaderTemplate>
<ItemTemplate>
<li>
<%#Eval("Title")%>
Third repeater here?
</li>
</ItemTemplate>
<FooterTemplate></ul><!--[if lte IE 6]></td></tr></table></a><![endif]--></FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
</asp:Repeater>
I would use the OnItemCreatedEvent of the repeater to register the OnItemDataBound event of each repeater and then bound the data accordingly. Is the asp:menu control not appropriate? Why repeaters?
I would create a custom server control and parse the sitemap recursively. This will give you more control of the rendering and allow you to specify additional custom attributes for the sitemap nodes.

Categories

Resources