Avatar of tmccrank
tmccrank
 asked on

Question about populating the <ItemTemplate> in a Repeater

Hi,

How can I show the contents of 2 columns - 1 column from 2 separate tables - in the <ItemTemplate> of a Repeater control?

The scenario: a student submits her answers to a multiple choice test and is redirected to ScoringPage.aspx where she will see the following for each question answered:

1) <asp:Repeater>Original question
      <ItemTemplate>
          - The student's answer from Table 1
          - The correct answer from Table 2
      </ItemTemplate>
   </asp:Repeater>

Thanks!
Jens
ASP.NET

Avatar of undefined
Last Comment
mrichmon

8/22/2022 - Mon
mrichmon

Very easy, just have that infromation pulled in your query

SELECT QuestionText, StudentAnswer, COrrectAnswer
FROM Questions INNER JOIN StudentAnswers ON Questions.QuestionId = StudentAnswers.QuestionId

Then you have all three columns in your table that is bound.


Another option is to have two tables, with a relationship defined between them based on the question, and then use the GetChildRows to get the current question's studentAnswer.
jjaqua

The data base should be set up in a way that would allow you to join the two tables and out put the information. Is this an option?


tmccrank

ASKER
Hi,

Thanks to you both for your answers.

Only one of the of the tables is being pulled down from sql server.  The other is a DataTable that I programmatically created in asp.net order to accept the user's answers from the page.  So a JOIN in sql server isn't possible, or at least it's not the way I have it set up.

I added the two DataTables to a DataSet and added a DataRelation:

ds.Relations.Add("AnswersRelation", ds.Tables("dtCorrectAnswers").Columns("AnswersID"), ds.Tables("dtUsersAnswers").Columns("dcUserAnswerID"), False)

...but I'm not sure how to proceed from here.

mrichmon:  how would I use GetChildRows to get BOTH the student's answer as well as the correct answer?

Thanks,
Jens
Your help has saved me hundreds of hours of internet surfing.
fblack61
jjaqua

Not sure if this helps but it will loop through the dataset and put everything on one line. could be used to create a data table to bind to the repeater or just to write the grades. this is very generic because I don't have all your table info.


'you could create a table and add all the data for each row then bind it to the repeater or write the markup to a literal control.
        Dim studenAnswer As DataRow
        Dim t As String
        'loop through answers
        For Each studenAnswer In dS.Tables("dtUsersAnswers").Rows 'print employee record

            t = studenAnswer("AnswersID") 'get data from the students answers table in the dataset. I'm only getting the  AnswersID because it's the only name I have.

            Dim correctAnswer As DataRow
            Dim correctAnswers As DataRow() = studenAnswer.GetChildRows("dtCorrectAnswers")
            For Each correctAnswer In correctAnswers 'print all event records associated with employee.

                t = t & correctAnswer("AnswersID") 'get data from the correct answers table in the dataset. I'm only getting the  AnswersID because it's the only name I have.

            Next
        Next

        'new answer
        t = t & vbCrLf 'just using this as an example
jjaqua

Please ignore the notes in my code that reference employee. there left over from it's original use.
tmccrank

ASKER
Thanks jjagua,

I don't quite follow your logic (I'm basically a newbie... sorry!).

To give you a better idea of what I already have, here's the relevant code for my ScoringPage.aspx:

======================================

    Dim DA As New DAL_NurseEdMods.DataAccess
    Dim strAuthUserName As String = User.identity.name

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        If Not Page.IsPostBack Then

            Dim dtQuestions As DataTable = DA.PopulateQuestions(CInt(dtUsersAnswers.Rows(0).Item("dcModuleID")))

            'bind the questions Repeater to dtQuestions DataTable
            rptQuestions.DataSource = dtQuestions
            rptQuestions.DataBind()

        End If
    End Sub

    Public Sub rptQuestions_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptQuestions.ItemDataBound

        'add dtUsersAnswers & dtCorrectAnswers PLUS a DataRelation to a new DataSet.

        'retrieve the *user's answers* -- DataTable created manually / filled with user data / stored as Session variable
        Dim dtUsersAnswers As DataTable
        dtUsersAnswers = CType(Session("dtUserAnswers"), DataTable)
        dtUsersAnswers.TableName = "dtUsersAnswers"

        'retrieve DataTable with the *correct answers* from SQL
        Dim dtCorrectAnswers As DataTable = DA.GetCorrectAnswers(CInt(dtUsersAnswers.Rows(0).Item("dcModuleID")))
        dtCorrectAnswers.TableName = "dtCorrectAnswers"

        'then declare DataSet that will hold both DataTables and a DataRelation
        Dim ds As New DataSet
        'then add DataTables to DataSet
        ds.Tables.Add(dtUsersAnswers)
        ds.Tables.Add(dtCorrectAnswers)

        'then add DataRelation between the DataTables.
        ds.Relations.Add("AnswersRelation", ds.Tables("dtCorrectAnswers").Columns("QuestionsID"), ds.Tables("dtUsersAnswers").Columns("dcQuestionsID"))

        Dim lt As ListItemType = e.Item.ItemType
        If lt = ListItemType.Item Or lt = ListItemType.AlternatingItem Then


       **** NEED CODE HERE TO POPULATE LITERAL CONTROLS WITH DATA: Literal "ltrStudentAnswer" with data from ds.Tables("dtUserAnswers").Columns("AnswersID") and literal                                                                        "ltrCorrectAnswer" with data from ds.Tables("dtCorrectAnswers").Columns("CorrectAnswer")

        End If
       
    End Sub

