15 Replies Latest reply on Dec 18, 2008 3:57 PM by Newsgroup_User

    Repeater with filtered arrayCollection?

    Ethan Kurtz
      I'm building a quiz/survey application where the questions and the answers are stored in 2 separate arrayCollections. The first repeater (of the questions) creates a canvas for each question inside of a viewstack component, as well as filtering the second arrayCollection of answer choices based on the current question. This works fine, but when I use the filtered array as the dataprovider for the nested repeater that outputs the answer choices, all questions end up with the same answer choices.

      As the questions are created, I'm alerting the answer choices and the filter is working, but it's obviously a binding problem/issue of some kind that's causing my problem.

      How do I force each question to only use the filtered arrayCollection as the dataProvider?

      Ethan
        • 1. Re: Repeater with filtered arrayCollection?
          ntsiii Level 3
          Apply the filter in the repeated component. Make a copy of the dataProvider AC if needed using:
          var acFiltered:ArrayCollection = new ArrayCollection(AC.source.concat());
          then apply the filter to that.

          Tracy
          • 2. Re: Repeater with filtered arrayCollection?
            Ethan Kurtz Level 1
            Fantastic Tracy - thanks for the quick reply!
            • 3. Re: Repeater with filterered arrayCollection?
              Level 7

              "ohsu_ek" <webforumsuser@macromedia.com> wrote in message
              news:ghmch7$t5d$1@forums.macromedia.com...
              > I'm building a quiz/survey application where the questions and the answers
              > are
              > stored in 2 separate arrayCollections. The first repeater (of the
              > questions)
              > creates a canvas for each question inside of a viewstack component, as
              > well as
              > filtering the second arrayCollection of answer choices based on the
              > current
              > question. This works fine, but when I use the filtered array as the
              > dataprovider for the nested repeater that outputs the answer choices, all
              > questions end up with the same answer choices.
              >
              > As the questions are created, I'm alerting the answer choices and the
              > filter
              > is working, but it's obviously a binding problem/issue of some kind that's
              > causing my problem.
              >
              > How do I force each question to only use the filtered arrayCollection as
              > the
              > dataProvider?

              Why not just use typed objects where the choices are a property on the
              question object?


              • 4. Re: Repeater with filtered arrayCollection?
                ntsiii Level 3
                Actually, that is pretty much how I would do it. Rather than have two separate arrayCollections, I would have a single dataProvider, with the answers array embedded in a property.

                Normally one would expect the data to be stored in hierarchical fashion like this on the server, and I would use XML as the dataProvider. Passing the question node into the repeated Question component would make the answers node available automatically.

                Tracy
                • 5. Re: Repeater with filtered arrayCollection?
                  Ethan Kurtz Level 1
                  Yes, I'll need to include the answerList for each question as part of the original dataProvider. For some reason, the initial hard coded arrayCollection of answers would filter fine using Tracy's example, but once I started pulling data in from a cfc/sql server, the filterFunction no longer works
                  • 6. Re: Repeater with filtered arrayCollection?
                    Ethan Kurtz Level 1
                    I've changed the cfc so that the answers to each question are included in a cell in the returned recordset as an array. However, flex seems to have a hard time figuring out what it is I'm trying to do - here's part of the code:

                    -----------
                    on result of remote object:

                    questionsArray = event.result[1];

                    event result is an array of 2 items - the first is general info about the quiz (name, etc), and the second is a resultset of the questions:

                    -question text
                    -question id
                    -answer type (radiobutton, etc)
                    -array of answer choices

                    I can easily access the question text, etc using dot notation of
                    questionsArray[0].qText, etc

                    but how do I access the array of answer choices?

                    questionsArray[0].qAnswerChoices.aText
                    - or -
                    questionsArray[0].qAnswerChoices[0].aText

                    do not work

                    qAnswerChoices is a column in the questions resultset containing an array for each row/question

                    Any ideas on how to use that property as a dataProvider?
                    • 7. Re: Repeater with filtered arrayCollection?
                      Level 7

                      "ohsu_ek" <webforumsuser@macromedia.com> wrote in message
                      news:gi9hlt$ma1$1@forums.macromedia.com...
                      > I've changed the cfc so that the answers to each question are included in
                      > a
                      > cell in the returned recordset as an array. However, flex seems to have a
                      > hard
                      > time figuring out what it is I'm trying to do - here's part of the code:
                      >
                      > -----------
                      > on result of remote object:
                      >
                      > questionsArray = event.result[1];
                      >
                      > event result is an array of 2 items - the first is general info about the
                      > quiz
                      > (name, etc), and the second is a resultset of the questions:
                      >
                      > -question text
                      > -question id
                      > -answer type (radiobutton, etc)
                      > -array of answer choices
                      >
                      > I can easily access the question text, etc using dot notation of
                      > questionsArray[0].qText, etc
                      >
                      > but how do I access the array of answer choices?
                      >
                      > questionsArray[0].qAnswerChoices.aText
                      > - or -
                      > questionsArray[0].qAnswerChoices[0].aText

                      This latter should work. Can you post a screen shot of what this data
                      structure looks like in the debugger?

                      HTH;

                      Amy


                      • 8. Re: Repeater with filtered arrayCollection?
                        Ethan Kurtz Level 1
                        Hi Amy,

                        Here's a screenshot of the debugger - it looks like the query object being inserted into the initial recordset is being processed differently than I thought it would:

                        Data Screenshot

                        This is what the cfc is doing to add the answers to the initial questions query/recordset:

                        <!--- get answers --->
                        <cfloop query="getSurveyQuestions">
                        <cfquery name="getSurveyAnswers" datasource="#request.dsn#">
                        select * from surveyAnswers
                        where qID = <cfqueryparam cfsqltype="cf_sql_integer" value="#getSurveyQuestions.qID#">
                        </cfquery>

                        <cfset getSurveyQuestions.qAnswerChoices = '#getSurveyAnswers#'>


                        </cfloop>

                        Looks like I need to update what is happening in the cfc

                        • 9. Re: Repeater with filtered arrayCollection?
                          Level 7

                          "ohsu_ek" <webforumsuser@macromedia.com> wrote in message
                          news:gibcad$3u4$1@forums.macromedia.com...
                          > Hi Amy,
                          >
                          > Here's a screenshot of the debugger - it looks like the query object being
                          > inserted into the initial recordset is being processed differently than I
                          > thought it would:
                          >
                          > http://www.hungryraccoon.com/dev/surveyData.jpg
                          >
                          > This is what the cfc is doing to add the answers to the initial questions
                          > query/recordset:
                          >
                          > <!--- get answers --->
                          > <cfloop query="getSurveyQuestions">
                          > <cfquery name="getSurveyAnswers"
                          > datasource="#request.dsn#">
                          > select * from surveyAnswers
                          > where qID = <cfqueryparam cfsqltype="cf_sql_integer"
                          > value="#getSurveyQuestions.qID#">
                          > </cfquery>
                          >
                          > <cfset getSurveyQuestions.qAnswerChoices =
                          > '#getSurveyAnswers#'>
                          >
                          >
                          > </cfloop>
                          >
                          > Looks like I need to update what is happening in the cfc
                          >

                          Yes, I'm not much on ColdFusion, but I can tell you that the approach I'd
                          take is to create a join that gives me the question and each answer in the
                          same row.

                          So it might look something like this:
                          QuestionID Stem AnswerID
                          AnswerText IsCorrect
                          1 "What is the Capital of Peru" 1
                          Bogata false
                          1 "What is the Capital of Peru" 2
                          Lima true
                          1 "What is the Capital of Peru" 3 La
                          Jolla false
                          1 "What is the Capital of Peru" 4
                          Jakarta false
                          2 "What is the biggest US State" 5
                          Texas false
                          ....
                          That way, instead of hitting your database n+1 times (where n is the number
                          of questions), you're only hitting it once.

                          Then in your loop you store the QuestionID and create a new question when
                          that changes.

                          HTH;

                          Amy


                          • 10. Re: Repeater with filtered arrayCollection?
                            Ethan Kurtz Level 1
                            I'm not able to do a join because there are multiple answer choices for each question. I'm going back to the drawing board using a filterFunction on an arrayCollection of all the answer choices (ordered by question ID). If I have a hardcoded arrayCollection, the fillter works fine, but coming back from the function out of coldfusion it does not do the comparison correctly. I looked at the data inside the hard-coded dataset and the dataset from the function and the only difference is that the two ID fields (answer and question ID) look like this (via debugger):

                            query-driven dataset
                            ---------------------------
                            [0] aCorrect 0
                            aID 1 [0x34]
                            aText "False"
                            qID 15 [0xF]

                            hard coded
                            --------------------
                            [0] aCorrect 0
                            aID 1
                            aText "False"
                            qID 15


                            What does that bracketed notation after the ID fields signify? Is it somehow related to the type of variable (int) that is being sent back to flex from CF in the recordset?

                            If I use the same filter function with the hard-coded array, it works fine, but the filter does not match up the qID from the object being passed in with the current record in the question array - here is what I am doing with that

                            repeaters
                            -----------------------
                            <mx:Repeater id="questionList" dataProvider="{questionsArray}" >
                            <mx:Canvas width="100%" height="100%">
                            <mx:VBox width="100%" height="100%" id="answerList">
                            <mx:Repeater id="answerChoices" dataProvider="{buildAnswers(questionList.currentIndex)}">
                            <custom:answerComp id="answerOption" textBoxText="{answerChoices.currentItem.aText}" cState="{questionList.currentItem.qAnswerType}"/>
                            <!--comboData="{questionList.currentItem.answerData}"-->
                            </mx:Repeater>
                            </mx:VBox>
                            </mx:Canvas>
                            </mx:Repeater>

                            functions
                            -------------
                            public function buildAnswers(questionNumber:int):ArrayCollection{
                            // set question number

                            var acFiltered:ArrayCollection = new ArrayCollection();
                            acFiltered.filterFunction = null;
                            acFiltered.refresh();

                            //filter answer choices based on current question ID and return data to repeater

                            acFiltered.filterFunction = filterAnswers;
                            acFiltered.refresh();

                            return acFiltered;

                            }

                            public function filterAnswers(item:Object):Boolean{
                            return (item.qID == questionsArray[questionArrayPosition].qID)

                            }

                            I haven't used the filterFunction that often, so if I am accepting the question ID from the repeater as part of the dataProvider set up as the wrong type (int in database), please let me know. I feel I'm really close and this is pretty frustrating...

                            Thanks

                            Ethan


                            • 11. Re: Repeater with filtered arrayCollection?
                              Level 7

                              "ohsu_ek" <webforumsuser@macromedia.com> wrote in message
                              news:gie12c$hs8$1@forums.macromedia.com...
                              > I'm not able to do a join because there are multiple answer choices for
                              > each
                              > question.

                              Huh? Did you _look_ at the sample recordset I showed you? I have been
                              producing eLearning applications that connect to databases to retrieve quiz
                              type data for almost 10 years now and using at least 3 different database
                              products and probably 5 different technologies to connect to those
                              databases, and I can tell you that the approach I told you is _very_
                              standard, regardless of how many answers each question might have.

                              The only exception is when you're using a MS type product (Access, SQL
                              Server, or a variant), you have the option of using a Shape query. Shape
                              queries are really cool, but can be a pain to get your head around, so many
                              people choose to just use a "flat" join query even when you have the option
                              of shaped data.

                              I looked for some ColdFusion examples to try to show you how this works, but
                              my quick search didn't yield much. This is not CF and it's not a quiz, but
                              maybe you can extrapolate:

                              http://aspnet.4guysfromrolla.com/ASPScripts/PrintFAQ.asp?FAQID=154

                              Note the place where it says "BAD CODE! DO NOT DO THIS!" That's exactly
                              what you're doing in CF, but in ASP.

                              > I'm going back to the drawing board using a filterFunction on an
                              > arrayCollection of all the answer choices (ordered by question ID).

                              If you insist on doing it this way, you'd be better off returning the entire
                              flat joined data set as above, but using a GroupingCollection to organize
                              it. This is a bit wasteful, though, because you'd be passing the repeated
                              stem data through to the client rather than only passing through the needed
                              data. I do feel that your basic issue is you're not strong on the CF side.


                              > If I have
                              > a hardcoded arrayCollection, the fillter works fine, but coming back from
                              > the
                              > function out of coldfusion it does not do the comparison correctly. I
                              > looked
                              > at the data inside the hard-coded dataset and the dataset from the
                              > function and
                              > the only difference is that the two ID fields (answer and question ID)
                              > look
                              > like this (via debugger):
                              >
                              > query-driven dataset
                              > ---------------------------
                              > [0] aCorrect 0
                              > aID 1 [0x34]
                              > aText "False"
                              > qID 15 [0xF]
                              >
                              > hard coded
                              > --------------------
                              > [0] aCorrect 0
                              > aID 1
                              > aText "False"
                              > qID 15
                              >
                              >
                              > What does that bracketed notation after the ID fields signify? Is it
                              > somehow
                              > related to the type of variable (int) that is being sent back to flex from
                              > CF
                              > in the recordset?

                              The bracketed notation is the uint equivalent of the number. I'd click on
                              the line in the debugger and look to see if it really is in there as in int
                              in both cases.

                              > If I use the same filter function with the hard-coded array, it works
                              > fine,
                              > but the filter does not match up the qID from the object being passed in
                              > with
                              > the current record in the question array - here is what I am doing with
                              > that
                              >
                              > repeaters
                              > -----------------------
                              > <mx:Repeater id="questionList" dataProvider="{questionsArray}" >
                              > <mx:Canvas width="100%" height="100%">
                              > <mx:VBox width="100%" height="100%" id="answerList">
                              > <mx:Repeater id="answerChoices"
                              > dataProvider="{buildAnswers(questionList.currentIndex)}">
                              > <custom:answerComp id="answerOption"
                              > textBoxText="{answerChoices.currentItem.aText}"
                              > cState="{questionList.currentItem.qAnswerType}"/>
                              > <!--comboData="{questionList.currentItem.answerData}"-->
                              > </mx:Repeater>
                              > </mx:VBox>
                              > </mx:Canvas>
                              > </mx:Repeater>
                              >
                              > functions
                              > -------------
                              > public function buildAnswers(questionNumber:int):ArrayCollection{
                              > // set question number
                              >
                              > var acFiltered:ArrayCollection = new ArrayCollection();
                              > acFiltered.filterFunction = null;
                              > acFiltered.refresh();
                              >
                              > //filter answer choices based on current question ID and return data to
                              > repeater
                              >
                              > acFiltered.filterFunction = filterAnswers;
                              > acFiltered.refresh();
                              >
                              > return acFiltered;
                              >
                              > }
                              >
                              > public function filterAnswers(item:Object):Boolean{
                              > return (item.qID == questionsArray[questionArrayPosition].qID)
                              >
                              > }
                              >
                              > I haven't used the filterFunction that often, so if I am accepting the
                              > question ID from the repeater as part of the dataProvider set up as the
                              > wrong
                              > type (int in database), please let me know. I feel I'm really close and
                              > this
                              > is pretty frustrating...

                              I'd put a break point in the filterAnswers function and look closely at what
                              the values of item.qID and questionsArray[questionArrayPosition].qID are at
                              that point, including data types.

                              HTH;

                              Amy


                              • 12. Repeater with filtered arrayCollection?
                                Ethan Kurtz Level 1
                                I cannot do a join because that would give each question multiple rows, which breaks the model of having an arrayCollection of dynamic questions - remember how the questionsArray feeds the initial repeater?

                                The only reason I changed the code to loop that way is because an idea was suggested to have an array as an object inside each a question's row. To begin with, I did this, and have since gone back to it and am trying to get the filter function to work correctly.

                                <cfquery name="getSurveyQuestions" datasource="#request.dsn#">
                                select qID,qText,qAnswerType from surveyQuestions
                                where sID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.sID#">
                                order by sID
                                </cfquery>

                                <cfquery name="getSurveyAnswers" datasource="#request.dsn#">
                                select * from surveyAnswers
                                where qID in (#valuelist(getSurveyQuestions.qID)#)
                                order by qID
                                </cfquery>


                                I'm admittedly frustrated, but while I'm new to Flex, I'm not new to coldfusion and would appreciate not being criticized regarding portions of the posting that have no bearing on the outcome.

                                I was looking for help regarding the filter function, but it appears I should look elsewhere
                                • 13. Re: Repeater with filtered arrayCollection?
                                  Level 7

                                  "ohsu_ek" <webforumsuser@macromedia.com> wrote in message
                                  news:giee7e$4bh$1@forums.macromedia.com...
                                  >I cannot do a join because that would give each question multiple rows,
                                  >which
                                  > breaks the model of having an arrayCollection of dynamic questions -
                                  > remember
                                  > how the questionsArray feeds the initial repeater?

                                  No it doesn't. You do the join in ColdFusion, but by the time Flex sees it,
                                  you've sent back hierarchical objects. Did you read the article I sent you
                                  to?

                                  > The only reason I changed the code to loop that way is because an idea was
                                  > suggested to have an array as an object inside each a question's row. To
                                  > begin with, I did this,

                                  I don't think you actually did it successfully. It looks like what might
                                  have happened is that your inner and outer loops somehow got out of synch so
                                  you were populating only one answer per question, with the rest blank, but
                                  you didn't have enough records "open" in your screen grabs for me to really
                                  see what was going on.

                                  > and have since gone back to it and am trying to get the
                                  > filter function to work correctly.

                                  I'm thinking that's a dead end.

                                  > I'm admittedly frustrated, but while I'm new to Flex, I'm not new to
                                  > coldfusion and would appreciate not being criticized regarding portions of
                                  > the
                                  > posting that have no bearing on the outcome.

                                  (1) If you're not new to CF, you really deserve the criticism, since this
                                  is a very standard way of doing a basic task you should be familiar with.
                                  (2) You contacted me off list and asked me to come back and look at this
                                  again, which means that rather than letting it lie I told you what I
                                  thought.
                                  (3) I did help you with the filterFunction. Did you try what I
                                  suggested?


                                  • 14. Re: Repeater with filtered arrayCollection?
                                    Ethan Kurtz Level 1
                                    If you read my posting, you would understand that a join between the answers and questions table will not work. Your example showed 4 rows for the same question because there were that many answer choices. I'm DYNAMICALLY building the questions based on the number of rows returned, so that's completely pointless being as how I don't want to display the same question 4 times.

                                    I'm not making a call back to the data everytime a question is created, which is why I want to filter the answer dataset on the client side to make the application faster.

                                    I did read your asp article, and I agree that it's bad practice to loop over a query to get additional data. That is exactly why I wanted the filter function to work against a second recordset of answer choices ordered by question id. Since it doesn't appear to work as I think it should, then I'm done.

                                    Thanks Tracy for your help above - I'm moving on now
                                    • 15. Re: Repeater with filtered arrayCollection?
                                      Level 7

                                      "ohsu_ek" <webforumsuser@macromedia.com> wrote in message
                                      news:gielfm$d35$1@forums.macromedia.com...
                                      > If you read my posting, you would understand that a join between the
                                      > answers
                                      > and questions table will not work. Your example showed 4 rows for the
                                      > same
                                      > question because there were that many answer choices. I'm DYNAMICALLY
                                      > building
                                      > the questions based on the number of rows returned, so that's completely
                                      > pointless being as how I don't want to display the same question 4 times.

                                      <sigh> If you'd read the article I sent you to, you would have seen that
                                      this is typical and that there is a way to handle it that's been in use by
                                      back end programmers for years and years. You look at the question ID at
                                      each loop and if the question ID has changed , you create a new question.
                                      In every loop, whether you have created a new question or not, you add a new
                                      answer. So you only get _one_ question (for each question id) with multiple
                                      child answers.

                                      > I'm not making a call back to the data everytime a question is created,
                                      > which
                                      > is why I want to filter the answer dataset on the client side to make the
                                      > application faster.

                                      No one asked you to. What I was suggesting was that you make one call.
                                      Period.

                                      > I did read your asp article, and I agree that it's bad practice to loop
                                      > over a
                                      > query to get additional data.

                                      But apparently didn't get the "gist" of what it was saying.

                                      > That is exactly why I wanted the filter function
                                      > to work against a second recordset of answer choices ordered by question
                                      > id.
                                      > Since it doesn't appear to work as I think it should, then I'm done.
                                      >
                                      > Thanks Tracy for your help above - I'm moving on now

                                      Yes, it's clear that for whatever reason you're not understanding what I'm
                                      saying and it's useless for me to try to help you further.