Fill megamenu dynamically - c#

I have this functions that gets categories in three levels.
One that gets ParentCategories
One that gets categories by ParentCategoryID
One that gets Subcategories by categoriesID.
I want to build a megamenu looking like this site:
http://www.potterybarn.com/
HTML Markup
<div>
<asp:Repeater ID="HorizMenuRepeater" runat="server">
<HeaderTemplate>
<ul id="mega-menu"></HeaderTemplate>
<ItemTemplate>
<li><a id="mBox" href="javascript:;">'<%#Eval("ParentCatName")%>'</a></li></ItemTemplate>
<FooterTemplate></ul></FooterTemplate></asp:Repeater>
</div>
<script>
window.addEvent('domready', function () {
new mBox.Tooltip({
content: 'MegamenuUC',
setStyles: { content: { padding: 15, lineHeight: 20 } },
position: {
x: 'right',
y: 'bottom'
},
attach: 'mBox',
closeOnMouseleave: true
});
});
</script>
<div id="MegamenuUC" style="display:none">
<uc1:Megamenu ID="Megamenu1" runat="server" />
</div>
result
Code of the usercontrol
<ul>
<h3>Category</h3>
<ul>
<li>Sub category</li>
</ul>
</ul>
I want to make this dynamically, now it's just the parentcategory that is dynamic.
I need somehow pass the id to know witch parentcategory you hovered over tho pas the right id to my function that gets the categories so I can populate my usercontrol with it
Thanks

I solved it and i used a repeater to create a clean list and a jquery plugin to create megamenu
Link to jquery plugin http://www.designchemical.com/lab/jquery-mega-drop-down-menu-plugin/options/
Code for databind repeater with linq
<div>
<asp:Repeater ID="ParentRepeater" runat="server" OnItemDataBound="ParentRepeater_OnItemBound">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><a><%# DataBinder.Eval(Container.DataItem, "ParentCatName") %></a>
<asp:Repeater ID="ParentCatRepeater" runat="server" OnItemDataBound="ChildRepeater_OnItemBound">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><a><%# DataBinder.Eval(Container.DataItem, "CategoryName") %></a>
<asp:Repeater ID="ChildRepeater" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><a><%# DataBinder.Eval(Container.DataItem, "ProductName") %></a></li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</div>
C#
protected void Page_Load(object sender, EventArgs e)
{
LinqtoDBDataContext db = new LinqtoDBDataContext();
ParentRepeater.DataSource = db.GetParentCategories();
ParentRepeater.DataBind();
}
protected void ParentRepeater_OnItemBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
dynamic cat = e.Item.DataItem as dynamic;
int parentcatid = Convert.ToInt32(cat.ParentCatID);
LinqtoDBDataContext db = new LinqtoDBDataContext();
//var cats = from c in db.Categories
// where c.ParentCatID == parentcatid
// select c;
Repeater ParentCatRepeater = e.Item.FindControl("ParentCatRepeater") as Repeater;
ParentCatRepeater.DataSource = db.GetCategories(parentcatid);
ParentCatRepeater.DataBind();
}
}
protected void ChildRepeater_OnItemBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
dynamic prod = e.Item.DataItem as dynamic;
int catid = Convert.ToInt32(prod.CategoryID);
LinqtoDBDataContext db = new LinqtoDBDataContext();
Repeater ChildRepeater = e.Item.FindControl("ChildRepeater") as Repeater;
ChildRepeater.DataSource = db.GetProductsInCategory(catid);
ChildRepeater.DataBind();
}
}
}

Related

Get values of checkbox in repeater