============================================

And here is the html for the Repeater:

============================================

<asp:repeater id="rptQuestions" runat="server" OnItemDataBound="rptQuestions_ItemDataBound">
      <HeaderTemplate>
              <ol>
      </HeaderTemplate>
      <ItemTemplate>
            <li>
                  Question:
                  <%# DataBinder.Eval(Container.DataItem, "Questions") %>
                       <div id="hidden" style="visibility: hidden;">
                       <%# DataBinder.Eval(Container.DataItem, "QuestionsID") %>
                       </div>
                  <p>Your Answer:<br \>
                       <asp:Literal ID="ltrStudentAnswer" Runat="server"></asp:Literal></p>
                  <p>Correct Answer:<br \>
                       <asp:Literal ID="ltrCorrectAnswer" Runat="server"></asp:Literal></p>
            </li>
      </ItemTemplate>
      <FooterTemplate>
            </ol>
      </FooterTemplate>
</asp:repeater>

===============================================

It's a fair bit of info, but hopefully it describes what I need more accurately.

Thanks very much,
Jens
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
mrichmon

>>how would I use GetChildRows to get BOTH the student's answer as well as the correct answer?

Basically you wouldn't.  The correct answer should be in the base table with the question correct?  Then you join to the student's answer using a relation.  The get child rows will only return the student answer.

So something like this:

<asp:Repeater id="parentRepeater" runat="server">
<ItemTemplate>
    <%# Eval("Question") %>
    Correct Answer: <%# Eval("CorrectAnswer") %>
    StudentAnswer:
<asp:Repeater id="childRepeater" datasource='<%# ((DataRowView)Container.DataItem).Row.GetChildRows("StudentAnswerRelation") %>' runat="server">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "[\"StudentAnswer\"]")%>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
tmccrank

ASKER
Thanks mrichmon.  I'm going to play around with this for a bit and let you know the results.
J
tmccrank

ASKER
Ok... the column "StudentAnswer" in the nested Repeater has the primary key of the records containing the actual text answer.  The column with the text answer is called "Answers".  How do I get to the contents of the "Answers" column?
Thanks-
J
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
mrichmon

This is done with the relationship and the GetChildRows.

Basically after you add your table to the data set you need to define a relation between the two data tables in that set.

http://msdn2.microsoft.com/en-us/library/system.data.datarelation.aspx

Then the GetChildRows function takes in the name of the relation - and the only rows that you will then have in that repeater will be the exact row you are looking for (if the realtion was on the primary key)

You could use  a similar method to have a master/teacher view that shows each student answer - then all student rows would be in the raltion and you would be able to do something like:

Question A
Correct Answer:
Student 1 Answer:
Student 2 Answer:
Student 3 Answer:

Question B
Correct Answer:
Student 1 Answer:
Student 2 Answer:
Student 3 Answer:

etc...
tmccrank

ASKER
Thanks mrichmon, really appreciate your help.

I'm feeling a bit lost here.  The concept that you're describing makes sense to me, it's just the implementation that's got me.

I've used a DataTable or DataView to bind to a control before, so I understand more or less how that works -- both in the code-behind (rptQuestions.DataSource = dtQuestions), and on the aspx page (<%# DataBinder.Eval(Container.DataItem, "Questions") %>).

But in this case you're only specifying the DataRelation I've established between two DataTables in a DataSet?  Do I still need to specify a datsource for the Repeater in the code-behind if the DataSource is part of the Repeater html tag?   (DataSource='<%# ((DataRowView)Container.DataItem).Row.GetChildRows("AnswersRelation") %>'>)

