HELP! Get value of dynamic control radio button!
-
11-09-2019 - |
Question
I am looking into create a dynamic survey as posted in Get User Input From Dynamic Controls but with some different environment.
Below is what i am trying to do:
First when the user click the button, it will populate a dynamic table with radio button for the survey questionnaire inside a placeholder. However, I was unable to get its value (for score calculation) after clicking the submit button. All the dynamic controls was gone. Beside i am using an ajax extension (updatePanel) for the development and I have been look into viewstate but I have no idea with it.
Does anyone have any ideas?
Here i included some of my code:
Page
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="btnTest" runat="server" Text="Take Test" OnClick="btnTest_Click" Visible="False" />
<asp:Label ID="lblTestErrMsg" runat="server"
ForeColor="Red"></asp:Label><br />
<table id="tblTest" runat="server" style="width: 100%">
<tr>
<td>
<asp:PlaceHolder ID="phQuestionnaire" runat="server"></asp:PlaceHolder>
<br />
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td>
<asp:Label ID="lblResult" runat="server"></asp:Label></td>
</tr>
<tr>
<td>
</td>
</tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>
Create Dynamic Table function
*v_dtTable and v_dtTable2 contains the data from database
Private Sub CreateDynamicTable(ByVal v_dtTable As Data.DataTable, ByVal v_dtTable2 As Data.DataTable)
Me.phQuestionnaire.Controls.Clear()
Dim cols As Integer = v_dtTable.Rows.Count + 2
Dim rows As Integer = v_dtTable2.Rows.Count + 1
Dim mid As Integer = v_dtTable.Rows.Count / 2
Dim tbl As Table = New Table()
tbl.ID = "tblQs"
tbl.BorderWidth = 1
tbl.CellPadding = 0
tbl.CellSpacing = 0
tbl.Width = 500
tbl.EnableViewState = True
Me.phQuestionnaire.Controls.Add(tbl)
For i As Integer = 0 To rows - 1
Dim tr As TableRow = New TableRow()
Dim rowCnt As Integer = 1
Dim colCnt As Integer = 0
For j As Integer = 0 To cols - 1
Dim tc As TableCell = New TableCell()
tc.BorderWidth = 1
Dim lbl As Label = New Label()
Dim bol As Boolean = False
If i = 0 Then
If j = 0 Then
tc.Text = "No."
ElseIf j = 1 Then
tc.Text = "Question"
Else
tc.Text = v_dtTable.Rows(j - 2).Item("scoreName")
tc.HorizontalAlign = HorizontalAlign.Center
End If
tc.BackColor = Drawing.Color.DeepSkyBlue
tc.ForeColor = Drawing.Color.White
Else
If v_dtTable2.Rows(i - 1).Item("isHeader") Then
bol = True
tc.Text = v_dtTable2.Rows(i - 1).Item("TestQuestion")
tc.Style("font-weight") = "bold"
ElseIf j = 0 Then
tc.Text = rowCnt
rowCnt += 1
ElseIf j = 1 Then
tc.Text = v_dtTable2.Rows(i - 1).Item("TestQuestion")
Else
Dim rBtn As RadioButton = New RadioButton
rBtn.GroupName = "rBtn" & rowCnt
rBtn.ID = "rBtn_" & rowCnt & "_" & colCnt
rBtn.InputAttributes("value") = v_dtTable.Rows(j - 2).Item("scoreValue")
colCnt += 1
If j = mid + 2 Then
rBtn.Checked = True
End If
tc.Controls.Add(rBtn)
tc.HorizontalAlign = HorizontalAlign.Center
End If
End If
If bol Then
tc.ColumnSpan = cols - 1
tr.Cells.Add(tc)
Exit For
Else
tr.Cells.Add(tc)
End If
Next j
tbl.Rows.Add(tr)
Next i
End Sub
Calculate Score function
Private Sub subCalculateScore()
Dim tblQs As Table = CType(Me.phQuestionnaire.FindControl("tblQs"), Table)
Dim rb As New RadioButton
Dim score As Integer = 0
If Me.phQuestionnaire.FindControl("tblQs") Is Nothing Then
Else
For Each tr As TableRow In tblQs.Rows
For Each tc As TableCell In tr.Cells
For Each c As Control In tc.Controls
If c.GetType.ToString = rb.GetType.ToString Then
Dim rBtn As RadioButton = CType(c, RadioButton)
If rBtn.Checked Then
Dim strScore As String = rBtn.InputAttributes("value")
score += CInt(strScore)
End If
End If
Next
Next
Next
End If
Me.Label1.Text = score
End Sub
View source for the dynamic generated table
<table id="tblQs" cellspacing="0" cellpadding="0" border="0" style="border-width:1px;border-style:solid;width:500px;border-collapse:collapse;"><tr>
<td style="border-width:1px;border-style:solid;"><span>No.</span></td>
<td style="border-width:1px;border-style:solid;"><span>Question</span></td>
<td style="border-width:1px;border-style:solid;"><span>dislike</span></td>
<td style="border-width:1px;border-style:solid;"><span>normal</span></td>
<td style="border-width:1px;border-style:solid;"><span>like</span></td>
<td style="border-width:1px;border-style:solid;"><span>vry likes</span></td></tr><tr>
<td style="border-width:1px;border-style:solid;"><span>1</span></td>
<td style="border-width:1px;border-style:solid;"><span>question 1</span></td>
<td style="border-width:1px;border-style:solid;">
<input id="rBtn_1_0" type="radio" name="rBtn1" value="rBtn_1_0" value="0" /></td>
<td style="border-width:1px;border-style:solid;">
<input id="rBtn_1_1" type="radio" name="rBtn1" value="rBtn_1_1" value="1" /></td>
<td style="border-width:1px;border-style:solid;">
<input id="rBtn_1_2" type="radio" name="rBtn1" value="rBtn_1_2" checked="checked" value="2" /></td>
<td style="border-width:1px;border-style:solid;">
<input id="rBtn_1_3" type="radio" name="rBtn1" value="rBtn_1_3" value="3" /></td></tr></table>
Solution 2
Thank you Jacob for his solution.
I am able to calculate the score by making some modification for the ID assignment.
I added its value at the back of the id since the value generated is the same with the ID as shown in the view source
rBtn.ID = "rBtn[" & rowCnt & "][" & colCnt & "]_" & value (eg. rBtn[1][0]_2 )
Then, i used substring to get and calculate the score as shown in the subCalculateScore function below:
Private Function subCalulateScore() As Integer
Dim score As Integer = 0
Dim expectedNumRows As Integer = Me.qsNum.Text
For i As Integer = 1 To expectedNumRows
Dim strBtn As String = Request.Form("rBtn" & i)
If Not strBtn Is Nothing Then
If strBtn.LastIndexOf("_") <> -1 Then
Dim strScore As String = strBtn.Substring(strBtn.LastIndexOf("_") + 1)
score += CInt(strScore)
End If
End If
Next
Return score
End Function
Haha.. sound like a lousy way to do it :p
Once again, thanks for your help, Jacob.
Always welcome for any other solution ^^
OTHER TIPS
If the names of the generated radio button groups are predictable enough, you could get their values by inspecting the Request.Form collection. Assuming the group names are rBtn1, rBtn2, etc, the post data will look something like rBtn1=6&rBtn2=7. That means you can do this:
Dim i as Integer
Dim score as Integer = 0
For i = 1 To expectedNumRows
score += CInt(Request.Form("rBtn" & i))
Next
This will help you work around the fact that the controls that were generated before no-longer exist. You should poke around in the debugger and inspect the Request.Form collection so you can get familiar with what's in there.
(my apologies if my VB.NET is incorrect; I'm used to C#)
I figured out yesterday that you can actually make your app work like normal by loading the control tree right after the loadviewstateevent is fired. if you override the loadviewstate event, call mybase.loadviewstate and then put your own code to regenerate the controls right after it, the values for those controls will be available on page load. In one of my apps I use a viewstate field to hold the ID or the array info that can be used to recreate those controls.
Protected Overrides Sub LoadViewState(ByVal savedState As Object)
MyBase.LoadViewState(savedState)
If IsPostBack Then
CreateMyControls()
End If
End Sub