I have a question regarding repeaters in ASP.net
I have 2 repeaters nested.
I would like to hide both the parent and the child repeater whenever the child repeater holds no items.
Each parent with their child items are giving unique classes like 'class="childlist_1"'.
ascx file:
<asp:Repeater ID="ParentRepeater" runat="server">
<ItemTemplate>
<ul class="Mainlist">
<li>
<h3 class="selected">List 1</h3>
<ul id="DomainList" class="child-items" runat="server">
<asp:Repeater ID="ChildRepeater" runat="server">
<ItemTemplate><li>Link to child item</li></ItemTemplate>
</asp:Repeater>
</ul>
</li>
</ul>
</ItemTemplate>
</asp:Repeater>
What is the best solution for this?
Thanks in advance!
You can do this in ItemDataBound event
protected void ParentRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item)
{
// code that binds ChildRepeater
.....
// check if ChildRepeater has no items
if (((Repeater)e.Item.FindControl("ChildRepeater")).Items.Count == 0)
{
e.Item.Visible = false;
}
}
}
If like me you like to use a method to bind the child repeater (i.e. DataSource='<%# GetChildDatasource(Eval("parentID").ToString()) %>'), this won't work as the datasource is binded after the parent's itemdatabound method is triggered.
The workaround is to use the PreRender method on the child repeater :
protected void ChildRpt_PreRender(object sender, EventArgs e)
{
//hide if empty
Repeater rpt = (Repeater)sender;
rpt.Visible = rpt.Items.Count > 0;
}
Related
I am using Repeater control and in it I have one Image tag having id as 'imgGallery'. but in code behind file, I cannot access it.
aspx
<div class="col-md-4 col-sm-12">
<div class="col-md-2">
<asp:Repeater ID="rptImage" runat="server">
<ItemTemplate>
<asp:Image ID="imgGallery" runat="server" />
</ItemTemplate>
</asp:Repeater>
</div>
</div>
aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
using (DBDataContext dt = new DBDataContext())
{
var frm = from i in dt.GalleryMasters
where i.CategoryId == 1
select i;
foreach (var item in frm)
{
Image img = (Image)rptImage.FindControl("imgGallery");
img.ImageUrl = item.Image;
((HtmlControl)(FindControl("ifrm"))).Attributes["src"] = item.Video;
}
}
}
If I use FindControl then var is null.
First you need to bind your repeater:
rptImage.DataSource = frm.ToList();
rptImage.DataBind();
In your view should be possible to do this:
<asp:Image ID="imgGallery" runat="server" ImageUrl='<%# Eval("Video") %>' />
In code behind, to get items in your repeater, you need to iterate throught his items. The single item contains your image control. This should work:
foreach (RepeaterItem item in rptImage.Items) {
Image img = (Image)item.FindControl("imgGallery");
// Some other code
}
If you want to bind image in Repeater control based on Database result then you can directly assign datasource to Repeater control instead of finding image control.
Also Repeater does not have any record then it will not find any control which is inside the repeater as there is not any row in repeater.
I need to create a data-bound control where each item renders <tbody><ItemTemplate></tbody>. Further, I'd also like to put the <HeaderTemplate> in a <thead> rather than a <tbody> row as the <asp:DataList> does. I need full control of the item template. It needs to be able to render an editable row, like the DataList does.
I believe I need to make a custom control for this (but if not, please let me know--it would save a lot of time). What's the best parent class to extend? My guess is that it's either DataList or DataBoundControl.
Looks like what I'm looking for is <asp:Repeater> with a little extra code for editing since it doesn't have an <EditItemTemplate>.
.ascx
<asp:Repeater id="rItems" runat="server" OnItemCommand="rItems_ItemCommand" OnItemDataBound="rItems_ItemDataBound">
<HeaderTemplate>
<table>
<thead>...</thead>
</HeaderTemplate>
<ItemTemplate>
<tbody id="itemRows" runat="server">
...
<asp:Button ... CommandName="Edit" />
...
</tbody>
<tbody id="editItemRows" runat="server" visible="false">...</tbody>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
.ascx.cs
private int m_editIndex = -1;
protected void rItems_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
switch (e.CommandName)
{
case "Edit":
m_editIndex = e.Item.ItemIndex;
break;
... // Cancel, Update, Delete, etc
case "Cancel":
m_editIndex = -1;
break;
}
BindItemsDataSource();
}
protected void rItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
bool edit = e.Item.ItemIndex == m_editIndex;
HtmlGenericControl tbody = e.Item.FindControl("itemRows") as HtmlGenericControl;
tbody.Visible = !edit;
tbody = e.Item.FindControl("editItemRows") as HtmlGenericControl;
tbody.Visible = edit;
if (edit)
{
PopulateEditableFieldValues(e.Item);
}
}
}
Lets say I have the following:
<asp:Repeater ID="repSubItems" runat="server" DataSource="<%# SubItems %>" >
<ItemTemplate>
<sc:FieldRenderer ID="FieldRenderer1"
FieldName="BlurbSpot_Content_SubHeading"
runat="server"
Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
</ItemTemplate>
</asp:Repeater>
I want to in code behind be able to do:
FieldRenderer1.Style["Width"] = MyCoolWidth;
But within the Repeater I cannot access the FieldRenderer1 control.
You will need to handle the ItemDataBound event of the repSubItems repeater. Example:
protected void repSubItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var fieldRenderer1 = e.Item.FindControl("FieldRenderer1") as Sitecore.Web.UI.WebControls.FieldRenderer;
if (fieldRenderer1 != null)
{
fieldRenderer1.Style["Width"] = MyCoolWidth;
}
}
}
You need to find the row your are looking for specifically in the Repeater and then find the control. Here is an example that can do it for all items in your Repeater:
// repeater item
foreach (Control cr in repSubItems.Controls)
{
// assuming this is your templated control name and not the final output name
FieldRenderer founcControl = cr.FindControl("FieldRenderer1") as FieldRenderer;
founcControl .Style["Width"] = MyCoolWidth;
}
The better way to do this would be to implement the OnDataBinding for your control specifically because then you have no searching to do:
<sc:FieldRenderer ID="FieldRenderer1" FieldName="BlurbSpot_Content_SubHeading"
runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>"
OnDataBinding="FieldRenderer1_DataBinding" />
protected void FieldRenderer1_DataBinding(object sender, System.EventArgs e)
{
FieldRenderer rend = (FieldRenderer)(sender);
// you can do whatever you want to rend at this point and it is scoped to ONLY
// the control so you never have to search for it.
rend.Style["Width"] = MyCoolWidth;
}
I'm having trouble with using UpdatePanel and changing the 'class' attribute of a control inside a repeater by javascript.
Here some code:
--on the aspx--
<script type="text/javascript">
function changeClass(ctl) {
if (ctl.className == "marked") {
ctl.className = "unmarked";
} else {
ctl.className = "marked";
}
}
</script>
<!-- some html -->
<asp:UpdatePanel ID="upp" runat="server">
<ContentTemplate>
<asp:Repeater ID="rpt1" runat="server" onitemdatabound="rpt1_ItemDataBound">
<ItemTemplate>
<a id="aButton" runat="server" href="javascript:void(0)">
<!-- some other controls -->
</a>
</ItemTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
--Codebehind--
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
MyClass obj = (MyClass)e.Item.DataItem;
((HtmlAnchor)e.Item.FindControl("aButton")).Attributes.Add("class", "marked");
//some other code....
}
}
//method called after the bind on 'rpt1'
private void mymethod()
{
foreach (RepeaterItem ri in rpt1.Items)
{
HtmlAnchor aButton = (HtmlAnchor)ri.FindControl("aButton");
if (Must-be-unmarked)
aButton.Attributes.Add("class", "unmarked");
aButton.Attributes.Add("OnClick", "changeClass(this);");
}
}
The problem is, when I click on an "aButton" the class is changed normally, but when I come in codebehind and get de 'class' of control to check if it's marked or unmarked, I only get the controls marked in ItemDataBound of repeater, not the "aButton"s marked by me at execution time.
here is what I do to get the "aButton"s marked:
private void checkMarked()
{
foreach (RepeaterItem ri in rpt1.Items)
{
if (((HtmlAnchor)ri.FindControl("aButton")).Attributes["class"] == "marked")
{
//do something...
}
}
}
When you change class property from client-side code, the server side will not know about it.
You'll need to add a hidden <input> with marked/unmakred so you can check the contents from the server on a post-back.
Another approach would be to sipmly have your javscript postback to the server directly when an item changes from marked/unmakred.
I know how to use a simple If statement wrapped in the <%# tags to hide something, but I don't know how to do it in a repeater when I need to access Container.DataItem, as in I need the dataItem currently being 'repeated'
eg
if (CurrentValidationMessage.Link != "")
{
show a hyperlink
}
Markup:
<asp:Repeater ID="repValidationResults" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<a href='<%# ((MttImportValidationMessage)Container.DataItem).EditLink %>'> Link to erroneous Milestone </a>
<%# ((MttImportValidationMessage)Container.DataItem).Message %>
<br />
</ItemTemplate>
</asp:Repeater>
It might be more maintainable if you just tagged the controls in the repeater with id's and runat='server' and reference the DataItem in the ItemDataBound event by using e.Item.DataItem.
Then use e.Item.FindControl to reference your controls in the ItemTemplate and perform your logic.
protected void repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
Domain.Employee employee = (Domain.Employee)e.Item.DataItem;
Control myControl = (Control)e.Item.FindControl("controlID");
//Perform logic
}
}
use ItemDataBound Event with repeater, and make the "a" tag with a runat="server" property and ID
protected void repValidationResults_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if (item.ItemType == ListItemType.AlternatingItem || item.ItemType == ListItemType.Item)
{
HyperLink link = (HyperLink) item.FindControl("link");
//Do all your logic here :)
}
}
MarkUp:
<asp:Repeater ID="repValidationResults" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<a runat="server" ID="link"> Link to erroneous Milestone </a>
<%# ((MttImportValidationMessage)Container.DataItem).Message %>
<br />
</ItemTemplate>
</asp:Repeater>