1 Reply Latest reply on Aug 9, 2007 12:17 PM by ntsiii

    Multiple HTTPService send() calls


      I'm new to Flex, and am trying to creat a quiz application that re-uses modular canvases for different question types. Each question is displayed on its own canvas, which is accessed through a TabNavigator.

      Each canvas has its own HTTPService object, which is passed a URL from the main application. I'm a little worried about each instance of the canvas having a HTTPService object with the same id, but it hasn't seemed to cause any problems so far.

      The problem I'm having is that of the four canvases, only two seem to populate with the external XML data from the HTTPService. What's even more weird is that the initially active tab is fine, as is the next tab which is chosen (it doesn't matter whether it's 2, 3 or 4) but the other two tabs remain blank when clicked.


      Main application: (comps.mxml)
      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute"
      creationComplete="loadQuestions()" >
      public function loadQuestions() : void
      <mx:Panel layout="absolute" left="10" top="10" bottom="10" right="10" id="mainPanel" title="Quiz Application">
      <mx:TabNavigator top="0" left="0" bottom="10" right="0" id="tabby">
      <mx:Canvas label="Question 1" width="100%" height="100%" activate="{mcq1.questionData.send()}">
      <custom:MCQCanvas id="mcq1" xmlURL="single.xml" left="10" top="10">
      <mx:Canvas label="Question 2" width="100%" height="100%" activate="{mcq2.questionData.send()}">
      <custom:MCQCanvas id="mcq2" xmlURL="secondSingle.xml" left="10" top="10">
      <mx:Canvas label="Question 3" width="100%" height="100%" activate="{mcq3.questionData.send()}">
      <custom:MCQCanvas id="mcq3" xmlURL="thirdSingle.xml" left="10" top="10">
      <mx:Canvas label="Question 4" width="100%" height="100%" activate="{mcq4.questionData.send()}">
      <custom:MCQCanvas id="mcq4" xmlURL="fourthSingle.xml" left="10" top="10">


      Canvas component: (MCQCanvas.mxml)
      <?xml version="1.0" encoding="utf-8"?>
      <mx:Canvas xmlns:mx=" http://www.adobe.com/2006/mxml" width="600" height="300">
      <mx:State name="feedback">
      <mx:AddChild position="lastChild">
      <mx:Text text="{feedbackString}" left="10" top="{myVBox.y + myVBox.height +30}" id="feedbackText"/>
      public var feedbackString:String;
      public var xmlURL:String;

      public function giveFeedback() : void

      if(mcqOpts.selection.value == questionData.lastResult.answer.value)
      feedbackString = questionData.lastResult.items.item.(@value == mcqOpts.selection.value).feedback;
      feedbackString += "\n" + questionData.lastResult.questionFeedback;
      feedbackString = "That's incorrect. " + mcqOpts.selection.label + " is not right. Try again.";
      //feedbackText.text = feedbackString;
      currentState ='feedback';

      <mx:HTTPService url="{xmlURL}" resultFormat="e4x" id="questionData" makeObjectsBindable="true" useProxy="false"/>
      <mx:ArrayCollection id="myArray" source="questionData" />
      <mx:Text id="arrayText" text="{myArray}"/>

      <mx:Text left="10" top="10" id="questionText" text="{questionData.lastResult.questionStem}:" right="10"/>
      <mx:VBox left="10" top="{questionText.y + questionText.height + 10}" id="myVBox">
      <mx:RadioButtonGroup id="mcqOpts" change="{giveFeedback()}"/>
      <mx:Repeater dataProvider="{questionData.lastResult.items.item}" id="options">
      <mx:RadioButton label="{options.currentItem.option}" value="{options.currentItem.@value}" groupName="mcqOpts" left="10"/>


      I haven't provided the XML because the data that DOES populate into the canvases seems to manage this just fine.

      Should I be using a single HTTPService object to manage the multiple XML data requests? What sort of object could I store the HTTPService results in, without binding this data to the actual HTTPService object (i.e. can I store the data in an internal structure and then re-use the HTTPService object ot go retrieve other data without losing the data from the first call)?

        • 1. Re: Multiple HTTPService send() calls
          ntsiii Level 3
          1) Don't bind directly to lastResult. It is too hard to debug. Use a result handler.
          2) "makeObjectsBindable="true" Are you sure you know what you are doing with this?
          3)Individual HTTPService calls should work, but I always use a single instance per application myself. Depending, you can just put the result data into an instance variable, or in an Array, or Dictionary, or AssociativeArray, really, whatever. You identify a specific result event with a specific send() by using AsyncToken.

          Here are some snippets that show most of this.
          Sample code using HTTPService, e4x, handler function to populate a list item.
          Also shows usage of AsyncToken.

          The DataGrid tag:
          <mx:DataGrid id="dg" dataProvider="{_xlcMyListData}" .../>

          The HTTPService tag:
          <mx:HTTPService id="service" resultFormat="e4x" result="onResult(event)" fault="..../>

          Script block declaration:
          import mx.rpc.Events.ResultEvent;
          [Bindable]private var _xlcMyListData:XMLListCollection;

          Invoke send:
          var oRequest:Object = new Object();
          oRequest.Arg1 = "value1";
          var callToken:AsyncToken = service.send(oRequest);
          token.callId = "myQuery1";

          Result Handler function:
          private function onResult(oEvent:ResultEvent):void {
          var xmlResult:XML = XML(event.result); //converts result Object to XML. can also use "as" operator
          var xlMyListData:XMLList = xmlResult.myListData; //depends on xml format, is row data
          _xlcMyListData = new XMLListCollection(xlMyListData); //wrap the XMLList in a collection
          trace(_xlcMyListData.toXMLString()); //so you can see exactly how to specify dataField or build labelFunction
          var callToken:AsyncToken = oEvent.token;
          var sCallId = callToken.callId; //"myQuery1"
          switch(sCallId) {
          case "myQuery1":