nested repeater show data that matches parent repeater - asp.net

I am using a repeater to build a custom table. However, I can't figure out how to make the table show subtotal if the next rows tour does not match the previous rows.
Something similar to that.
row1 tour1
row2 tour 1
tour1 subtotal
row3 tour2
row4 tour2
subtotal
total
<asp:Repeater ID="ParentRepeater" runat="server" DataSourceID="SqlDataSource1">
<HeaderTemplate>
<table border="1">
<tr>
<th>TOUR</th>
<th>THEME</th>
<th>ROUTE</th>
<th>DEPT</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%#Container.DataItem("tour")%></td>
<td align="center"><%#Container.DataItem("theme")%></td>
<td align="right"><%#Container.DataItem("route")%></td>
<td align="right"><%#Container.DataItem("dep7")%></td>
<asp:Repeater ID="ChildRepeater" runat="server"
DataSourceID="SqlDataSource2">
<HeaderTemplate>
<table border="1">
<tr>
<th>BOOKNO</th>
<th>PARTY</th>
<th>TOUR</th>
<th>THEME</th>
<th>ROUTE</th>
<th>DEPT</th>
<th>HOME</th>
<th>USERID</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td align="center"><%#Container.DataItem("bookno") %></td>
<td><%#Container.DataItem("party")%></td>
<td><%#Container.DataItem("tour")%></td>
<td align="center"><%#Container.DataItem("theme")%></td>
<td align="right"><%#Container.DataItem("route")%></td>
<td align="right"><%#Container.DataItem("dep7")%></td>
<td align="right"><%#Container.DataItem("home")%></td>
<td align="right"><%#Container.DataItem("userid")%></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
code behind
Protected Sub ItemBound(ByVal sender As Object, ByVal args As RepeaterItemEventArgs)
If args.Item.ItemType = ListItemType.Item Then
Dim childRepeater As Repeater = DirectCast(args.Item.FindControl("ChildRepeater"), Repeater)
childRepeater.DataSource = SqlDataSource2
childRepeater.DataBind()
End If
End Sub
but this shows all the data in the nested repeater not the ones that match the parentrepeater fields
for example tour,theme,dep7 should match in the child repeater

