4 Replies Latest reply on Jan 6, 2012 3:49 AM by pjetr_be

    Catch MXML children before they get added to the parent component

    ratnawe Level 1

      Hi Flexers,

       

      is there a way to grasp the children of an MXML component (e.g. Labels inside a Group) like this

       

      <s:Group>

        <s:Label id="label1" />

        <s:Label id="label2" />

      </s:Group>

       


      before they get added to the parent? How does the compiler do this?

       

      In pure ActionScript the case is clear. Children will get added to the parent by invoking the addElement() method. You could override this method and before the children actually get added to the parent you can do stuff with them.

       

      But when working with MXML they will get added "automatically" and I have learned that the addElement() method will not be invoked for MXML children (at least overriding shows no effect).

       

      The only way I see to grasp those components is via the elementAdd event but my problem is that the components will already have been added when the elementAdd event is dispatched. So I'm stuck!

       

      Why would I want to do this?

       

      I want to create a custom component that already has several layout groups and the children of that custom component defined in MXML will get pushed into different layout groups according to their nature, e.g. a TitleWindow will be pushed to the content layout group and a Menu would be pushed to the sidebar layout group. I want to build a basic GUI framework to simplify my own application development.

       

      Why don't you write your own layout class that does that?

       

      Well I'm trying this right now hoping that it is the way it's meant to work. For any clarifying opinions and comments I would be glad to give the points!

       

      Regards,

      Thilo

        • 1. Re: Catch MXML children before they get added to the parent component
          Flex harUI Adobe Employee

          Seems like you could use states.

          1 person found this helpful
          • 2. Re: Catch MXML children before they get added to the parent component
            ratnawe Level 1

            Thanks for your comment, Flex harUI!

             

            I worked a bit on my layout approach. It seems that it will do what I want. Because I don't see how states could help me here I give you an example:

             

            Let's say the custom component is called MainContainer and the layout for it MainContainerLayout. Then we might have some code like this:

             

            <MainContainer width="100%" height="100%>

             

              <layout>
                 <MainContainerLayout toolbarPosition="top" />
              </layout>

             

              <Toolbar>
                 <s:Button label="Toolbar Button" />
              </Toolbar>

             

              <s:Panel>
                 <s:Label text="Content" />
              </s:Panel>

             

            </MainContainer>

             


            So the layout cares (with some type checking) where to place the children...

             

            Do you think that my approach could work or am I going in a wrong direction?

             

            Regads,
            Thilo

            • 3. Re: Catch MXML children before they get added to the parent component
              ratnawe Level 1

              I now have found the solution that suits best. And here it comes

               

              I've set my own default property in my custom component and I do the type checking within the overridden addElement function. Because the addElement method is not called automatically after the creation of has completed they will be added "manually". My custom component now looks like this.

               

              <s:SkinnableContainer
                  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:comps="some.package.*"
                  width="100%" height="100%"
                  >
                 
                  <fx:Metadata>
                      [DefaultProperty("mxmlChildComponents")]
                  </fx:Metadata>
                 
                  <fx:Script>
                      <![CDATA[
                          import mx.core.IVisualElement;
                          import mx.events.FlexEvent;
                         
                          import spark.components.Button;
                          import spark.components.Panel;
                         
                          [ArrayElementType("IVisualElement")]
                          private var _mxmlChildComponents:Array


                          public function get mxmlChildComponents():Array { return _mxmlChildComponents; }
                          public function set mxmlChildComponents(value:Array):void { _mxmlChildComponents = value; }
                         
                          override public function addElement(element:IVisualElement):IVisualElement {
                              if(element is Button) {
                                  return toolbarGroup.addElement(element);
                              } else if(element is Panel) {
                                  return myContentGroup.addElement(element);
                              } else {
                                  return null;
                              }
                          }

               


                          protected function mainGroup_creationCompleteHandler(event:FlexEvent):void
                          {
                              for(var i:uint = 0; i<mxmlChildComponents.length; i++) {
                                  if(mxmlChildComponents[i] is IVisualElement) {
                                      this.addElement(mxmlChildComponents[i]);
                                  }
                              }
                          }

               

                      ]]>
                  </fx:Script>
                 
                  <s:VGroup id="mainGroup" width="100%" height="100%" creationComplete="mainGroup_creationCompleteHandler(event)">

               

                      <s:HGroup id="toolbarGroup" width="100%" />

               

                      <s:Group id="myContentGroup" width="100%" height="100%"> <!-- cannot be named contentGroup, preserved name -->
                          <s:layout>
                              <comps:SpecialContentLayout />
                          </s:layout>
                      </s:Group>


                  </s:VGroup>
                 
              </s:SkinnableContainer>

               

               

              It can be embedded in an application as follows:

               

              <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:comps="some.package.*"
                  >
                 
                  <s:layout>
                      <s:VerticalLayout/>
                  </s:layout>
                 
                  <comps:MyCustomComp>
                      <s:Button label="Toolbar Button 1" />
                      <s:Panel title="Content Panel 1" />
                      <s:Panel title="Content Panel 2" />
                      <s:Button label="Toolar Button 2" />
                  </comps:MyCustomComp >
              </s:Application>

               

               

              Now buttons will be pushed to the toolbar group and panels will be pushed to the content group. This naturally isn't the purpose but one could easily imagine more complex and useful scenarios...

               

              Regards,

              Thilo

              • 4. Re: Catch MXML children before they get added to the parent component
                pjetr_be

                I needed to override addElement, so that I could add the elements directly to a group in my custom component. This group has some effects, and is masked.

                 

                You should override the function set mxmlContent. This is done before creationComplete is dispatched, so you have to catch this in another way.

                 

                Here is a simplified version on how to do it.

                <?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"

                         >

                    <fx:Script>

                        <![CDATA[

                            private var _creationComplete:Boolean = false;

                           

                            override public function set mxmlContent(value:Array):void{

                                if(_creationComplete){

                                    _content.mxmlContent = value;

                                }else{

                                    _creationComplete = true;

                                    super.mxmlContent = value;

                                }

                            }

                        ]]>

                    </fx:Script>

                    <s:Group id="_content" />

                </s:Group>