15 Replies Latest reply on Mar 17, 2009 6:03 PM by fuyuko1979

    trigger an event from one component to another component

    fuyuko1979
      Hi there, I have a flex app with a datagrid component that I would like to click on it which sends an id number and an event to the tab navigator component which will trigger a state change in there.
      Is there a way for the two components to talk to each other without going through the main application?

      thank you
        • 1. Re: trigger an event from one component to another component
          Level 7

          "fuyuko1979" <webforumsuser@macromedia.com> wrote in message
          news:gp3uiu$kru$1@forums.macromedia.com...
          > Hi there, I have a flex app with a datagrid component that I would like to
          > click on it which sends an id number and an event to the tab navigator
          > component which will trigger a state change in there.
          > Is there a way for the two components to talk to each other without going
          > through the main application?

          Give each of them an instance of the same object to listen to.


          • 2. Re: trigger an event from one component to another component
            Level 7

            "fuyuko1979" <webforumsuser@macromedia.com> wrote in message
            news:gp3uiu$kru$1@forums.macromedia.com...
            > Hi there, I have a flex app with a datagrid component that I would like to
            > click on it which sends an id number and an event to the tab navigator
            > component which will trigger a state change in there.
            > Is there a way for the two components to talk to each other without going
            > through the main application?

            Sorry, that should be give each of them the same object to listen to.


            • 3. Re: trigger an event from one component to another component
              cluebcke
              And now you know why there are Flex MVC frameworks :) If the TabNavigator contains the DataGrid, then you can just make the event bubble and listen for it in the TabNavigator. If not, to rephrase what Amy said a little, both components need to have a reference to the same EventDispatcher (or subclass thereof), so that the TabNavigator can call addEventListener on it, and the DataGrid can call dispatchEvent on it (or one of its children, so long as the event bubbles).

              This is one of the problems that Flex frameworks solve in various ways. Cairngorm uses an application wide Controller that acts as a publish/subscribe board for CairngormEvents. PureMVC adopts the Observer/Notify pattern along with proxies for gaining access to objects around the system.

              You can certainly start with Application.application.addEventListener and Application.application.dispatchEvent (you can avoid the latter by making your events all bubble, but that will scale very poorly, performance-wise, as your application grows in structure and number of events). If you haven't already investigated some of the frameworks, it may not be a bad idea to start there; it's not a good approach, but it'll work in the short-term, and discovering some of the shortcomings yourself (e.g. you'll never be able to know what handlers are listening for what events without scanning your whole codebase or tracing all your events). Doing so will give you a better perspective when you decide to up your game and adopt a more scaleable approach, whether you pick a framework off the shelf or decide to roll your own solution
              • 4. Re: trigger an event from one component to another component
                fuyuko1979 Level 1
                wow thanks so much for this!
                As you can see I am a total newb...
                The thing is, to actually expand on my initial question, I want to display the information from the datagrid row in to the tab navigator area when a user clicks on a datagrid row.
                Both the tabnavigator and the datagrid are totally separate mxml components.
                Would you recommend creating a custom event here which will send the xml object (which contains all the information) to the tab navigator?
                And also how do I exactly make both of my componentnets to reference the same event dispatcher?

                sorry for my total ignorance!!
                • 5. Re: trigger an event from one component to another component
                  fuyuko1979 Level 1
                  wow thanks so much for this!
                  As you can see I am a total newb...
                  The thing is, to actually expand on my initial question, I want to display the information from the datagrid row in to the tab navigator area when a user clicks on a datagrid row.
                  Both the tabnavigator and the datagrid are totally separate mxml components.
                  Would you recommend creating a custom event here which will send the xml object (which contains all the information) to the tab navigator?
                  And also how do I exactly make both of my componentnets to reference the same event dispatcher?

                  sorry for my total ignorance!!
                  • 6. Re: trigger an event from one component to another component
                    cluebcke Level 1
                    n00bs rule, no worries.

                    Here's how I would approach it, bare-bones style, with plenty of room for exploration and improvement later on.

                    1. Yeah, create a custom event. It'll be a subclass of Event. The nice thing you can do here as add a property to it, and even force yourself to provide the property in the constructor (so long as it shouldn't ever be blank). Here's an example of how I usually do these, though there are several acceptable varations:

                    package com.foo.event
                    {
                    import flash.events.Event;

                    public class FooItemSelectedEvent extends Event
                    {
                    public static const EVENT_TYPE : String = "FooItemSelected";

                    public var selectedItem : Object; // could be any name or type you want, including multiple properties for complex messages

                    public function FooItemSelectedEvent(selectedItem : Object)
                    {
                    super(EVENT_TYPE, true, false);
                    this.selectedItem = selectedItem
                    }
                    }
                    }

                    You can then dispatch and catch this event, and be assured you're dealing with the right event, and that it'll have the data you need.

                    2. As to where to dispatch and listen, that's what I was getting at with the frameworks--there are different approaches; while PureMVC's observer/notify pattern (you can Google that to your hearts content) seems the most natural and generally OO to me, it's also the biggest one to adapt. Way too much if you're just getting started with Flex/AS3 and you have a new app.

                    So the quickest, dirtiest route is this:

                    In the container where you want to use the selected data, somewhere (a creationComplete or initialize handler, or the constructor if you're using code-behind):

                    Application.application.addEventListener(FooItemSelectedEvent.EVENT_TYPE, myEventListener)

                    and

                    function myEventListener(event:FooItemSelectedEvent) : void {
                    var foo : Object = event.selectedItem;
                    //... whatever else you want to do
                    }

                    Then in the change handler for the datagrid, you have

                    Application.application.dispatchEvent(new FooItemSelectedEvent(myData));

                    And there you go. Now you're using the top-level application as a publish/subscribe board for messages--which it already was anyway.

                    I mentioned one drawback in my previous post, which was that there isn't a good way to know who's issue what events and who's listening for them--that may or may not be a problem, depending on your point of view.

                    Probably the larger drawback, which is why I would recommend this is a great temporary solution while you learn, is that Application is already a great big event listener, but it's intended to listen for events relating to the user interface. When we start intermingling our business logic with that, we're not doing a very good job of keeping code that serves different purposes separated, which is a good practice. Some frameworks, like PureMVC, don't use Flex (or Flash) events at all, partly in order to draw a strong line between implementing business logic and UI behavior.

                    Anyway, hope that helps. Sorry for the dissertation, need to get back to my day job now :) But please follow up with any more questions and I'll assist as best I can.

                    - Chris
                    • 7. Re: trigger an event from one component to another component
                      Level 7

                      "fuyuko1979" <webforumsuser@macromedia.com> wrote in message
                      news:gp4chf$7kb$1@forums.macromedia.com...
                      > wow thanks so much for this!
                      > As you can see I am a total newb...
                      > The thing is, to actually expand on my initial question, I want to display
                      > the
                      > information from the datagrid row in to the tab navigator area when a user
                      > clicks on a datagrid row.
                      > Both the tabnavigator and the datagrid are totally separate mxml
                      > components.
                      > Would you recommend creating a custom event here which will send the xml
                      > object (which contains all the information) to the tab navigator?
                      > And also how do I exactly make both of my componentnets to reference the
                      > same
                      > event dispatcher?

                      Why are you wanting to do this without going through the Application?
                      Usually, if you don't have a need for a heavy MVC framework, the most common
                      approach is to use the Application as a controller.


                      • 8. Re: trigger an event from one component to another component
                        fuyuko1979 Level 1
                        Thank you so much!!!
                        You are the best!
                        Everything makes sense and once I get the time I will implement your code in to mine.
                        Once I finish this project I will look in to flex frameworks... so much to learn... *sigh*

                        Thanks again!

                        (I too must get back to my day job...)
                        • 9. Re: trigger an event from one component to another component
                          fuyuko1979 Level 1
                          hi Amy,

                          well, when I click on the row in the datagrid I want a state change to occurr in the tabnavigator.
                          Unless there is a way to change the state of the tabnavigator from the main application, I thought it would be straight forward to fire the event straight to the tabnavigator.
                          • 10. Re: trigger an event from one component to another component
                            Level 7

                            "fuyuko1979" <webforumsuser@macromedia.com> wrote in message
                            news:gp4hsf$dja$1@forums.macromedia.com...
                            > hi Amy,
                            >
                            > well, when I click on the row in the datagrid I want a state change to
                            > occurr
                            > in the tabnavigator.
                            > Unless there is a way to change the state of the tabnavigator from the
                            > main
                            > application, I thought it would be straight forward to fire the event
                            > straight
                            > to the tabnavigator.

                            tabnavigatorID.selectedIndex=someIntVariable;

                            HTH;

                            Amy


                            • 11. Re: trigger an event from one component to another component
                              fuyuko1979 Level 1
                              hi cluebcke,

                              I followed your instructions and everything is working wonderfully!
                              but now I have another question!
                              I have a tab navigator with tab A and tab B - each tab is a separate component.
                              I want to dispatch an event from tab A and when tab B hears it, change the tab to display tab B and then catch the event and display the XML object in the required fields.
                              So naturally in the mxml file of tab B I add an eventListener in my init function which is triggered on creationComplete. But Alas! creationComplete never happens for tab B unless I explicitly click on the tab itself!
                              How can i make it so that tab B is always listening when the application first initialises and how can I flip the tab to display tab B once tab B hears the event?..... woudl this be a case of going through the main application?

                              thanks for any help!!!!
                              • 12. Re: trigger an event from one component to another component
                                cluebcke Level 1
                                Another learning opportunity! This is a perfect moment for you to learn all about "creation policy", which, in a nutshell, describes the circumstances under which components create their children. With ViewStack-style containers, of which TabNavigator is a member, they tend to not create all their children right away. Doing this allows the application to become fully initialized and available much more quickly than if every component was created and added to the stage/display list. In your case, TabNavigator is doing something that's usually smart, but might not be best for what you need.

                                I strongly encourage you to read up on creation policy in the developer's guide and API docs, but here are a couple of options:

                                1. Set the "creationPolicy" property on your TabNavigator to "all". This will cause it to create all its children (ending in creationComplete being dispatched from each). There's an up-front performance hit for doing this, but if you're not doing a whole lot of it, it's negligible.

                                2. Have the TabNavigator itself attach the event listener. When the event is caught, then it can set its selectedIndex (or selectedItem) property, and can then either invoke methods on the second tab directly.

                                There are variations but I think your solution will look like one of these two approaches. If performance isn't really affected, I'd go with #1, because then you're still keeping your logic with the code that requires it. At some point later on in your development experience, you may want to adopt some kind if "controller pattern" that'll let you remove this logic from visual components and abstract it into more of a business or view logic layer, but I wouldn't worry about that for now.

                                HTH again,
                                Chris
                                • 13. Re: trigger an event from one component to another component
                                  fuyuko1979 Level 1
                                  hi clubcke, thank you so much for all your generous help, I'm almost finished with my application and everything is working wonderfully thanks to you!
                                  I realise I have so much more to learn though, once i finish this I will look in to amfphp and working with frameworks... so much to learn *sigh* but you've been an amazing help so thank you!
                                  I do have one question however and I hope I can ask you.
                                  My application is a multi user application in that the accessibility of the information is dependent on the permission of the user.
                                  I have made my app so far with the admin user in mind so everything works with all the admin functionality, but now when it comes to limiting some of these functionalities for the guest user, what is the best way to do this?
                                  shall i make a global variable called permissions and depending on that permission do I hide or show certain controls in each of my component? would this be the right approach?

                                  thanks again for all your help,

                                  best,
                                  Fuyuko
                                  • 14. Re: trigger an event from one component to another component
                                    cluebcke Level 1
                                    More than happy to help, Fuyuko. By the way, my name is Chris Luebcke; I just now realized that my full name doesn't show up in my posts, though I've set my forum configuration to do so.

                                    Anyway, you're on the right path. An application that requires authentication will typically have a User object that is globally accessible; you can start by adding an ActionScript property to your top-level application:

                                    public var user : User;

                                    Then setting and accessing it by referencing the Application.application static property

                                    var user : User = Application.application.user

                                    A more mature application will usually follow a framework or pattern for making data accessible from anywhere that doesn't rely on adding properties to your application MXML file, but this will get you off the ground.

                                    I was going to say something else about designing how you structure and access permissions, but there's no simple answer to that; it depends on whether you have s simple or complex permissions matrix, how much it's likely to change over time, where the permissions are stored, whether your server solution provides code generation, etc.

                                    Regards,
                                    Chris
                                    • 15. Re: trigger an event from one component to another component
                                      fuyuko1979 Level 1
                                      Hi Chris, thank you again for putting me in the right direction and sorry for using your username, i thought it was one of those words that take out vowels in parts for effect!

                                      I have one question regarding your last post: I'm not sure what Application.application.user is referring to.
                                      I have a login component in which I have set up a public var user:User.
                                      User is a class i made.
                                      So when the user loggs in successfully, I set the permission status to user.permission.
                                      This is all working fine but i now have to somehow instantiate this or call this in my main application file, is this when i should be using Application.application.user?
                                      in the main app file, I can alert login.user.permission and that works but it does not work if I alrert Application.application.user.....
                                      sorry for my ignorance...

                                      You have been great at highlighting the different ways that one can approach making applications in flex, one being the noob way which as you rightly point out can be quite short sighted for a more larger application.
                                      So my question is, now that I have a basic - very basic - knowledge in flex, how can I extend my knowledge further?
                                      Shall I start using frameworks after this? would this help me in becoming more proficient in the way I create applications and become knowledgeable on such things as "controller pattern" that will allow me to have a clear separation between business logic and visual components?
                                      Hmm...maybe what I am trying to ask is, what is the next step to becoming more proficient in Flex and RIA development?

                                      thanks again for your help,

                                      kind regards,
                                      Fuyuko