So I've been looking around for a good answer to this question, but haven't really found anything useful. Hopefully someone can shed some light on this for me.
Basically, I have a repeater that is backed by a database table. Inside the ItemTemplate for this repeater, I have some HTML elements that are populated with properties from each item in the list. Pretty standard stuff. However, there is a possibility that one of the items could be null. In that case, it would make sense for me to put some sort of if (blah != null) logic around the offending code. The only problem is, when I've tried to do so, ASP throws up on me, telling me that I can't use an if statement inside of <%# %>.
My question to the masses is this: if you can't use an if statement inside of <%# %>, then how are you supposed to do conditional logic based on the values of each item?
I know that you can call your own methods inside the repeater, but that won't work for what I'm trying to do.
Below is what I'm trying to accomplish, to better illustrate my point.
<asp:Repeater runat="server" ID="repeater">
<ItemTemplate>
<div class="item-wrap">
<% if(Eval("imageUrl") != null) { %>
<div class="plan-img">
<asp:Image runat="server" ImageUrl='<%# Eval("imageUrl") %>'/>
</div>
<% } %>
</div>
</ItemTemplate>
</asp:Repeater>
inside your ItemTemplate write the markup like this:
<asp:Panel runat="server" Visible='<%# Eval("imageUrl") != null %>'>
<asp:Image runat="server" ImageUrl='<%# Eval("imageUrl") %>'/>
</asp:Panel>
Basically you can't mix code <% with databinding constructs <%#.
My advice would be to add the following property in your CodeBehind:
protected YourClass DataItem
{
get
{
return (YourClass)this.Page.GetDataItem();
}
}
and then write the markup without Eval():
<asp:Image runat="server" ImageUrl='<%# DataItem.imageUrl %>'/>
You're supposed to generate the same content for every item in the template. If you don't need to use it for a particular item just set it's visibility to false in the binding events.
Related
My code is like this
<asp:Repeater ID="rptEvaluationInfo" runat="server">
<ItemTemplate>
<asp:Label runat="server" Id="lblCampCode" Text="<%#Eval("CampCode") %>"></asp:Label>
</ItemTemplate>
Everything looks okay to me, But it generates an error in the runtime. When I remove this part
Text="<%#Eval("CampCode") %>"
error goes.
SO I assume the issue is with databind. So I tried an alternative like this
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<label><%#Eval("CampCode") %> </label>
</ItemTemplate>
And it also works good. Can any one tell me what is the issue with my first code?
Note: I don't have access to the error message due to the special
reasons on my project , that's why I have not posted it here.
And I want to use ASP controls itself on the case that's why i haven't
gone with my second solution
The problem is with quotes. Currently you have double quotes everywhere, so ASP.NET is not able to parse this. Change outer ones to single quotes like this:
Text='<%#Eval("CampCode") %>'
I am trying to find out if it's possible to have a control inside another control in ASP, like this:
<asp:FormView ID="FormView1" runat="server" Width="630px" Height="496px">
<ItemTemplate>
<asp:Literal ID="ID" runat="server">Idnumber: </asp:Literal><%#Eval("ID") %>
<asp:DataList ID="DataList1" runat="server">
<ItemTemplate>
<asp:HyperLink ID="ID" runat="server"> <%# Eval("FILE") %> </asp:HyperLink>
</ItemTemplate>
</asp:DataList>
</ItemTemplate>
</asp:FormView>
Can I access DataList1 control? I have been trying, but I can't figure it out, I should be able to access nested controls, but I cant get it to do it.
Controls inside Template tags cannot be directly accessed in code behind. Instead you should use FindControl method:
var dataList1 = (DataList)FormView1.FindControl("DataList1");
Note that this might not work in early stages of page life cycle (not until Page_Load I believe).
I'm trying to do a nested repeater as described here but it's erroring out.
My repeater is as follows:
<asp:Repeater ID="HouseholdRepeater" runat="server">
<ItemTemplate>
<div><b><%# DataBinder.Eval(Container.DataItem,"Name") %></b></div>
<div>
<asp:Repeater ID="ApplicationRepeater" runat="server" DataSource="<%#((DataRowView)Container.DataItem).Row.GetChildrows("Applications") %>"> <!-- error here -->
<ItemTemplate>
<div>
<%# DataBinder.Eval(Container.DataItem,"Description") %>
</div>
</ItemTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
The error message I get is "The server tag is not well formed."
It looks exactly like the example to me. I'm not seeing what is wrong with it. Any ideas how to make this work?
Also, I databind it in the code using an anonymous object from a Linq query.
You are using double quotes to specify your DataSource property, but your DataSource contains double quotes itself. Try enclosing the DataSource in single quotes:
DataSource='<%#((DataRowView)Container.DataItem).Row.GetChildrows("Applications") %>'
Change
Row.GetChildrows("Applications")
to
Row.GetChildrows(""Applications"")
Also change
<a href="<%# DataBinder.Eval(Container.DataItem,"Link")
to
<a href="<%# DataBinder.Eval(Container.DataItem,""Link"")
The DataSource section looks incorrect... the DataSource should be something like this
'<%#DataBinder.Eval(Container, "DataItem.ChildTable") %>'
Change
DataSource="<%#((DataRowView)Container.DataItem).Row.GetChildrows("Applications") %>"
to
DataSource='<%#((DataRowView)Container.DataItem).Row.GetChildrows("Applications") %>'
I have a Customer class with a string property comments and I am trying to bind it like this:
<asp:TextBox ID="txtComments"
runat="server"
TextMode="MultiLine" Text=<%=customer.Comments %>>
</asp:TextBox>
However, it gives me the error:
Server tags cannot contain <% ... %> constructs.
I also have a method in the class called GetCreatedDate and in the aspx page, I am doing
<%=GetCreatedDate()%> and <%GetCreatedDate();%>. What is the difference?
Alternatively you can set the value in the Page_Load event of the code behind file:
txtComments.Text = customer.Comments;
you should use "<%# %>" for data binding
<asp:TextBox ID="txtComments"
runat="server"
TextMode="MultiLine" Text="<%# customer.Comments %>">
</asp:TextBox>
Try this instead.
<asp:TextBox ID="txtComments"
runat="server"
TextMode="MultiLine" Text=<%# customer.Comments %>>
</asp:TextBox>
Notice the = to #
Use the DataBinding syntax as stated, <%# customer.Comments %>. This syntax is only evaluated when the TextBox is databound. You would usually use it in a DataBound list. In this case you need to databind the control manually. Override the page's OnDataBinding method and call txtComments.DataBind();
The databinding syntax is the only way to declaratively set ServerControl properties from the aspx page. The Response.Write of the other syntax happens at a time that the ServerControl properties cannot be accessed. If the control is not inside a databound control, you have to databind it.
If you were looking to go all declarative in your page, you don't gain to much using this method because you still need to write code in the code behind.
An alternative if you want to use the TextBox on its own without a parent DataBound control would be to subclass the TextBox, add an AutoBind property, and in the subclassed control call its DataBind method if it is true. That would let you bind the values without writing databinding code in the code behind.
You could also add the TextBox and other form controls to a FormView control and bind it to your object. You can still use the DataBinding syntax in that case.
try this
<asp:TextBox ID="txtComments"
runat="server"
TextMode="MultiLine" Text='<%# customer.Comments %>'>
</asp:TextBox>
I'm setting up a User Control driven by a XML configuration. It is easier to explain by example. Take a look at the following configuration snippet:
<node>
<text lbl="Text:"/>
<checkbox lbl="Check me:" checked="true"/>
</node>
What I'm trying to achieve to translate that snippet into a single text box and a checkbox control. Of course, had the snippet contained more nodes more controls would be generated automatically.
Give the iterative nature of the task, I have chosen to use Repeater. Within it I have placed two (well more, see bellow) Controls, one CheckBox and one Editbox. In order to choose which control get activate, I used an inline switch command, checking the name of the current configuration node.
Sadly, that doesn't work. The problem lies in the fact that the switch is being run during rendering time, long after data binding had happened. That alone would not be a problem, was not for the fact that a configuration node might offer the needed info to data bind. Consider what would happen if the check box control will try to bind to the text node in the snippet above, desperately looking for it's "checked" attribute.
Any ideas how to make this possible?
Thanks,
Boaz
Here is my current code:
Here is my code (which runs on a more complex syntax than the one above):
<asp:Repeater ID="settingRepeater" runat="server">
<ItemTemplate>
<%
switch (((XmlNode)Page.GetDataItem()).LocalName)
{
case "text":
%>
<asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("#lbl") %>' runat="server" />
<asp:TextBox ID="settingsLabelText" Text='<%# SettingsNode.SelectSingleNode(XPath("#xpath").ToString()).InnerText %>'
runat="server" AutoPostBack="true" Columns='<%# XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"#width",20) %>'
/>
<% break;
case "checkbox":
%>
<asp:CheckBox ID="settingsCheckBox" Text='<%# XPath("#lbl") %>' runat="server"
Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("#xpath").ToString())).HasAttribute(XPath("#att").ToString()) %>'
/>
<% break;
} %>
</ItemTemplate>
</asp:Repeater>
One weekend later, here is what I came with as a solution. My main goal was to find something that will both work and allow you to keep specifying the exact content of the Item Template in markup. Doing things from code would work but can still be cumbersome.
The code should be straight forward to follow, but the gist of the matter lies in two parts.
The first is the usage of the Repeater item created event to filter out unwanted parts of the template.
The second is to store decisions made in ViewState in order to recreate the page during post back. The later is crucial as you'll notice that I used the Item.DataItem . During post backs, control recreation happens much earlier in the page life cycle. When the ItemCreate fires, the DataItem is null.
Here is my solution:
Control markup
<asp:Repeater ID="settingRepeater" runat="server"
onitemcreated="settingRepeater_ItemCreated"
>
<ItemTemplate>
<asp:PlaceHolder ID="text" runat="server">
<asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("#lbl") %>' runat="server" />
<asp:TextBox ID="settingsLabelText" runat="server"
Text='<%# SettingsNode.SelectSingleNode(XPath("#xpath").ToString()).InnerText %>'
Columns='<%# XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"#width",20) %>'
/>
</asp:PlaceHolder>
<asp:PlaceHolder ID="att_adder" runat="server">
<asp:CheckBox ID="settingsAttAdder" Text='<%# XPath("#lbl") %>' runat="server"
Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("#xpath").ToString())).HasAttribute(XPath("#att").ToString()) %>'
/>
</asp:PlaceHolder>
</ItemTemplate>
</asp:Repeater>
Note: for extra ease I added the PlaceHolder control to group things and make the decision of which controls to remove easier.
Code behind
The code bellow is built on the notion that every repeater item is of a type. The type is extracted from the configuration xml. In my specific scenario, I could make that type to a single control by means of ID. This could be easily modified if needed.
protected List<string> repeaterItemTypes
{
get
{
List<string> ret = (List<string>)ViewState["repeaterItemTypes"];
if (ret == null)
{
ret = new List<string>();
ViewState["repeaterItemTypes"] = ret;
}
return ret;
}
}
protected void settingRepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
string type;
if (e.Item.DataItem != null)
{
// data binding mode..
type = ((XmlNode)e.Item.DataItem).LocalName;
int i = e.Item.ItemIndex;
if (i == repeaterItemTypes.Count)
repeaterItemTypes.Add(type);
else
repeaterItemTypes.Insert(e.Item.ItemIndex, type);
}
else
{
// restoring from ViewState
type = repeaterItemTypes[e.Item.ItemIndex];
}
for (int i = e.Item.Controls.Count - 1; i >= 0; i--)
{
if (e.Item.Controls[i].ID != type) e.Item.Controls.RemoveAt(i);
}
}
You need something that looks more like this:
<ItemTemplate>
<%# GetContent(Page.GetDataItem()) %>
</ItemTemplate>
And then have all your controls generated in the code-behind.