8 Replies Latest reply on Apr 30, 2010 10:34 AM by CrazyMerlin

    Datagrid and loose coupling of selectedItem

    ElsaB
      I'm pretty new to Flex, but I know this must be possible, however search as I might I can't find any examples of what I need online, so I'm hoping someone here can help me out, or point me in the right direction.

      I've got two custom components, one with a DataGrid that has an ArrayCollection as it's dataprovider, and the other is a simple panel - just meant for displaying further details of whatever item is selected in the datagrid.

      How can I pass the selectedItem from the DataGrid across to the panel component? At the moment I can't seem to pass it outside of the datagrid component, perhaps because I'm not using the right Event or because I'm not binding it properly.

      Thanks,
      Elsa
        • 1. Re: Datagrid and loose coupling of selectedItem
          peterent Level 2
          Let's assume the DataGrid and the Panel are in the same MXML file, like this:

          <mx:DataGrid id="mygrid" ...>
          ...
          </mx:DataGrid>

          <mx:Panel id="mypanel" ...>
          ...
          <mx:Label id="empName" text="Display data here" />
          ...
          </mx:Panel>

          Let's say you want the employeeName field of the DataGrid's selectedItem to appear in the Label within the Panel:

          <mx:Label id="empName" text="{mygrid.selectedItem.employeeName}" />

          Now the employeeName field of the DataGrid's selectedItem is data-bound to the text field of the Label. This works because both the DataGrid and that Panel.Label is in the same file.

          Let's go further. Suppose the Panel (with that Label) is actually another MXML file (called MyPanel.mxml) so it appears in the file with the DataGrid as:

          <MyPanel id="mypanel" ... />

          to pass in the selectedItem from the DataGrid you need to do 3 things:

          1. Create a public variable within MyPanel in a <mx:Script> block which will be bound to the selectedItem:
          <mx:Script>
          [Bindable] public var employeeData:Object;
          </mx:Script>

          2. Modify the Label in MyPanel and bind its text property to this public variable:
          <mx:Label id="empName" text="{employeeData.employeeName}" />

          3. In the file with the DataGrid and MyPanel tags, bind the selectedIndex of the DataGrid to the public employeeData variable of MyPanel:
          <MyPanel id="mypanel" employeeName="{mygrid.selectedItem}" ... />

          There are other ways to do this, but this is more leeping with the loose coupling method.
          • 2. Re: Datagrid and loose coupling of selectedItem
            ElsaB Level 1
            Hi thanks Peter

            I've read your article on loose coupling for Flex1.5.
            In your example the Panel component is a child of the datagrid component, but in my case they are both sat at the same level in the application, so I need to pass the selectedItem (pressumably bound to an Object variable) up to the parent first.

            I'm trying to use an Event to do it, but I'm having trouble building the function and dispatching the Event.
            I'm well aware this is wrong but this is what I have so far:

            private function selectHandler():void
            {
            var event:Event = new Event("movieSelect");
            event = listItems.selectedItem

            //event.target.selectedItem = listItems.selectedItem;

            dispatchEvent(event);
            }

            Thanks for the help.
            Elsa
            • 3. Re: Datagrid and loose coupling of selectedItem
              peterent Level 2
              Let me see if I understand. You have something like this: a main application (or some MXML file) that has 2 children. One contains a DataGrid and the other contains a Panel. You want to get the selection from the DataGrid to appear in the Panel.

              Let's call this: MyGrid.mxml (say it extends HBox and that HBox has a DataGrid in it) and MyPanel (say it extends Panel and has a Label in it).

              In MyGrid.mxml:

              1. Define an event: <mx:Metadata>[Event(" gridSelect")]</mx:Metadata>
              2. Define a public var to access the selection: [Bindable] public var selectedItem:Object;
              3. Make the change event on the DataGrid set the value of selectedItem and dispatch the event:

              <mx:DataGrid id="mygrid" change="handleChange()" ... >

              private function handleChange() : void {
              selectedItem = mygrid.selectedItem;
              dispatchEvent( new Event(" gridSelect") );
              }

              In MyPanel.mxml:

              1. Define a public variable to accept the data: [Bindable] public var gridItem:Object;
              2. Bind to this item in the controls: <mx:Label text="{ gridItem.employeeName}" />

              In the main (or whatever) component that has MyPanel and MyGrid has children:

              <MyPanel id="mypanel" ... />
              <MyGrid id="mygrid" gridSelect="mypanel. gridItem = event.target. selectedItem" ... />

              Notes:

              I tried to use boldface, underline and italics to show where the items are releated.
              There are several other ways of doing this, but I think this is the most straightforward and easiest to understand. You have MyGrid dispatching an event whenever its DataGrid is selected and it provides a public variable which contains that selection. The MyPanel has a public var to which various controls are data-bound. When the gridSelect event is triggered, the MyPanel public variable is set from the selectedItem and this will trigger the data binding to update the controls in MyPanel.
              • 4. Re: Datagrid and loose coupling of selectedItem
                ElsaB Level 1
                Thank you so much Peter thats brilliant!
                • 5. Re: Datagrid and loose coupling of selectedItem
                  FranceC
                  Thanks for the post peterent. I'd like to expand the question to cover messaging when the components are not direct children of a common parent.

                  In particular, I have a grandchild that needs to communicate with an uncle. Here is the file structure:

                  Application.mxml
                  |__ navigation.mxml [child of application,mxml]: acts as a controller
                  ____|__ leftNavigation.mxml [child of navigation.mxml]: contains the event that needs to send a message to its uncle
                  |__ mainBody.mxml: listening for message from leftNavigation.mxml

                  How does the mainBody.mxml receive the message(event) that the leftNavigation.mxml fires?

                  Thanks in advance for your help,
                  Francine
                  • 6. Re: Datagrid and loose coupling of selectedItem
                    peterent Level 2
                    This is an excellent question. I see 3 possible answers (and there are probably more):

                    All in One

                    If your layout is contained all in one file, where each component has an id, like this:

                    Application.mxml
                    |__ navigation.mxml id="nav"
                    ____|__ leftNavigation.mxml id="leftNav"
                    |__ mainBody.mxml: id="mainBody"

                    So these are tags in the Application.mxml file, then you can simply do:

                    ____|__ leftNavigation.mxml id="leftNav" myEvent="mainBody.someFunction(event)"

                    Where you add an event handler for the event right on the leftNavigation tag and explicity reference the mainBody tag via its id, and call a public function or set a public property.

                    Many Files - Bubble Up

                    If on the other hand you have an MXML files like this:

                    Application.mxml
                    ______| navigation.mxml
                    ______| mainBody.mxml

                    navigation.mxml
                    ______| leftNavigation.mxml

                    then it becomes a little more complex. The first thing you should decide is what type of event should leftNavigation dispatch. If it can dispatch a known event to navigation.mxml, such as "click", then you use event bubbling described in this thread:

                    Application.mxml
                    ______| navigation.mxml click="mainBody.someFunction(event)"
                    ______| mainBody.mxml id="mainBody"

                    So leftNavigation has to dispatch a click (flash.events.MouseEvent) event.

                    Custom Event

                    If you require a custom event, even if there is no special Event class but an event name that is not already known, then you have an extra couple of steps. Let's say you want to have a "navigate' event and the leftNavigation has a public property which will hold that value so you do not need to create a custom Event. Just having the event.target will allow the public property to be accessed.

                    Now you have to do the following:

                    In leftNavigation.mxml add metadata for the event so the compiler knows about it:
                    <mx:Metadata>[Event("navigate")]</mx:Metadata>

                    and have leftNavigation dispatch that event, and make sure the bubbles=true is set.

                    In navigation.mxml also define the same meta data.

                    In the Application.mxml you can now do:

                    Application.mxml
                    ______| navigation.mxml navigate="mainBody.someFunction(event)"
                    ______| mainBody.mxml id="mainBody"

                    In mainBody's someFunction, event.target can be used to get the public property containing the information as event.target will be leftNavigation.

                    • 7. Re: Datagrid and loose coupling of selectedItem
                      DEEPJYOTSENA
                      That was a very nicely explained.But I have a question.Actually I have many as i am new to Flex and action script.

                      let me explain myself.....i have a mxml component in which there is a datagrid with id="grid" and there are three columns.the data provider is an arraycollection.

                      again i created another mxml component where there are three text fields.i want to display the values in the grid in the text fields when the user selects the datagrid rows.

                      the parent of this two component is an mxml file.but this two components are to be seen in the base state but in another state.(in my case in loggedin state).how can i do this...and the parent file is in not the same level as the two components.

                      is it possible to call the grid component in the text component and directly pass the values?????

                      I Hope i am making some sense.........


                      • 8. Re: Datagrid and loose coupling of selectedItem
                        CrazyMerlin Level 1

                        It sounds like you need some global property holder, so that you can reference data across different states. This can be done with a local shared object, which is the Flash equivalent of a cookie.

                        Simply create a class that manages all the interaction with the LSO and you can just request data, or set data via it.

                         

                        You can create an LSO like so:

                         

                        var myLSO:SharedObject = SharedObject.getLocal('myLSO');
                        

                         

                        The LSO doesn't exist at that point so it will be created and assign to the myLSO variable.

                         

                        To write to an LSO you simply create variables on its data property:

                         

                        myLSO.data.username = txtUsername.text;
                        myLSO.data.password = MD5(txtPassword.text);
                        

                         

                        You can then ensure the data is written to the local computer with:

                         

                        myLSO.flush();
                        

                         

                        Just be sure to catch the result as a failure to write will throw an exception.

                        If you create a static class to wrap the LSO you can simply do something like:

                         

                        LSOManager.write({username: txtUsername.text});
                        

                         

                        Hope that helps.