First, add 2 class fields:
private int _subTotal; // Not sure what you're summing but you
// wrote subtotal in your pseudo-output
private int _lastTourId;
Reset these field before you databind your repeater:
_subTotal = 0;
_lastTourId = -1;
TourRepeater.DataBind();
The create a single level Repeater:
<asp:Repeater ID="TourRepeater" ...>
<HeaderTemplate>...<>
<ItemTemplate>
<tr>
Some columns with your tour data
</tr>
<PlaceHolder ID="SubTotalRow" ... />
</ItemTemplate>
<FooterTemplate>
<PlaceHolder ID="SubTotalRow" ... />
</FooterTemplate>
</asp:Repeater>
Bind this Repeater directly to your tour data, then do this in your OnItemDataBound event handler (I'll have to go for c#):
void RepeaterItemDataBound(object source, RepeaterItemEventArgs e)
{
if (
e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem // think you forgot this
)
{
var tour = e.Item.DataItem as Tour;
if (tour != null)
{
if (_lastTourId == -1) { _lastTourId == tour.TourId; } // To avoid subtotal row before first tour
if (tour.TourId != _lastTourId) // This is a new tour so insert a subtotal row for the previous tour
{
var subTotalRow = e.Item.FindControl("SubTotalRow") as PlaceHolder;
if (subTotalRow != null)
{
RenderSummaryRow(subTotalRow, _subTotal);
}
_subTotal = tour.SomeValueYouWantToAddToSubTotal;
}
else
{
_subTotal += tour.SomValueYouWantToAddToSubTotal;
}
_lastTourId = tour.TourId;
}
}
else if (e.Item.ItemType == ListItemType.Footer)
{
var subTotalRow = e.Item.FindControl("SummaryRow") as PlaceHolder;
if (summaryTotalRow != null)
{
RenderSummaryRow(subTotalRow, _subTotal);
}
}
}
private void RenderSummaryRow(PlaceHolder placeHolder, int subTotal)
{
// create subtotal row manually by either creating TableRow + TableCells and adding them to a placeholder, or
// just add a literal and create your markup manually as innerHtml. Put your _subtotal value in where you want
}
An alternative method is to retrieve your tour data into a DataTable, and retrieve the data WITH ROLLUP etc which will create summary rows automagically. There's several tutorials about this around the web, but I couldn't find the great one I used before I switched to MVC.

Related

How to render two column layout using an asp.net repeater

I have a list of items I want to render using a repeater, the twist is these items need to render in two columns in a table layout. Also if there are odd number of items the last cell will contain a place holder image. any thoughts?
Ex, my list [“string1”,”string2”,”string3”,”string4”,”string5”]
Display
<table>
<tr>
<td>string1</td>
<td>string2</td>
</tr>
<tr>
<td>string3</td>
<td>string4</td>
</tr>
<tr>
<td>string5</td>
<td>string6</td> or [<td>Some place holder Imge if odd number </td>]
</tr>
</table>
So that I end up with a view that looks like this
“String1” “String2”
“String3” “String4”
“String5” “String6”
Or if the list has odd number of Items
“String1” “String2”
“String3” “String4”
“String5” “Some place holder image”
We can render two columns in markup. Also we have to add a placeholder that we will use in code to insert image :
<asp:Repeater ID="rptMyRepeater" runat="server" OnItemDataBound="rptMyRepeater_ItemDataBound">
<HeaderTemplate>
<table>
<tr>
</HeaderTemplate>
<ItemTemplate>
<%# (Container.ItemIndex != 0 && Container.ItemIndex % 2 == 0) ? #"</tr><tr>" : string.Empty %>
<%# string.Format("{0}{1}{2}", #"<td>", Container.DataItem, #"</td>") %>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
</ItemTemplate>
<FooterTemplate>
</tr>
</table>
</FooterTemplate>
</asp:Repeater>
Now in the code check for last item and check if it is odd. If it is, add an image inside td, append the td in placeholder:
protected void rptMyRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
int count = ((List<string>)rptMyRepeater.DataSource).Count;
if (e.Item.ItemIndex != 0 && e.Item.ItemIndex % 2 == 0 && e.Item.ItemIndex == count - 1)
{
PlaceHolder PlaceHolder1 = e.Item.FindControl("PlaceHolder1") as PlaceHolder;
Image img = new Image();
img.ImageUrl="pholder.jpg";
TableCell td = new TableCell();
td.Controls.Add(img);
PlaceHolder1.Controls.Add(td);
}
}
}
And the code I have used for testing:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//rptMyRepeater.DataSource = new List<String>() { "String1", "String2", "String3", "String4", "String5", "String6" };
rptMyRepeater.DataSource = new List<String>() { "String1", "String2", "String3", "String4", "String5" };
rptMyRepeater.DataBind();
}
}
Hope it helps!

wont display drop down

