I have a survey composed of nested repeater objects of questions that are within subjects. Everything is populated dynamically via the database. Each question has a radiobuttonlist of answers. There can be one or many questions per subject. When the user complete the form and click submit, how does my click function loop through all controls, find each radiobuttonlist and its' selected answer?
<div id="qDiv" runat="server" >
<asp:Repeater runat="server" ID="rptSubject" OnItemDataBound="rptSubject_ItemDataBound">
<ItemTemplate>
<h2><%#DataBinder.Eval(Container.DataItem, "Subject")%></h2>
<asp:Repeater runat="server" ID="rptQuestion" OnItemDataBound="rptQuestion_ItemDataBound">
<ItemTemplate>
<p><%# DataBinder.Eval(Container.DataItem, "Question")%></p>
<asp:RadioButtonList ID="rblAnswers" runat="server"></asp:RadioButtonList>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
</div>
protected void submitButton_Click(object sender, EventArgs e)
{
???
}
As well as the selected answer, can I also get access to the repeaters values question & subject in the click function?
Use the Page.FindControl(string) method to find server controls based on a known ID pattern.
Related
I'm sure there's a really simple explanation for this but I've been tearing my hair out too long now so I appeal to SO for the sake of my sanity!
It's this simple: I have a ListView which is bound when the page first loads (and not again on postback). It's part of a form. On the first load I see the list of items but when I postback I see the EmptyDataTemplate. Is this correct behaviour? I'm sure that ListView as a data binding control should persist its list over postbacks. Here's the code, first front end:
<asp:ListView ID="boxes" runat="server" ItemType="Model.Generic.ILookupEntity<int>" EnableViewState="true">
<LayoutTemplate>
<div>
<ul class="contact-list checkbox-row">
<li id="itemPlaceholder" runat="server" />
</ul>
</div>
</LayoutTemplate>
<ItemTemplate>
<li>
<label>
<asp:CheckBox ID="cb" runat="server" />
<asp:HiddenField ID="value" runat="server" Value="<%# Item.Key %>" />
<span><%# Item.Value %></span>
</label>
</li>
</ItemTemplate>
<EmptyDataTemplate>
<p>No data</p>
</EmptyDataTemplate>
</asp:ListView>
<asp:CheckBoxList ID="boxtemp" runat="server" />
Then back end:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!IsPostBack)
{
var items = new List<Model.Generic.LookupEntity<int>>()
{
new Model.Generic.LookupEntity<int>(1, "One"),
new Model.Generic.LookupEntity<int>(2, "Two"),
new Model.Generic.LookupEntity<int>(3, "Three"),
new Model.Generic.LookupEntity<int>(4, "Four"),
};
boxes.DataSource = items;
boxes.DataBind();
boxtemp.DataSource = items;
boxtemp.DataTextField = "Value";
boxtemp.DataValueField = "Key";
boxtemp.DataBind();
}
}
I've added the boxtemp CheckBoxList as a test. This one retains its data on postback. But the ListView doesn't. What am I doing wrong here?
UPDATE 1
What's even weirder is that if I add the following code and debug, the variable test references the value 4 even on postback. But when the posted page is rendered I still see the EmptyItemTemplate.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
var test = boxes.Items.Count;
}
UPDATE 2
Having had it confirmed that this is not expected behaviour I have now found the cause I think. The ListView is inside a user control which is calling this.DataBind() on PreRender. I presume this is causing all data bound controls inside to re-bind on postback. The weird thing is that if I handle the ListView's OnDataBinding and OnDataBound events, on post back I can observe that the list still contains 4 items during both events. But is still rendered displaying the EmptyDataTemplate. Given this scenario, and assuming that the parent control's DataBind call is required, can anyone suggest the best resolution?
I have a control image in a user control. And I'm using a repeater to create several images list.
I have a button outside from the user control to delete image (per images).
I want to know, how can I make references to an specific row when I click in the button to delete the image.
This is the repetear:
<asp:Repeater ID="ImageRepeater" runat="server"
onitemcommand="ImageRepeater_ItemCommand">
<ItemTemplate>
<div>
<uc1:IVT_DisplayImage ID="IVT_DisplayImage1" runat="server" ImageURL="<%# Container.DataItem %>" />
<asp:Button ID="RemoveDiplayImage" Text="Remove" runat="server"
CommandName="delete"
/>
</div>
</ItemTemplate>
</asp:Repeater>
This is the event ItemCommand:
protected void ImageRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "delete")
{
//????
}
}
I want to know, how identify by code wich row (user control) I'm selecting.
You need to add CommandArgument to your button like CommandArgument="<%# Container.ItemIndex %>".
This way, in the code; e.CommandArgument gives you the item number, with which you can get the item that you want.
Note: In fact instead of specifying ItemIndex as CommandArgument, you can use any Primary Key (Unique Identifier) from the DataSource that you bind to the repeater from where you will be able to get hold of the record directly from the list object (DataSource).
I am developing an application for my company in which i am stuck at thinking what would be the best approach for doing this.
The company already have a page for survey around 15 questions with multiple choices. Now i have been asked to develop an application so that from admin section they can modify the existing questions and their options, also they can add more questions and options.
I am not sure what would be the best approach for doing this. I was thinking creating a page in admin section where they can see existing questions and answer options, if they modify it i can directly change it in the database and if they add more questions, I can go and create a custom questions fields in the database. For answers option i will not create any fields in the database as i will generate options dynamically like textboxes, checkboxes, radiobuttons etc.. and when user select the answer i will put pnly selected answers in the database.
EDIT
=======
I just want to give admin only 3 options for adding options ( checkbox, radios, textbox )
I am confused as how to create controls dynamically using generics. like admin can pass in the values in the method like this CreateControls(TextBox, NoOfOptions, List)
Please forgive me for not adding any code in my questions as i have not yet started working on this and stuck at the first stage of thinking process.
I am using VS2010, .Net 4.0, SQL server 208 R2 for this application.
Please advice. any working example Link would be appreciated.
I have one idea regarding this.I already done this kind of functionality but in my case each custom question is bind with textbox only.
In you case we can follow these steps :
Admin End :
Specify each control with unique value it may be number or control name.Save this in table with question id.
Client End :
1.) Take repeater.In item template take following controls :
a.)Label (Your custom question)
b.)textboxes (visible false)
c.)checkboxes (visible false)
d.)radiobuttons (visible false) etc.
2.)Bind this repeater with questions table.
3.)Now fire rowdatabound event and set visibility of controls on the basis of question id.
May this help you if you have any doubt please ask .
UPDATE :
Now please check the implementation of whole process which i had discussed yesterday :
XML file use as test database :
<?xml version="1.0" encoding="iso-8859-1"?>
<catalog>
<cd>
<id>1</id>
<title>Question 1</title>
<ctrl>1</ctrl>
</cd>
<cd>
<id>2</id>
<title>Question change</title>
<ctrl>2</ctrl>
</cd>
<cd>
<id>3</id>
<title>Question 3</title>
<ctrl>3</ctrl>
</cd>
<cd>
<id>4</id>
<title>Question 4</title>
<ctrl>2</ctrl>
</cd>
ASPX page :
<asp:Repeater ID="Repeater1" runat="server"
onitemdatabound="Repeater1_ItemDataBound">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="Label1" runat="server" Text='<%#Eval("id") %>'></asp:Label>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%#Eval("ctrl") %>' />
</td>
<td>
<asp:Label ID="Label2" runat="server" Text='<%#Eval("title") %>'></asp:Label>
</td>
<td>
<asp:TextBox ID="TextBox1" runat="server" Visible="false"></asp:TextBox>
</td>
<td>
<asp:RadioButton ID="RadioButton1" runat="server" Checked="true" Text="YES" TextAlign="Left" Visible="false" />
<asp:RadioButton ID="RadioButton2" runat="server" Text="NO" TextAlign="Left" Visible="false" />
</td>
<td>
<asp:CheckBox ID="CheckBox1" runat="server" Visible="false" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
CS file :
if (!IsPostBack)
{
DataSet ds = new DataSet();
ds.ReadXml(MapPath("XMLFile.xml"));
Repeater1.DataSource = ds;
Repeater1.DataBind();
}
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
HiddenField ctrl = (HiddenField)e.Item.FindControl("HiddenField1");
if (ctrl.Value == "1")//1 for Textbox
{
TextBox txtCtrl = (TextBox)e.Item.FindControl("TextBox1");
txtCtrl.Visible = true;
}
else if (ctrl.Value == "3")//3 for Radio Button
{
RadioButton rdbYCtrl = (RadioButton)e.Item.FindControl("RadioButton1");
RadioButton rdbNCtrl = (RadioButton)e.Item.FindControl("RadioButton2");
rdbYCtrl.Visible = true;
rdbNCtrl.Visible = true;
}
else if(ctrl.Value == "2")//2 for Chackbox
{
CheckBox chkCtrl = (CheckBox)e.Item.FindControl("CheckBox1");
chkCtrl.Visible = true;
}
}
}
Hope this help you now :-)
Prettiest way to do this is to write a webcontrol. PLace it inside the ItemTemplate of teh Repeater. The repeater will do the databinding job, where as the webcontrol will render the question and the answer fields for each questions.
What I can imagine at the momment is, your datasource (that is bound to ther repeater must have at least:
QuestionID - This is to identify the question
Question - this contains the question
ResponseType - this is just a flag to determine whether to render textbox, radio or checkbox as the answer field/s
The webcontrol must have at least these properties:
QuestionID
Question
ResponseType
UserAnswer
Choices - collection of choice
During itemdatabound event of the repeater, get the webcontrol instance in the itemtemplate. assign the questionid and question from the bound DataItem to the respective webcontrol properties. Then check the AnswerType. if it's either radio or checkbox, retrieve the choices from the db/xml for this particular questionid, and assign it to the webcontrol Choices property.
Now at the webcontrol's RenderContents event:
write the question
if AnswerType is textbox, write textarea or textbox element
if AnswerType is either radio or checkbox, iterate the Choices property to render the respective input tags.
Anyway, if you use this approach, the admin can set unlimited number of choices for each questions. Each question can have flexibility. Image can be attached to questions, even as the choices like those IQ test.
However, there are a lot more to code in the webcontrol like, maintaining data on postbacks, fieldvalidation, etc.
I know there are a lot of related posts or articles about this, but then it seems that they're not helping my case. I've even compared with a working sample at this site, http://www.ezineasp.net/post/ASP-Net-LinkButton-Command-Event.aspx, I don't think there's much difference. I thought my code should be working but apparently it just won't. I'm so sorry if this looks like a duplicate, but it's my last resort to post here.
Here's my HTML:
<asp:ListView runat="server" ID="AppsList">
<LayoutTemplate>
<div>
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</div>
</LayoutTemplate>
<ItemTemplate>
<div class="applist">
<div class="app">
<asp:ImageButton ID="imgbtnApp" runat="server" ImageUrl='<%#Eval("Icon") %>' height="100" width="100" CommandName="Select" CommandArgument='<%# Eval("ID") %>' OnCommand="AppsList_ItemCommand" />
</div>
<div class="appname">
<asp:LinkButton ID="linkbtnAppName" runat="server" CommandName="Select" ForeColor="#333333" CommandArgument='<%# Eval("ID") %>' OnCommand="AppsList_ItemCommand" CssClass="linkbtnAppName"><%# Eval("AppName") %></asp:LinkButton>
</div>
</div>
</ItemTemplate>
<EmptyDataTemplate>
Sorry - Nothing found.
</EmptyDataTemplate>
</asp:ListView>
Code:
protected void AppsList_ItemCommand(object sender, CommandEventArgs e)
{
if (e.CommandName == "Select")
{
txtTest.Text = e.CommandArgument.ToString();
}
}
What I'm trying to achieve here is to capture the ID of the item in the ListView into the textbox when I click on either the Image Button or Link Button. Both will perform the same thing. I already got the Image button to work. When I click the Image, the ID, e.g 1 will appear in the textbox. But when I want to do the same thing with the Link Button, nothing will happen. The event is not being triggered in any way.
I've seen some posts talking about repeaters or AJAX to do the same thing, but I was just wondering why can't this code work. I would appreciate any pointer.
For my own experience, I have wrongly set ViewStateMode="Disabled" in page directive.
Because of this when post back occur upon clicking LinkButton inside the List View, existing data are vanished. So, will not reach to LinkButton's OnCommand event and never fire.
Once ViewStateMode attribute is removed, everything working well.
I noticed that your eventArgs should ListViewCommandEventArgs instead of CommandEventArgs and you should also bind the itemCommand event to your aspx page as shown below.
ASPX:
<asp:ListView runat="server" ID="AppsList" OnItemCommand="AppsList_OnItemCommand">
Code Behind:
protected void AppsList_OnItemCommand(object sender, ListViewCommandEventArgs e)
{
if (String.Equals(e.CommandName, "Select"))
{
}
}
UPDATE:
Also remove the OnCommand attribute from image button and Link button OnCommand="AppsList_ItemCommand" , and each CommandName should be different than other.
<div class="applist">
<div class="app">
<asp:ImageButton ID="imgbtnApp" runat="server" ImageUrl='<%#Eval("Icon") %>' height="100" width="100" CommandName="Select" CommandArgument='<%# Eval("ID") %>' />
</div>
<div class="appname">
<asp:LinkButton ID="linkbtnAppName" runat="server" CommandName="Select" ForeColor="#333333" CommandArgument='<%# Eval("ID") %>' CssClass="linkbtnAppName"><%# Eval("AppName") %></asp:LinkButton>
</div>
</div>
</ItemTemplate>
Well, in case someone is wondering why this is happening, this is what I've found out after spending a great deal of time ripping off my codes to see what's wrong with it. I doubt that someone will bump into this issue, but to heck with it, sharing is caring.
Apparently the search button I've placed in my master page is the reason behind this. I've assigned its ID as "submit", which is the thing that is stopping my linkbutton from working, which I have no idea why that is happening. The search function is merely a search engine allowing users to look for the keywords in the webpage. The linkbutton's OnCommmand event just won't trigger when the ID to the search button is assigned as "submit".
When I change it to "submit1", everything works as normal. I'm still a newbie in this asp.net thing, can anyone tell me why is this even affecting the linkbutton? Anyway, the OnCommand event is now working properly.
I had a similar issue with LinkButtons. I don't remember how I figured this out, but I must of got fustrated and started clicking the LinkButton a few times fairly quickly and I noticed that the Command event did fire once in awhile. Soon I figured it's if I clicked on the LinkButton before the page fully loads that the command would fire correctly. If the page fully loaded then it seems something was hijacking that command on the LinkButton.
Without success, from one of the other suggestions I searched for any button that might be using the name/id "submit". There wasn't one on my page.
With success, I tried using ASP.Net Buttons instead of LinkButtons. That seemed to fix my issue. I'm not entirely sure what caused this situation but Buttons seem to work in my case so I'll stick with that.
I constructed a Repeater for my XML file roughly like so:
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="samplexml.xml" XPath="level1/level2" />
<asp:Repeater id="category" runat="server" DataSourceID="XmlDataSource1">
<ItemTemplate>
<div class="category">
<h2><%#XPath("#name") %></h2>
<asp:Repeater id="group" runat="server" DataSource='<%# XPathSelect("group") %>'>
<ItemTemplate>
...
</ItemTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
And now I'm working on how to get the data inside of each on postback. I learned roughly how to get into a RepeaterItem:
foreach (RepeaterItem items in category.Items)
{
Output.Text += items.UniqueID + "<br />";
}
But after a lot of searching MSDN, this site, and others, I haven't been able to figure out how to get into the group repeater.
Am I missing something obvious here? I'm in .NET 2.0.
You aren't missing anything obvious. In my experience working with nested Repeaters/ListViews/Etc is a nightmare.
If you have the option to do this using MVC I would recommend that. If not.... Your best bet is probably to get familiar with FindControl. Typically your code will look something like this:
protected void category_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Repeater level2 = e.Item.FindControl("group") as Repeater;
//you are now working with the nested repeater in a single row... Do what you will!
}
So when a row in the parent repeater binds, you will have to use FindControl to find it's nested repeater. Good luck!