13 Replies Latest reply on Mar 19, 2010 5:51 AM by drrevis

    Dispatch event to child of NavigatorContent

    drrevis

      Hi,

       

      I'm working on moving a project over to Flex 4 and so far I really like it, but I'm stuck on a particular issue.

       

      Previously I had a ViewStack where each child was a custom component.  For Flex 4, I've changed it so that each child is a NavigatorContent component that includes the custom component as in:

       

              <mx:ViewStack id="elementsViewStack" width="100%" height="100%" >
                  <s:NavigatorContent id="retrieveDataView"><system:RetrieveDataView/></s:NavigatorContent>
                  <s:NavigatorContent id="backupDataView"><system:BackupView/></s:NavigatorContent>

      ......

              </mx:ViewStack>

       

      Whenever I change the view, I need to update the data that is being displayed and so I would key that off of a show event.  In some cases, I had to specifically send a show event because the view would stay the same, but I needed to update the data anyway, so I would just dispatch the event to the selected child of the view stack.

       

      Since I now have to wrap the custom component in a navigator content component, this strategy no longer works because the show event goes to the navigator content component rather than my custom component (or at least, that's what I'm assuming is happening).  I tried to access the custom component as a child of the navigator content component, but it tells me there are zero elements, so I don't know how to dispatch the event to my custom component given this situation.

       

      The other approach I tried was to make my custom component a navigator content component instead of an s:group component, but for some reason that makes the states in my custom component not work correctly.  I know the state is being set correctly as a trace in actionscript shows, but the elements aren't included correctly based on the current state.

       

      Can someone help me figure out a way to make this work?

       

      Thanks for any help!

      Renee

        • 1. Re: Dispatch event to child of NavigatorContent
          Flex harUI Adobe Employee

          IMHO, I think the views should pull data from a data model, then you

          wouldn't need any event to push an updated.

           

          But if you want to push, I would try to base your views on NavigatorContent

          and figure out why the states weren't doing the right thing.

          • 2. Re: Dispatch event to child of NavigatorContent
            drrevis Level 1

            I'm basically using a data pull, but with a lazy fetch idea, only updating the data if/when needed.  I need to know when the view is redisplayed so I can update the data if necessary.  In one case in particular, I use the same view but with different data depending on how I navigated to that view and that's why I'm forcing the show event.  I could try to rethink this approach and might do that, but for now the other approach would definitely be easier.

             

            As for the states issue with the NavigatorContent component, I'm not sure the problem is on my end.  To verify it, I simplified the view to only have one state and see the trace indicate that the state is set as expected.  I have a VGroup component that displays correctly if I don't have the includeIn parameter, but it doesn't display if I do.  Not sure what I could be doing wrong there.  Any suggestions or does this sound like a system issue?

             

            Thanks for your help!

             

            Renee

            • 3. Re: Dispatch event to child of NavigatorContent
              Flex harUI Adobe Employee

              We would need to see a simple test case of the states issue.

              • 4. Re: Dispatch event to child of NavigatorContent
                drrevis Level 1

                Ok, I stripped it down to the basics.  When I run this, Test Label 1 displays, but Test Label 2 does not.  I originally created the component based on a VGroup component and it worked fine, but it stopped working when I changed it to NavigatorContent.  If I remove the includeIn property, Test Label 2 will display.

                 

                 

                <?xml version="1.0" encoding="utf-8"?>
                <s:NavigatorContent xmlns:fx="http://ns.adobe.com/mxml/2009"
                         xmlns:s="library://ns.adobe.com/flex/spark"
                         xmlns:mx="library://ns.adobe.com/flex/halo"
                         width="100%" height="100%" creationComplete="initView()" >
                   
                    <fx:Declarations>
                        <!-- Place non-visual elements (e.g., services, value objects) here -->
                       
                    </fx:Declarations>

                 

                    <fx:Script>
                        <![CDATA[
                           
                            public function initView():void {
                                this.currentState = "list";
                                trace("current state init is: " + this.currentState);
                            }
                           
                        ]]>
                    </fx:Script>
                   
                    <s:states>
                        <s:State name="list"/>
                        <!--<s:State name="uses"/>-->
                    </s:states>
                   
                    <s:layout><s:VerticalLayout/></s:layout>
                    <s:Label text="Test Label 1" styleName="headerLabel" />
                    <s:VGroup includeIn="list" width="100%" height="85%">
                        <s:Label text="Test Label 2" styleName="headerLabel" />
                    </s:VGroup>
                   
                </s:NavigatorContent>

                • 5. Re: Dispatch event to child of NavigatorContent
                  Flex harUI Adobe Employee

                  Works for me.  Are you on latest builds?

                  • 6. Re: Dispatch event to child of NavigatorContent
                    drrevis Level 1

                    I'm using the GlassFish Tools Bundle for Eclipse with the Flash Builder 4.0.0.253292 plugin.

                     

                    I thought it was the latest.  Only installed it about a month ago.

                    • 7. Re: Dispatch event to child of NavigatorContent
                      Flex harUI Adobe Employee

                      Try a new project and see if you have the same problem.

                      • 8. Re: Dispatch event to child of NavigatorContent
                        drrevis Level 1

                        Haven't tried a new project yet, but I did find something interesting.  As I had mentioned previously, I am coming into this view/custom component via a ViewStack that is associated with an Accordian.  In the ViewStack, I had been specifying it as:

                         

                                <mx:ViewStack id="grammarElementsViewStack" width="100%" height="100%">

                                    <s:NavigatorContent id="verbView"><verbs:VerbalView/></s:NavigatorContent>
                        ...

                                </mx:ViewStack>

                         

                        In this case, the states work as expected and things display properly, but if I change it to:

                         

                                <mx:ViewStack id="grammarElementsViewStack" width="100%" height="100%">

                                    <verbs:VerbalView id="verbalView"/>
                        ...

                                </mx:ViewStack>

                         

                        the states don't work and I see the problem that I've described.  However, using the previous method, I don't know how to dispatch the show event to the VerbalView component.

                         

                        If this really is a problem, maybe I'll have to define multiple children in the ViewStack that use the same custom component with different ids.  That might do the trick.  It would still be interesting to know, though, if you can confirm this problem.

                        • 9. Re: Dispatch event to child of NavigatorContent
                          Flex harUI Adobe Employee

                          In my test I put your code in an MXML component and put that in the

                          viewstack and it worked, so it was more like your case #2.

                           

                          I'm not sure what you mean by associated with Accordion.  That's why you

                          should try a simple test case, just a ViewStack with one or two views based

                          on NavigatorContent that have states in them.

                          • 10. Re: Dispatch event to child of NavigatorContent
                            drrevis Level 1

                            Ok. I tried commenting out the Accordian and current viewstack I have and replaced them w/just two simple buttons to move through a viewstack with only four views which specify the views in these various ways.  I'm still seeing the problem.

                             

                            Since I'm using Flex with BlazeDS and Java EE in the backend, I'll have to work on setting up a new project with the right structure to test this out with a simpler environment.  I'll try to do that tomorrow to see if I can get it working.  Thanks.

                            • 11. Re: Dispatch event to child of NavigatorContent
                              drrevis Level 1

                              So I've been trying to narrow this down and this is what I've come up with.

                               

                              I have a new project with the following application:

                               

                              <?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/halo"
                                             xmlns:test="com.test.*">
                                  <fx:Declarations>
                                      <!-- Place non-visual elements (e.g., services, value objects) here -->
                                  </fx:Declarations>
                                 
                                  <s:Group width="100%" height="100%">
                                      <s:layout><s:HorizontalLayout gap="0" /></s:layout>
                                     
                                      <s:VGroup width="200" height="100%">
                                          <s:Button label="Previous" click="viewStack1.selectedIndex--" enabled="{viewStack1.selectedIndex != 0}"/>
                                          <s:Button label="Next" click="viewStack1.selectedIndex++" enabled="{viewStack1.selectedIndex != viewStack1.numChildren-1}"/>
                                      </s:VGroup>

                               

                                      <mx:ViewStack id="viewStack1" width="100%" height="100%"
                                                    borderStyle="outset" borderColor="0x228ea5" borderThickness="5"
                                                    paddingTop="10" paddingBottom="5" paddingLeft="7" paddingRight="7">
                                          <test:TestNavigatorComponent id="test1"/>
                                          <test:TestNavigatorComponent id="test2"/>
                                          <test:TestNavigatorComponent2 id="test3"/>
                                          <test:TestNavigatorComponent2 id="test4"/>
                                      </mx:ViewStack>

                               

                                  </s:Group>
                                 
                              </s:Application>

                               

                               

                              Then I have two different custom components that use the exact same code:

                               

                              <?xml version="1.0" encoding="utf-8"?>
                              <s:NavigatorContent xmlns:fx="http://ns.adobe.com/mxml/2009"
                                                  xmlns:s="library://ns.adobe.com/flex/spark"
                                                  xmlns:mx="library://ns.adobe.com/flex/halo"
                                                  width="100%" height="100%" creationComplete="initView()">
                                  <fx:Declarations>
                                      <!-- Place non-visual elements (e.g., services, value objects) here -->
                                  </fx:Declarations>

                               

                                  <fx:Script>
                                      <![CDATA[
                                         
                                          public function initView():void {
                                              this.currentState = "list";
                                              trace("current state init is: " + this.currentState);
                                          }
                                         
                                      ]]>
                                  </fx:Script>
                                 
                                  <s:states>
                                      <s:State name="list"/>
                                      <!--<s:State name="uses"/>-->
                                  </s:states>
                                 
                                  <s:layout><s:VerticalLayout/></s:layout>
                                  <s:Label text="NavComponent Test Label 1" styleName="headerLabel" />
                                  <s:VGroup includeIn="list" width="100%" height="85%">
                                      <s:Label text="NavComponent Test Label 2" styleName="headerLabel" />
                                  </s:VGroup>

                               

                              </s:NavigatorContent>

                               

                               

                              The initial view displays correctly, but every other view using TestNavigatorComponent or TestNavigatorComponent2 does not show the second label.  I've tried many variations of this.  If I use another component based on VGroup that is wrapped in a NavigatorContent, it displays correctly.  But if I put that in the first position of the viewstack, then the first view using TestNavigatorComponent does not display correctly - i..e,:

                               

                                          <s:NavigatorContent>
                                              <test:TestVGroupComponent/>
                                          </s:NavigatorContent>
                                          <test:TestNavigatorComponent id="test1"/>
                                          <test:TestNavigatorComponent id="test2"/>
                                          <test:TestNavigatorComponent2 id="test3"/>
                                          <test:TestNavigatorComponent2 id="test4"/>
                                          <s:NavigatorContent>
                                              <test:TestVGroupComponent/>
                                          </s:NavigatorContent>

                               

                              I'm not sure what in my environment could cause this to happen.  Can you see if you can confirm this on your end?

                               

                              Thanks,

                              Renee

                              • 12. Re: Dispatch event to child of NavigatorContent
                                smon_ed

                                In response to what you say here: " I tried to access the custom component as a child of the navigator content component, but it tells me there are zero elements, so I don't know how to dispatch the event to my custom component given this situation."

                                 

                                I've just come across something like this - when I try to populate my NavigatorContent, the children do not display and I had trouble accessing existing children.

                                 

                                http://opensource.adobe.com/wiki/display/flexsdk/Gumbo+DOM+Tree+API

                                 

                                Specifically, I think this is the most relevant passage:

                                 

                                 

                                function(){return A.apply(null,[this].concat($A(arguments)))}

                                What this means is that even though it looks like Panel's children should be a button, a label, and a checkbox; it's only real child is a panel skin instance. And the button, label, and checkbox get pushed down to become children of the contentGroup in the skin file. There are a few ways to access the Button in the panel: myPanel.getElementAt(0) or myPanel.contentGroup.getElementAt(0) or myPanel.skin.contentGroup.getElementAt(0).

                                All SkinnableComponent's have a skin property. In an SkinnableContainer, the children of the components are actually pushed down to the skin's contentGroup. The component tree refers to the semantic tree translated from MXML. In the Panel example, this would just include, the Panel and its children: a button, a label, and a checkbox. The layout tree refers to the actual tree seen by the layout system, the layout tree due to skinning. In the Panel example, this would include the panel, the panel skin, all the panel skin's children, and all the panel's children that are actually pushed down into the contentGroup of the panel skin.

                                The layout tree doesn't necessarily correlate to the display list tree that Flash sees. This is because GraphicElements are not innately display objects. Because of performance reasons, they implement display object sharing to minimize the number of display objects.

                                IVisualElementContainer is the interface that defines the content APIs. In Spark, Skin, Group, and SkinnableContainer are the components for holding visual elements and implement this interface. To provide consistency, MX's Container will also implement this interface and just be a facade for addChild(), numChildren, etc....

                                 

                                So, for example, you might want to try and access your custom component like this:

                                 

                                MyNavContentContainer.skin.contentGroup.getChildByName("myComponent")

                                 

                                Also, in order to get my new child components to display, I have set the creationPolicy of my ViewStack to:

                                creationPolicy="all"

                                 

                                This means that the NavigationContent containers are drawn at startup and not only when required.

                                 

                                I'm not sure how relevant this is for you but it's info nevertheless - maybe it'll help.

                                 

                                • 13. Re: Dispatch event to child of NavigatorContent
                                  drrevis Level 1

                                  This is great information and definitely makes sense.  I think it would still be cleaner to make the custom components be based off of the NavigatorContent components so I can use them directly in the viewstack, but if I can't get that to work with the state issue, this will definitely be a backup plan.  Thanks so much for passing it on!

                                   

                                  Renee