Could you provide the missing code for me?  This is from the rptQuestions_ItemDataBound event for the first (parent) Repeater:

 'retrieve the user's answers
        Dim dtUsersAnswers As DataTable
        dtUsersAnswers = CType(Session("dtUserAnswers"), DataTable)

        dtUsersAnswers.TableName = "dtUsersAnswers"

        'retrieve DataTable with correct answers
        Dim dtCorrectAnswers As DataTable = DA.GetCorrectAnswers(CInt(dtUsersAnswers.Rows(0).Item("dcModuleID")))
        dtCorrectAnswers.TableName = "dtCorrectAnswers"

        'declare DataSet that will hold DataTables and a DataRelation
        Dim ds As New DataSet
        'then add DataTables to DataSet
        ds.Tables.Add(dtUsersAnswers)
        ds.Tables.Add(dtCorrectAnswers)

        'then add DataRelation between the DataTables.
        ds.Relations.Add("AnswersRelation", ds.Tables("dtCorrectAnswers").Columns("QuestionsID"), ds.Tables("dtUsersAnswers").Columns("dcQuestionsID"))

        Dim lt As ListItemType = e.Item.ItemType
        If lt = ListItemType.Item Or lt = ListItemType.AlternatingItem Then

            'find the nested rptUserAnswers control
            Dim rptStudentAnswer As Repeater = CType(e.Item.FindControl("rptStudentAnswer"), Repeater)

            'if the Repeater exists, then
            If Not rptStudentAnswer Is Nothing Then


                    *** ??? ***

                    rptUserAnswers.DataSource = *** ??? ***
                    rptUserAnswers.DataBind()
            End If
        End If
    End Sub

Thank you,
Jens
ASKER CERTIFIED SOLUTION
mrichmon

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
tmccrank

ASKER
Awesome.  Thanks so much, I'm understanding more and more... but as they say, "Knowledge brings a greater perception of ignorance"...!  Oh well, learning about this stuff can be fun though.  I'm still fiddling around with it but wanted to thank you for your efforts right away... I'm sure this has me on the right track.

Question: When I run the project I'm getting a compilation error at the child Repeater saying that the name DataRowView is not declared:

<asp:Repeater ID="rptStudentAnswer" Runat="server" DataSource='<%# ((DataRowView)Container.DataItem).Row.GetChildRows("relCorrectAnswers_UserAnswers") %>'>

I realize that I need to create a DataRowView, but where, and how is it utilized?

Here's my code so far:

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'retrieve uswer info --> display on page
        lblUserPrincipal.Text = "You are logged on as: " & strAuthUserName.Remove(0, strAuthUserName.LastIndexOf("\") + 1)

        If Not Page.IsPostBack Then

            'retrieve user's answers DataTable from Session variable.
            Dim dtUsersAnswers As DataTable
            dtUsersAnswers = CType(Session("dtUserAnswers"), DataTable)

            'retrieve questions
            Dim dtQuestions As DataTable = DA.PopulateQuestions(CInt(dtUsersAnswers.Rows(0).Item("dcModuleID")))

            'retrieve correct answers
            Dim dtCorrectAnswers As DataTable = DA.GetCorrectAnswers(CInt(dtUsersAnswers.Rows(0).Item("dcModuleID")))

            'create DataSet to hold DataTables
            Dim ds As DataSet

            'add DataTables
            ds.Tables.Add(dtQuestions)
            ds.Tables.Add(dtUsersAnswers)
            ds.Tables.Add(dtCorrectAnswers)

            'add relationships between the DataTables
            ds.Relations.Add("relQuestions_CorrectAnswers", ds.Tables("dtQuestions").Columns("QuestionsID"), _
                ds.Tables("dtCorrectAnswers").Columns("QuestionsID"))
            ds.Relations.Add("relCorrectAnswers_UserAnswers", ds.Tables("dtCorrectAnswers").Columns("QuestionsID"), _
                ds.Tables("dtUsersAnswers").Columns("dcQuestionsID"))

            'bind the questions Repeater to dtQuestions DataTable
            rptQuestions.DataSource = ds.Tables("dtQuestions") 'rptQuestions auto-binds to first Table in the DataSet
            rptQuestions.DataBind()
        End If
    End Sub


Thanks again,
Jens
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
mrichmon

You may need a "using System.Data" on the backend or an <%@ import namespece="System.Data" %> on the front end
tmccrank

ASKER
I used <%@ import namespece="System.Data" %> on the front end.  Now getting "'DataRowView' is a type and cannot be used as an expression."
tmccrank

ASKER
I got it.  I'm using VB.NET and was using your C# script:

DataSource='<%# CType(Container.DataItem, DataRowView).Row.GetChildRows("relCorrectAnswers_UserAnswers") %>'>

Thanks again for all your help.

Jens
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
mrichmon

yeah, I thought I mentioned that at one point, but maybe not.

Sorry.