I have a repeater inner another repeater and this second one i have a list of checkbox and i need to get the value of the checked.
This is my front code:
<asp:Repeater runat="server" ID="rptPerfis" OnItemDataBound="ItemBound">
<ItemTemplate>
<div class="mws-form-row">
<ul class="mws-form-list inline" style="float: none; display: inline;">
<li style="padding-top: 10px;">
<%# rptNome(Container) %></li>
</ul>
<asp:Repeater runat="server" ID="rptUsers">
<ItemTemplate>
<div class="mws-form-item radioPermissoes clearfix" style="float: none;">
<ul class="mws-form-list inline">
<li>
<asp:CheckBox runat="server" Text="<%# rptAdministradorNome(Container) %>" ID="checkUser" CssClass="<%# rptAdministradorPostClass(Container) %>" /></li>
</ul>
</div>
</ItemTemplate>
</asp:Repeater>
</div>
<br />
<hr />
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton runat="server" ID="fLnkSalvar" class="mws-ic-16 ic-disk" OnClick="fLnkSalvar_Click">Salvar</asp:LinkButton>
and this is how i fill this repeater:
protected void Page_Load(object sender, EventArgs e)
{
listaAdm = Servicos.AdministradorMySql.ListarEmpresa(denuncia.Empresa).OrderByDescending(x => x.Nome).ToList();
todosPerfis = Servicos.Perfil.ListarTodos().ToList();
rptPerfis.DataSource = todosPerfis.Where(x => x.Ativo).OrderBy(x => x.Nome);
rptPerfis.DataBind();
}
protected void ItemBound(object sender, RepeaterItemEventArgs args)
{
if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)
{
int idPerfil = ((Perfil)args.Item.DataItem).ID;
Repeater childRepeater = (Repeater)args.Item.FindControl("rptUsers");
childRepeater.DataSource = listaAdm.Where(x => x.Perfil > 1 && x.Perfil == idPerfil).ToList();
childRepeater.DataBind();
}
}
protected void fLnkSalvar_Click(object sender, EventArgs e)
{
Administrador usuario = new Administrador();
usuario.Permissoes = new List<string>();
// i need to get this values here to fill this `List<string>` and then save
foreach (var x in usuario.Permissoes)
{
Servicos.Denuncia.InserirUsuarios(denuncia.ID, x);
}
}
I've no idea how can i get this values or if there another easier way without add in the list i think its better
You have to use FindControl on multiple levels. First the correct Item in the parent Repeater, then find the CheckBox in the correct Item of the child Repeater.
var cb = ((Repeater)rptPerfis.Items[i].FindControl("rptUsers")).Items[j].FindControl("checkUser") as CheckBox;
PS you need to wrap the code in Page_Load in an IsPostBack check or you will never retrieve the correct checkbox state in a PostBack.

how to access a header template in c#

I have a template:
<asp:Repeater ID="litFolder" runat="server" OnItemDataBound="litFolder_ItemDataBound">
<HeaderTemplate>
<ul class="test" id="currentLink">
</HeaderTemplate>
<ItemTemplate>
<div class="leftNav">
<li>
<asp:HyperLink ID="innerHyperLink" runat="server"></asp:HyperLink>
</li>
</div>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
and I'm trying to set the to display block when a link is selected. I can set the link to display block, but how do I set the ul to display block ( only using C# )
protected void litFolder_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// if the child from the first repeater has children, it will grab them here
Item innerItem = (Item)e.Item.DataItem;
if (innerItem != null)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
// this creates a link to the page in sitecore once clicked
HyperLink topNavigation = (HyperLink)e.Item.FindControl("innerHyperLink");
topNavigation.NavigateUrl = LinkManager.GetItemUrl(innerItem);
topNavigation.Text = innerItem["Title"];
if (topNavigation != null) {
//this is where I think I need to define the ul to display block
}
}
}
}
I need to make sure that the current link sets the ul that it is in and not all the ul's with the class test.
In order to prevent the Ul from being broken, place the <div class="leftNav"> inside the <li> as shown below:
<asp:Repeater ID="litFolder" runat="server" OnItemDataBound="litFolder_ItemDataBound">
<HeaderTemplate>
<ul class="test" id="currentLink">
</HeaderTemplate>
<ItemTemplate>
<li>
<div class="leftNav">
<asp:HyperLink ID="innerHyperLink" runat="server"></asp:HyperLink>
</div>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
To set the display block style, you can find the control based on the ID, then set the style to it.
Thanks

