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.
Related
I have built a slideshow. Each of the slides has a div placed over the top of it. The div contains some text. What I want to do is if the h2 and p element have no text then hide the div that contains them. I have attempted to hide the div from the repeaters DataBound event but it is still showing the div over the slide.
Here's what I have so far:
aspx:
<asp:Repeater ID="rptSlides" runat="server" ClientIDMode="Static" OnItemDataBound="rptSlides_ItemDataBound">
<ItemTemplate>
<div runat="server" id="slideDiv" class="slide">
<img runat="server" src='<%# Eval("slideImgPath")%>' />
<div id="slideTextdiv" runat="server" class="slideText">
<h2 id="titlePlaceHolder" runat="server" class="slideTitle text-center text-capitalize h2 ">
<%# Eval("slideTitle") %>
</h2>
<p id="textPlaceHolder" runat="server" class="slideDes">
<%# Eval("slideDesc") %>
</p>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
Code behind:
protected void rptSlides_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
foreach (RepeaterItem item in rptSlides.Items)
{
HtmlGenericControl titleText = (HtmlGenericControl)item.FindControl("titlePlaceHolder");
HtmlGenericControl slidetextDesc = (HtmlGenericControl)item.FindControl("textPlaceHolder");
HtmlGenericControl slideDiv = (HtmlGenericControl)item.FindControl("slideTextdiv");
if (titleText.InnerText == "" && slidetextDesc.InnerText == "")
{
slideDiv.Style.Add("Display", "none");
}
}
}
Further info
I have also tried the following:
foreach (RepeaterItem item in rptSlides.Items)
{
HtmlGenericControl slideDiv = (HtmlGenericControl)FindControlRecursive(item, "slideTextdiv");
HtmlGenericControl titleText = (HtmlGenericControl)FindControlRecursive(item, "titlePlaceHolder");
HtmlGenericControl slidetextDesc = (HtmlGenericControl)FindControlRecursive(item, "textPlaceHolder");
if (string.IsNullOrWhiteSpace(titleText.InnerText) && string.IsNullOrWhiteSpace(slidetextDesc.InnerText))
{
slideDiv.Attributes["class"] = "emptySlideText";
}
}
I created a class in the css called emptySlideText, like so:
.emptySlideText {
display:none; }
Unfortunatley this has had no effect.
I have also tried changing the line
slideDiv.Style.Add("Display", "none");
to
slideDiv.Attributes.Add("style", "display:none");
But again it made no difference
First of all you don't need a foreach loop inside your rptSlides_ItemDataBound event as ItemDataBound event of a repeater control iterates for each item. Next Div is not a HtmlGenericControl control rather it is HtmlControl control. Once you have this you can hide the div using Visible property like this:-
protected void rptSlides_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
HtmlControl slideTextdiv = (HtmlControl)e.Item.FindControl("slideTextdiv");
HtmlGenericControl titlePlaceHolder = (HtmlGenericControl)e.Item.FindControl("titlePlaceHolder");
HtmlGenericControl textPlaceHolder = (HtmlGenericControl)e.Item.FindControl("textPlaceHolder");
if (titlePlaceHolder != null)
titlePlaceHolder.InnerText = Regex.Replace(titlePlaceHolder.InnerText, #"\r\n?|\n", "").Trim();
if (textPlaceHolder != null)
textPlaceHolder.InnerText = Regex.Replace(textPlaceHolder.InnerText, #"\r\n?|\n", "").Trim();
if (String.IsNullOrEmpty(titlePlaceHolder.InnerText) && String.IsNullOrEmpty(textPlaceHolder.InnerText))
{
slideTextdiv.Visible = false;
}
}
}
Please include using System.Text.RegularExpressions; to import Regex class.
I'm trying to get a column value of the first element on a repeater, and use it on the repeater's HeaderTemplate. After searching and trying many ways of achieving this through intellisense, I gave up and decided to post this question here.
My code is as follows:
Frontend
<asp:Repeater ID="states" runat="server">
<HeaderTemplate>
<h1>Stage: <asp:Literal ID="stageName" runat="server"></asp:Literal></h1>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# DataBinder.Eval(Container.DataItem, "StateName") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
Backend
protected void BindStageStates()
{
List<StagesStatesModel> statesList = App.Services.Stages.StagesService.GetStatesByStage(Page.DefaultApp, 1, Page.DefaultCultureId).Where(p => p.StateActive == true).ToList();
states.ItemDataBound += new RepeaterItemEventHandler(rptStagesStatesDataBound);
states.DataSource = statesList;
states.DataBind();
}
void rptStagesStatesDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Header)
{
Literal stageName = (Literal)e.Item.FindControl("stageName");
stageName.Text = // Something to go here..
}
}
Thanks in advance!
Try OnItemCreated
protected void Repeater_OnItemCreated(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Footer)
{
e.Item.FindControl(ctrl);
}
if (e.Item.ItemType == ListItemType.Header)
{
e.Item.FindControl(ctrl);
}
}
By:
How to find controls in a repeater header or footer
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;
}
I have a repeater which displays and data bind the source of tab links. Here is the code:
protected void rptTab_ItemBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Item i = e.Item.DataItem as Item;
Link hlTabLink = e.Item.FindControl("hlTabLink") as Link;
hlTabLink.Target = Sitecore.Links.LinkManager.GetItemUrl(i);
hlTabLink.DataSource = i.Paths.FullPath;
hlTabLink.Field = "Title";
}
}
Now this is my markup:
<asp:Repeater ID="rptTab" runat="server" OnItemDataBound="rptTab_ItemBound">
<ItemTemplate>
<li id= "liTabTest" runat = "server">
<a>
<sc:Link ID = "hlTabLink" Field = "scTabLink" onclick = "TabClick()" runat ="server"></sc:Link>
</a>
</li>
</ItemTemplate>
</asp:Repeater>
And this is the jQuery which is adding CSS class dynamically based on which item is selected:
$(document).ready(function () {
init();
});
function init() {
$("ul#Tab-labels li").removeClass("tab-label TabbedPanelsTabSelected");
$("ul#Tab-labels li:first").addClass("tab-label TabbedPanelsTabSelected");
};
function TabClick() {
alert('test');
};
Now you can see that I am displaying the CSS file based on the index of the tab. I also have to add the click event in that jQuery. So there are basically two things that I am confused:
My click event in jQuery is not getting called :(
From jQuery I have to know in the click event that which page it has
to go through? So that I have to get from codebehind or what? Like a
hidden field and store the tab pages in that, then fetch out from
jQuery.
How should I resolve this? Please help!
For sc:Link, change the bind method to onClientClick for onclick = "TabClick()". OnClick is for the postback server method.
BTW, what is the sc prefix? Is there a user control you are adding to the page?
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;
}