<form>
<asp:Repeater id="rptComments" runat="server">
<HeaderTemplate>
<table class="detailstable FadeOutOnEdit">
<tr>
<th style="width:200px;">Answers</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<th style="width:200px;"><asp:DropDownList ID="dropDownForChecklistAnswers" runat="server" /></th>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
<asp:Button id="button" text="Submit" OnClick="Page_Load" runat="server" />
</FooterTemplate>
</asp:Repeater>
</form>
Code Behind:
List<Checklist_Record_Choice> CLRC =
(from choice in db.Checklist_Record_Choices
select choice).ToList();
dropDownForChecklistAnswers.DataSource = CLRC;
DropDownList1.DataTextField = Text;//Text being the name of column2 in the table (which contains yes, no, n/a)
dropDownForChecklistAnswers.DataBind();
ERROR: dropDownForChecklistAnswers does not exist in the current context???
please advise
EDIT;
thanks for reply. I have
public void OnReptDataBound(object sender, RepeaterItemEventArgs e)
{
ClarkeDBDataContext db1 = new ClarkeDBDataContext();
List<string> CLRC =
(from choice in db1.Checklist_Record_Choices
select choice.Text).ToList();
DropDownList ddl = (DropDownList)e.Item.FindControl("dropDownForChecklistAnswers");
ddl.DataSource = CLRC;
}
but DropDownList ddl is coming back as object ref not set to instance of an object...why is it null??
You need to use FindControl to access a control which is part of a Repeater's template.
Subscribe to the OnItemDataBound of the Repeater (set the attribute OnItemDataBound="OnReptDataBound")
And then in your code behind do the following
void OnReptDataBound(object sender, RepeaterItemEventArgs e)
{
if(e.Item.ItemType == ListItemType.Item)
{
DropDownList ddl = (DropDownList )e.Item.FindControl("dropDownForChecklistAnswers");
ddl.DataSource = ....

ASP.NET Repeater need to alter display

I have the following Repeater:
<asp:Repeater ID="rpttsk" runat="server">
<HeaderTemplate>
<tr>
<td>
<b>ID</b>
</td>
<td>
<b>Date</b>
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%#Eval("ID")%>
</td>
<td>
<%#Eval("PerfDate", "{0:MMM d, yyyy}")%>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
I am putting the code in the code behind file
Protected Sub rpttsk_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rpttsk.ItemDataBound
but not even hitting this sub procedure
I'd do it this way:
Frontend:
<asp:Repeater ID="rpttsk" runat="server" OnItemDataBound="rpttsk_ItemDataBound">
<HeaderTemplate>
<tr>
<td>
<b>ID</b>
</td>
<td>
<b>Date</b>
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%#Eval("ID")%>
</td>
<td>
<asp:Label ID="lbl" runat="server"/>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
Backend:
protected void rpttsk_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
YourDataType item = e.Item.DataItem as YourDataType;
Label lbl = e.Item.FindControl("lbl") as Label;
lbl.Text = item;
if (DateTime.Compare(item.YourDateHere, DateTime.Now()) > 0)
{
lbl.ForeColor = Color.Red;
}
else
{
lbl.ForeColor = Color.Blue;
}
}
}
If you want entire rows to be coloured, you'll have to put everything in labels.
You can set this logic in code Behind in ItemDataBound
void rpttsk_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
}
}
Choosing the colour to display is a view concern. In general I would put view concern logic into the views rather than the code behinds. It allows for more view flexibility. It can make maintenance easier since cosmetic updates to your applications don't require as many binary updates.
You could technically say that the logic of comparing the date to today is a business logic concern, possibly. So that could be a code behind thing, such as a getter like "IsDateGreaterThanToday".
Then your repeater view could be revised like so:
<td <%# IsViewGreaterThanToday(Eval("PerfDate")) ? "class='greater-than-today'" : ""%>>
<%#Eval("PerfDate", "{0:MMM d, yyyy}")%>
</td>

ListView DataPager is not paging