Bind 5 items in each row of repeater

I have a set of items coming from the database. Their number may vary. I have bound them in a repeater. Now my following example will explain what I want:
I have 11 items coming from database, I want them to be grouped in terms of 5 items per row.
1st row: 5 items.
2nd row: 5 items.
3rd row: 1 item.
Currently, I am just binding them in a repeater. How do I do this?
Yes. It is possible:
<asp:Repeater ID="rptItems" runat="server">
<ItemTemplate>
<asp:Literal runat="server" Text='<%# Eval("Value") %>'></asp:Literal>
<div style="clear: both" runat="server" Visible="<%# (Container.ItemIndex+1) % 5 == 0 %>"></div>
</ItemTemplate>
</asp:Repeater>
It produces following results for the sequence of numbers:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
if you can use ListView, then you can use GroupItemCount . some thing like this MSDN Example
<asp:ListView ID="ContactsListView"
DataSourceID="yourDatasource"
GroupItemCount="5"
runat="server">
<LayoutTemplate>
<table id="tblContacts" runat="server" cellspacing="0" cellpadding="2">
<tr runat="server" id="groupPlaceholder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<div> your Items here </div>
</ItemTemplate>
<GroupTemplate>
<tr runat="server" id="ContactsRow" style="background-color: #FFFFFF">
<td runat="server" id="itemPlaceholder" />
</tr>
</GroupTemplate>
<ItemSeparatorTemplate>
<td runat="server" style="border-right: 1px solid #00C0C0"> </td>
</ItemSeparatorTemplate>
</asp:ListView>
If you want to stick with a Repeater, I can think of two approaches.
Firstly, you could stick with a flat list of items and make the repeater insert a "new line" after each 5th item. You should be able to do this in the <ItemTemplate> with a block like
<% if ((Container.DataItemIndex % 5) == 4) { %>
</div>
<div>
<% } %>
which honestly isn't very nice.
Alternatively, you could use MoreLINQ's Batch method to batch your items up into IEnumerables of 5, and then use two nested repeaters to render them. Set the outer repeater to wrap the inner repeater in <div> tags, and set the inner repeater's DataSource='<%# Container.DataItem %>'. This should result in much cleaner markup.
You can try below, I mistakenly said ListView, actually I meant DataList
<asp:DataList ID="DataList1" runat="server" RepeatColumns="5"
RepeatDirection="Horizontal" RepeatLayout="Flow">
<ItemTemplate >
<%--Your Item Data goes here--%>
</ItemTemplate>
</asp:DataList>
You may use nested Data controls (i.e Repeater) and also handle the OnItemDataBound event to bind the inner Repeater.
Sample Data Source component:
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
public static List<List<Item>> getItems()
{
List<Item> list = new List<Item>()
{
new Item(){ ID=11, Name="A"},
new Item(){ ID=12, Name="B"},
new Item(){ ID=13, Name="C"},
new Item(){ ID=14, Name="D"},
new Item(){ ID=15, Name="E"},
};
/* Split the list as per specified size */
int size = 2;
var lists = Enumerable.Range(0, (list.Count + size - 1) / size)
.Select(index => list.GetRange(index * size,
Math.Min(size, list.Count - index * size)))
.ToList();
return lists;
}
}
Markup (.aspx)
<asp:Repeater ID="outerRepeater"
runat="server" onitemdatabound="outerRepeater_ItemDataBound"
>
<ItemTemplate>
<p>
Row
</p>
<asp:Repeater ID="innerRepeater"
runat="server">
<ItemTemplate>
<asp:Literal ID="literal1" runat="server" Text='<%# Eval("ID") %>' />
<asp:Literal ID="literal2" runat="server" Text='<%# Eval("Name") %>' />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
outerRepeater.DataSource = Item.getItems();
outerRepeater.DataBind();
}
}
protected void outerRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Repeater repeater = e.Item.FindControl("innerRepeater") as Repeater;
repeater.DataSource = Item.getItems()[e.Item.ItemIndex];
repeater.DataBind();
}
<asp:Repeater ID="Repeater1" runat="server"
OnItemDataBound="Repeater1_databinding">
<HeaderTemplate>
<table id="masterDataTable" class="reportTable list issues" width="100%">
<thead>
<tr>
<asp:Literal ID="literalHeader" runat="server"></asp:Literal>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<asp:Literal ID="literals" runat="server"></asp:Literal>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody> </table>
</FooterTemplate>
</asp:Repeater>
<input id="hdnColumnName" runat="server" clientidmode="Static" type="hidden" />
<input id="hdnColumnOrder" runat="server" clientidmode="Static" type="hidden" />
// javascript Function
<script type="text/javascript">
$(document).ready(function () {
$('#ddlReport').removeClass('required');
$('.sort').click(function () {
$('#hdnColumnName').val($(this).text());
$('#hdnColumnOrder').val($(this).attr('class'));
$(this).toggleClass("desc asc");
$("#lnkSort").click();
});
});
</script>
// Bind repeater
DataTable dt = objReport.GetCustomRecord();
fn = new List<string>();
for (int i = 0; i < dt.Columns.Count; i++)
{
if (dt.Columns[i].ColumnName != "Maxcount" )
{
fn.Add(dt.Columns[i].ColumnName);
}
}
Repeater1.DataSource = dt;
Repeater1.DataBind();
protected void Repeater1_databinding(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Header)
{
if (e.Item.FindControl("literalHeader") != null)
{
StringBuilder sb = new StringBuilder();
Literal li = e.Item.FindControl("literalHeader") as Literal;
fieldName().ForEach(delegate(string fn)
{
if (hdnColumnName.Value != fn.ToString())
{
sb.Append("<th width=\"10%\"> <a id=\"btnCustomerName\" class=\"sort desc\" onclick=\"btnSorts_onclick()\" style=\"cursor:pointer;text-decoration: none !important;\" >"
+ fn.ToString() + "</a></th>");
}
else
{
if (hdnColumnOrder.Value == "sort asc")
sb.Append("<th width=\"10%\"> <a id=\"btnCustomerName\" class=\"sort desc\" onclick=\"btnSorts_onclick()\" style=\"cursor:pointer;text-decoration: none !important;\" >"
+ fn.ToString() + "</a></th>");
else
sb.Append("<th width=\"10%\"> <a id=\"btnCustomerName\" class=\"sort asc\" onclick=\"btnSorts_onclick()\" style=\"cursor:pointer;text-decoration: none !important;\">"
+ fn.ToString() + "</a></th>");
}
});
li.Text = sb.ToString();
}
}
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
if (e.Item.FindControl("literals") != null)
{
DataRowView drv = (DataRowView)e.Item.DataItem;
Literal li = e.Item.FindControl("literals") as Literal;
StringBuilder sb = new StringBuilder();
fieldName().ForEach(delegate(string fn)
{
sb.Append("<td>" + drv[fn.ToString()] + "</td>");
});
li.Text = sb.ToString();
}
}
}

