MCVC Model - Part 2

December 26th, 2007

So you learned how to handle a model’s name, as well as passing in a config object and bind the model to the controller here. Now we will move on to the real fun like loading xml data into the model and understanding its’ timers as well as the event system.

To refresh our memories, here is a clip of the event classes.

/**
         * Use this to send data out to external flash applications or other webapps
         */

        public function submit_data(oData : Object) : Void {
        }
       
        /**
         * Used by the Controller to send events back to the Model
         * @param event: Object that contains event data.
         * @example
         *           // Inside instance sending event
         *           var oEvent:Object = {type:’trace’,message:’Put Any Data Here’}
         *           BaseController.new_event(oEvent);
         *           
         *           // This goes inside the model/component’s receive event method
         *           public function receive_event(event : Object) : Void {
         *                var sType:String = event.type;
         *                switch (sType) {
         *                     case "trace" :
         *                          trace(event.message);
         *                     break;
         *                }
         *           }
         */

        public function receive_event(event : Object) : Void {
                var sType:String = event.type;
                switch (sType) {
                        case “event” :
                                //do something
                        break;
                }
        }

So there are two important base methods here. The first is the submit_data() that is used when you want to send data from your model out of the application. When I say out of the application I am referring to the External Interface API, PHP or other language through a get/post request, and when using the Flash Local Connection API.

The receive_event() method is where all events from the BaseController are sent by default when another class sends this model’s instance an event object. Event objects are simple dynamic objects with properties attached to server as a message system between other classes in the application.

I have set up a sample switch statement but your extended class should override this and have a custom switch to interpret and redistribute events it receives. As you can see at the core of the event system is an event with a type value. You should preform the switch on the type. This system is designed to be very open and flexible. You can pass anything through the controller to the model and as long as you are expecting the right data you can have the model react appropriately.

So how do we get some xml data into this model? It is important to keep in mind that these methods simply provide some short cuts for common methods I have always used in my models. Not all models get its data from external xml so when you extend this class just keep in mind that if you need these extra methods they are there at any time.

The load_xml() is a really simple way of handling loading xml then passing it off directly to the correct parser function. Take a look:

/**
         * Standard load_xml method. Use this for a quick way to load xml then send to a custom parser.
         * @param xml_url: Path to xml file.
         * @param parser_name: String preface of the parser method. It defaults to the ‘base_parse_xml’ method.
         */

        public function load_xml(xml_url:String,parser_name:String):Void{
                load_xml_broadcast(xml_url);
                var xmlData:XML = new XML();
                xmlData.ignoreWhite = true;
                var oClass:Object = this;
                // Check for parser_name
                if (!parser_name)
                        parser_name = “base”;
                // On load actions - send xml data to parser
                xmlData.onLoad = function(success:Boolean):Void{
                        if (success)
                                oClass[parser_name+‘_parse_xml’](xmlData);
                        else
                                trace(“ERROR: Could not load xml file at ‘”+xml_url+“‘”);
                       
                };
                // Load XML data
                xmlData.load(xml_url);
        }

To use this method you simply need to pass it in a url to the xml file and an optional name for the parser. By default there is a base_parse_xml() method. The naming convention for parser methods is [NAME_ID]_parse_xml(_data:XML). This is helpful when you have more then one type of data to load and need custom parser for each one.

And here is a sample of the default parser method that needs to be overridden in the extended class.

/**
         * Default XML parser for model. Model parse_xml functions follow this naming convion [custom_name]_parse_xml(xml_data:XML)
         * When using the naming convention and the load_xml method it is possible to set up several parsers for any model.
         * @param xml_data: XML automatically supplied buy the load_xml method.
         */

        private function base_parse_xml(xml_data:XML):Void{
                trace(“Ready to parse xml data:”+newline+xml_data);
        }

When it comes to parsing the data there are a few methods you can use to quickly clean up the xml:

  • clean_up_nodes(xmlData:XMLNode) - Convert simple xml nodes into an object.
  • clean_up_attributes(xmlNode:XMLNode) - This will go through a nodes attributes and put them into an object.
  • clean_up_typed_nodes(xmlData:XMLNode) - Convert simple xml nodes into a correctly typed value.

I am not going to get into them in great detail here because they are well documented in the code.

It is important to note that there is also a function that is always called after an xml has been loaded. To access this feature, simply override this method in your extended model and you can have it send off an event upon xml load instead of having it trace out by default. Here is that method:

/**
         * Use this to update a preloader of data loading status or trigger an event in the Model.
         */

        private function load_xml_broadcast(xml_url:String):Void{
                trace(“ALERT: Now loading ‘”+xml_url+“‘”);     
        }

The final methods are all timer related. There is not much to mention here except to note how on the start_timer you can pass in a id as a string to look up later in the _aTimers array. This way when you need to manipulate it through the stop_timer method you can easily look it up. Also, the set_timeout is a really great exposure of an undocumented class in AS 2 called “setTimeout” that allows you to created a 1 time only timer that removes itself from memory when it is completed.

private function start_timer(id:String,scope:Object,function_name:String,time:Number,data:Object):Number{
               
                if (time > 0){
                        var nTimer_id:Number = setInterval(scope,function_name,time,data);
                       
                        _aTimers[id] = nTimer_id;
                       
                        return nTimer_id;
                       
                }else{
                       
                        return null;   
               
                }
        }
       
        private function set_timeout(id:String,scope:Object,function_name:String,time:Number,data:Object):Boolean{
               
                if (time > 0){
               
                        _global[’setTimeout’](scope,function_name,time,data);
                       
                        return true;
               
                }else{
               
                        return false;   
               
                }
               
        }
       
        private function stop_timer(id:String):Void{
                clearInterval(_aTimers[id]);
                delete _aTimers[id];
        }

As you can see these methods simply clean up existing Flash API calls and help organize your timers a little better. Pass in the function name to have it called when the timer or setTimeout is triggered. This is a good thing to use with models that are constantly reloading live data.

So that is the Model. Next up is the BaseController class here.

Leave a Reply