The ListView is displaying properly and the DataPager is displaying the buttons at the bottom, but when I click the NEXT button, the DataPager is not going to the next page of data.
ASPX page:
<div id="EventListing">
<asp:ListView ID="ListEvents" runat="server">
<LayoutTemplate>
<div ID="itemPlaceholder" runat="server">
</div>
<div id="pagerFormat">
<asp:DataPager ID="ListingDataPager" runat="server" PageSize="5" PagedControlID="ListEvents" QueryStringField="page" >
<Fields>
<asp:NextPreviousPagerField
FirstPageText="First"
LastPageText="Last"
NextPageText="Next"
PreviousPageText="Back" />
</Fields>
</asp:DataPager>
</div>
</LayoutTemplate>
<ItemTemplate>
<table id="tblEvents">
<tr>
<td rowspan="4" id="Col1Events"></td>
<td rowspan="4" id="Col2Events"></td>
<td rowspan="4" id="Col3Events"></td>
<td class="tdEvents"><span style="font-weight:bold; font-size: 1em;"><%#Eval("EVENT_DATERANGE") %>: <%#Eval("EVENT_NAME") %></span></td>
</tr>
<tr>
<td class="tdEvents"> <span style="font-size: .9em;"><%#Eval("EVENT_DESC") %></span></td>
</tr>
<tr>
<td class="tdEvents"><span style="font-size: .9em;"><%#Eval("EVENT_STREET") %>, <%#Eval("CITY.CITY_NAME") %></span></td>
</tr>
<tr>
<td class="tdEvents"><span style="font-size: .9em;"><%#Eval("EVENT_PHONE") %></span></td>
</tr>
<tr>
<td colspan="4" id="tdEmpty"></td>
</tr>
</table>
</ItemTemplate>
</asp:ListView>
</div>
Code Behind Page:
protected void btnFindEvents_Click(object sender, EventArgs e)
{
DateTime StartDt;
string EventType = ddlEventType.SelectedValue;
string dt = Request.Form["DatePickername"];
if (ddlEventType.SelectedIndex == 0)
{
EventType = "";
}
if (dt != "")
{
StartDt = Convert.ToDateTime(Request.Form["DatePickerName"]);
}
else
{
StartDt = DateTime.Now;
}
string CityName= ddlEventCity.SelectedValue;
if (ddlEventCity.SelectedIndex == 0)
{
CityName = "";
}
if ((ddlEventType.SelectedIndex == 0) && (ddlEventCity.SelectedIndex == 0))
{
//(1) ALL EVENTS
BLgetEvents obj = new BLgetEvents();
var EventList = obj.getAllEvents(StartDt);
ListEvents.DataSource = EventList;
ListEvents.DataBind();
}
}
you have to bind data again on the ListView when you page by DataPager. So, you need to implement this bind on PagePropertiesChanging event of your ListView control. Something like:
// 1 - add a method to bind ListView, add some parameters if you need
protected void BindListView()
{
var data = // get data from database
ListEvents.DataSource = data;
ListEvents.DataBind();
}
// 2 - call this method on the button
protected void btnFindEvents_Click(object sender, EventArgs e)
{
BindListView();
}
// 3 - call this method on the PagePropertiesChanging event of the ListView
protected void ListEvents_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e)
{
//set current page startindex, max rows and rebind to false
YourDataPagerControlId.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
//rebind List View
BindListView();
}
And on your asp.net webform, you need to set the event on the listview tag:
<asp:ListView ID="ListEvents" runat="server" OnPagePropertiesChanging="ListEvents_PagePropertiesChanging">
...
</asp:ListView>
When you set the datasource from code behine, the same principle is valid for other databound controls like GridView, DataList, Repeater etc (you need to bind again on some paging event). An alternative way to solve this, you could add a datasource control (like objectdatasource, linqdatasource, etc...) and set it on the ListView's DataSourceID property and the DataPager will work automatically.
For more details, look at this link: http://weblogs.asp.net/hajan/archive/2011/09/08/paging-listview-using-datapager-without-using-datasource-control.aspx

Render empty repeater

When Repeater contains no items it's not get rendered in HTML at all, even HeaderTemplate or FooterTemplate. I need to manipulate it on client-side even if it's empty.
Is there any way to always render Repeater in HTML?
In the <FooterTemplate>, add a Label with some empty data text and set its visible property to false.
<FooterTemplate>
<table>
<tr>
<td>
<asp:Label ID="lblEmptyData"
Text="No Data To Display" runat="server" Visible="false">
</asp:Label>
</td>
</tr>
</table>
</FooterTemplate>
Now check the the data while binding repeater, if no rows return then make label visible otherwise no action.
More details here.
as #Saurabh said, use <FooterTemplate> add a Label with specifying your message in the Text property and set its visible property to false like this:
<FooterTemplate>
<%-- Label used for showing Error Message --%>
<asp:Label ID="ErrorMessage" runat="server" Text="Sorry!!" Visible="false">
</asp:Label>
</FooterTemplate>
Then in the code-behind use the following logic; if there is no data, show the message, otherwise, show the data as following:
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Repeater rpt = sender as Repeater; // Get the Repeater control object.
// If the Repeater contains no data.
if (rpt != null && rpt.Items.Count < 1)
{
if (e.Item.ItemType == ListItemType.Footer)
{
// Show the Error Label (if no data is present).
Label ErrorMessage = e.Item.FindControl("ErrorMessage") as Label;
if (ErrorMessage != null)
{
ErrorMessage.Visible = true;
}
}
}
}
<asp:Repeater ID="rptList" runat="server" DataSourceID="odsList">
...
<FooterTemplate>
<%if (rptList.Items.Count == 0)
{ %>
**Your message**
<%} %>
</FooterTemplate>
</asp:Repeater>
Try this
protected bool IsDataEmpty
{
get
{
ICollection list = Repeater1.DataSource as ICollection;
return list.Count == 0 ? true : false;
}
}
In Markup :
<table width="80%">
<tr runat="server"
visible='<%# IsDataEmpty %>'>
<td>
There is no data to display
</td>
</tr>
for step by step follow the link :Link

Resources