How to find a nested control inside of asp repeater

I'm trying to find <span id="source"> inside of my repeater the listControl is coming back null.
<asp:Repeater id="rptRssFeed" runat="server" OnItemDataBound="RssFeedItemDataBound">
<HeaderTemplate><ul></HeaderTemplate>
<FooterTemplate></ul></FooterTemplate>
<ItemTemplate>
<li id="socialListItem" runat="server">
<%# GetTitle(Container.DataItem) %>
<span class="source" id="source" runat="server"><%# GetSource(Container.DataItem) %></span>
<p><%# GetTeaser(Container.DataItem) %></p>
</li>
</ItemTemplate>
<AlternatingItemTemplate>
<li class="alt" id="socialListItem" runat="server">
<%# GetTitle(Container.DataItem) %>
<span class="source" id="source" runat="server"><%# GetSource(Container.DataItem) %></span>
<p><%# GetTeaser(Container.DataItem) %></p>
</li>
</AlternatingItemTemplate>
</asp:Repeater>
public void RssFeedItemDataBound(object sender, RepeaterItemEventArgs e)
{
HtmlGenericControl listControl = (HtmlGenericControl)e.Item.FindControl("socialListItem");
if (!ShowSource)
{
HtmlGenericControl spanControl = (HtmlGenericControl)listControl.FindControl("source");
spanControl.Visible = false;
}
listControl.Attributes["class"] += ((XmlFeedItem)e.Item.DataItem).XmlFeedType;
}
You need to check if you are checking for the List Item in the ListItemType.Item or AlternatingItem type.
public void RssFeedItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
HtmlGenericControl listControl = (HtmlGenericControl)e.Item.FindControl("socialListItem");
if (listControl != null)
{
if (!ShowSource)
{
HtmlGenericControl spanControl = (HtmlGenericControl)listControl.FindControl("source");
spanControl.Visible = false;
}
listControl.Attributes["class"] += ((XmlFeedItem)e.Item.DataItem).XmlFeedType;
}
}
}

