0 Replies Latest reply on Feb 23, 2012 9:39 AM by hobbes26

    Can anyone solve this simple MVC problem with ArrayCollection

    hobbes26

      I have very simple application trying to understand how to apply MVC without any framework. There are quite a few exemples on the net but most do not deal with complex data.

      here is my application with 4 files: MVCtest.mxml, MyController.as, MyModel.as and MyComponent.as

       

      first the Model MyModel.as

      package model
      {
      import flash.events.Event;
      import flash.events.EventDispatcher;
      import flash.events.IEventDispatcher;

      import mx.collections.ArrayCollection;

      [Event(name="ArrayColChanged", type="flash.events.Event")]

      [Bindable]
      public class MyModel extends EventDispatcher
      {
        private static var instance:MyModel;
       
        public static const ARRAYCOL_CHANGED:String = "ArrayColChanged";
       
        private var _myArrayCol:ArrayCollection;
       
        public function MyModel(target:IEventDispatcher=null)
        {
         super(target);
         instance = this;
        }
       
        public static function getInstance():MyModel
        {
         if(instance == null)
         {
          instance = new MyModel();
         }
         return instance;
        }

        public function get myArrayCol():ArrayCollection
        {
         return _myArrayCol;
        }

        public function set myArrayCol(value:ArrayCollection):void
        {
         _myArrayCol = new ArrayCollection(value.source);
         dispatchEvent(new Event(ARRAYCOL_CHANGED));
        }

      }
      }

       

      then the controller: MyController.as

      package controller

      {

      import components.MyComponent;

       

      import flash.events.Event;

      import flash.events.EventDispatcher;

      import flash.events.IEventDispatcher;

       

      import model.MyModel;

       

      import mx.collections.ArrayCollection;

      import mx.controls.Alert;

      import mx.rpc.events.FaultEvent;

      import mx.rpc.events.ResultEvent;

      import mx.rpc.remoting.RemoteObject;

       

      public class MyController extends EventDispatcher

      {

        [Bindable]

        public var view:MVCtest;

       

        [Bindable]

        public var componentView:MyComponent;

       

        private var _model:MyModel = MyModel.getInstance();

       

        public function MyController(target:IEventDispatcher=null)

        {

         super(target);

         _model.addEventListener("ArrayColChanged", onArrayColChange);

        }

       

        public function initialise(event:Event):void

        {

         getData();

        }

       

        public function getData():void

        {

         var dataRO:RemoteObject = new RemoteObject;

         dataRO.endpoint = "gateway.php";

         dataRO.source = "MytestdbService";

         dataRO.destination = "MytestdbService";

         dataRO.addEventListener(ResultEvent.RESULT, dataROResultHandler);

         dataRO.addEventListener(FaultEvent.FAULT, dataROFaultHandler);

         dataRO.getAllMytestdb();   

        }

       

        public function dataROResultHandler(event:ResultEvent):void

        {

         _model.myArrayCol = new ArrayCollection((event.result).source);

        }

       

        public function dataROFaultHandler(event:FaultEvent):void

        {

         Alert.show(event.fault.toString());

        }

       

        public function onArrayColChange(event:Event):void

        {

         componentView.myDataGrid.dataProvider = _model.myArrayCol;

        }

      }

      }

       

      This is the main application: MVCtest.mxml

      <?xml version="1.0" encoding="utf-8"?>

      <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

            xmlns:s="library://ns.adobe.com/flex/spark"

            xmlns:mx="library://ns.adobe.com/flex/mx"

            xmlns:controller="controller.*"

            xmlns:components="components.*"

            width="600" height="600"

            creationComplete="control.initialise(event)">

      <fx:Declarations>

        <controller:MyController id="control" view = "{this}"/>

      </fx:Declarations>

      <fx:Script>

        <![CDATA[

         import model.MyModel;

         import valueObjects.MyVOorDTO;

         [Bindable]

         private var _model:MyModel = MyModel.getInstance();

        ]]>

      </fx:Script>

      <s:VGroup paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

        <s:Label fontSize="20" fontWeight="bold" text="MVC Test with components"

           verticalAlign="middle"/>

        <components:MyComponent/>

      </s:VGroup>

      </s:Application>

       

      And this is the component: MyComponent.mxml

      <?xml version="1.0" encoding="utf-8"?>

      <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"

         xmlns:s="library://ns.adobe.com/flex/spark"

         xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">

      <s:layout>

        <s:VerticalLayout paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"/>

      </s:layout>

      <fx:Declarations>

        <!-- Place non-visual elements (e.g., services, value objects) here -->

      </fx:Declarations>

      <s:Label fontSize="16" fontWeight="bold" text="My Component " verticalAlign="bottom"/>

      <s:DataGrid id="myDataGrid" width="100%" height="100%" requestedRowCount="4">

        <s:columns>

         <s:ArrayList>

          <s:GridColumn dataField="mystring" headerText="String"></s:GridColumn>

          <s:GridColumn dataField="myinteger" headerText="Integer"></s:GridColumn>

          <s:GridColumn dataField="myreal" headerText="Real"></s:GridColumn>

          <s:GridColumn dataField="mydate" headerText="Date"></s:GridColumn>

         </s:ArrayList>

        </s:columns>

      </s:DataGrid>

      </s:Group>

       

      Here is the code to generate the database:

       

      CREATE DATABASE mytest;

      CREATE TABLE myTestDB
      (
            myid INT UNSIGNED NOT NULL AUTO_INCREMENT,
            mystring CHAR(15) NOT NULL,
            myinteger INT NOT NULL,
            myreal DECIMAL(6,2) NOT NULL,
            mydate DATE NOT NULL,

            PRIMARY KEY(myid)
      ) ENGINE = InnoDB;

       

      INSERT INTO myTestDB (mystring, myinteger, myreal, mydate) VALUES ('Test', 123, 45.67, '2012-01-01'), ('Practice', 890, 12.34, '2012-02-01'), ('Assay', 567, 78.90, '2011-10-01'), ('Trial', 111, 22.22, '2009-09-09'), ('Experiment', 333, 44.44, '1999-04-15'), ('Challenge', 555, 66.66, '2012-12-21');


      And finally here is the PHP script.

       

      <?php

       

      class myVOorDTO

      {

        var $_explicitType = "valueObjects.myVOorDTO";

       

        public $myid;
        public $mystring;

        public $myinteger;

        public $myreal;

        public $mydate;


        public function __construct()

        {

          $this->myid = 0;
          $this->mystring = "";

          $this->myinteger = 0;

          $this->myreal = 0.0;

          $this->mydate = date("c");

        }

      }


      class MytestdbService
      {


        var $username = "yourusername";
        var $password = "yourpassword";

        var $server = "yourserver";

        var $port = "yourport";

        var $databasename = "mytest";

        var $tablename = "mytestdb";

        var $connection;

        public function __construct()
        {
          $this->connection = mysqli_connect(
          $this->server, $this->username, $this->password, $this->databasename, $this->port);

        }


      /**

      * Returns all the rows from the table.

      *

      * @return myVOorDTO

      */

        public function getAllMytestdb()

        {

          $query = "SELECT * from $this->tablename";

          $result = mysqli_query($this->connection, $query);


          $results = array();


          while ($obj = mysqli_fetch_assoc($result))

          {
            $row = new myVOorDTO();

            $row->myid = $obj['myid'] + 0;

            $row->mystring = $obj['mystring'];

            $row->myinteger = $obj['myinteger'] + 0;

            $row->myreal = $obj['myreal'] + 0.0;

            $row->mydate = new Datetime($obj['mydate']);
            array_push($results, $row);

          }
          return $results;
        }
      }

      ?>

       

      My understanding as to what is going on is: (1) on creation complete the application launch the initialise() function of the controller (2) this function starts the remoteObject which get the data (3) once the results arrive the resultHandler store the data into the ArrayCollection of the model ***this does not work*** (4) even if part 3 did not work, the setter of the ArrayCollection in the model send an event that it has been changed (5) the controller receive this event and assigns the ArrayCollection of the model as the dataprovider for the datagrid in the compoent.

       

      Of course, since the ArrayCollection is null, the application gives an error as the dataProvider for the datagrid is null.

      What is missing in this application to make it work properly? I believe this is an example that could help a lot of people.

      Even if I change the setter in the model to _myArrayCol = ObjectUtil.copy(value) as ArrayCollection; it still does not work.

      Also, it seems that the remoteObject does not return a typed object (i.e. myVOorDTO) but rather generic objects. I am usually able to make this works but in this particular application I have not managed to do it. Again what's missing?

       

      Thanks for any help with this!