Change value of databound control within Repeaters in C#

I have a nested repeater control that displays a list of data, in my case it is an FAQ list. here is the design portion:
<asp:Repeater ID="lists" runat="server">
<ItemTemplate>
<h2 class="sf_listTitle"><asp:Literal ID="listTitle" runat="server"></asp:Literal></h2>
<p class="sf_controlListItems">
<a id="expandAll" runat="server">
<asp:Literal ID="Literal1" runat="server" Text="<%$Resources:ExpandAll %>"></asp:Literal>
</a>
<a id="collapseAll" runat="server" style="display:none;">
<asp:Literal ID="Literal2" runat="server" Text="<%$Resources:CollapseAll %>"></asp:Literal>
</a>
</p>
<ul class="sf_expandableList" id="expandableList" runat="server">
<asp:Repeater ID="listItems" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<li>
<h1 id="headlineContainer" runat="server" class="sf_listItemTitle">
<a id="headline" runat="server" title="<%$Resources:ClickToExpand %>"></a>
</h1>
<div id="contentContainer" runat="server" class="sf_listItemBody" style="display:none;">
<asp:Literal ID="content" runat="server"></asp:Literal>
</div>
</li>
</ItemTemplate>
<FooterTemplate>
</FooterTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
The repeater that I am interested in is the second repeater, listItems. In my code-behind, I cannot directly call listItems and see the controls inside of it. I tried to grab the control inside of list.DataBinding (maybe I need to use a different event?) method:
void lists_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var oRepeater = (Repeater) lists.FindControl("listItems");
}
but this comes up as null. Can anyone give me some pointers/tips of what I need to do to gain access to the listItems repeater and it's children controls?
Thanks!
lists
belongs to each RepeaterItem, not directly to the Repeater itself.
Try :-
void lists_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ( e.Item.ItemType == ListItemType.AlternatingItem
|| e.Item.ItemType == ListItemType.Item )
{
Repeater oRepeater = (Repeater)e.Item.FindControl("listItems");
// And to get the stuff inside.
foreach ( RepeaterItem myItem in oRepeater.Items )
{
if ( myItem.Item.ItemType == ListItemType.AlternatingItem
|| myItem.Item.ItemType == ListItemType.Item )
{
Literal myContent = (Literal)myItem.FindControl("content");
// Do Something Good!
myContent.Text = "Huzzah!";
}
}
}
}
And you should be good :)
Edited to incorporate DavidP's helpful refinement.
You need to change that line to
var oRepeater = (Repeater) e.Item.FindControl("listItems");
You're close! Inside your event handler check the RepeaterItemEventArgs for what kind of row you're dealing with. Your child repeater will only be available on (Alt)Item rows, not headers or footers. My guess is that it's blowing up on the header.

Categories