views:

5043

answers:

3

I have a List with a custom ItemRenderer. The ItemRenderer contains a Checkbox and a Label. The component with the List has a 'select all' checkbox. When the 'select all' checkbox is checked, it dispatches an event that each item should listen to in order to select its own checkbox. The eventlistener is added on creationComplete of each item, and the event is dispatched correctly when the 'select all' checkbox is selected, but the listener in the custom ItemRenderer does not listen.

How do I make the ItemRenderer listen to an event that is dispatched in its parent??

I'll add some code examples to clarify:

------- container ----------
<mx:VBox>
   <mx:Script>
      <![CDATA[
         public var user1 = new User(1, "Jack");
         public var user2 = new User(2, "John");
         public var user3 = new User(3, "Mary");

         [Bindable]
         public var users:ArrayCollection = new ArrayCollection([user1], [user2], [user3]);

         public static const SELECT_ALL_USERS:String = "selectAllUsers";

         private function selectAllChangeHandler():void
         {
            if (selectAll.selected)
               dispatchEvent(new Event(SELECT_ALL_USERS,true));
         }
      ]]>
   </mx:Script>
   <mx:CheckBox id="selectAll" change="{selectAllChangeHandler()}" />
   <mx:List dataProvider="{users}" itemRenderer="myRenderer" />
</mx:VBox>


------- renderer ----------
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox creationComplete="{init()}">
   <mx:Script>
      <![CDATA[
         private function init():void
         {
            addEventListener (Container.SELECT_ALL, selectAllHandler, false, 0, true);
         }

         private function selectAllHandler():void
         {
            checkbox.selected=true;
         }

         private function selected(id:int):Boolean
         {
             return id==1 || id==3;
         }
      ]]>
   </mx:Script>

   <mx:CheckBox id="checkbox" selected="{selected(data.id)}" />
   <mx:Label text="{data.name}" />
</mx:HBox>

Please note that the users ArrayCollection or its containing user objects cannot be changed because I need the values later on. So when 'selectAll' is clicked, each checkbox in the list should also be checked.

+1  A: 

Your custom ItemRenderers should not register an event listener with their parent, but with your "select all" checkbox, i.e.

theCheckbox.addEventListener(YourEvent.YOUR_EVENT, itemRendererSelectAllHandler);

Failing that, can you post your code which adds the event listener and which dispatches the event form the checkbox?

edit:

Here's your bug: In renderer's init(), you need to add an event listener not to the renderer, but to the container which dispatches the event. So make that a

container.addEventListener(Container.SELECT_ALL_USERS, selectAllHandler, false, 0, true);
Simon
+1  A: 

Doing select all in flex is little complex but I will tell you the way we did it and it works great.

We created a List derived control called "ExList" which has a property "selectAllCB" which we bind it to existing check box which will work for select all logic. Please note, when we set selectAllCB property, we make ExList to listen to checkbox's events.

When checkbox is checked, we manually set selectedItems array to array of dataProvider and all items are selected.

Playing with itemRenderer doesnt work correctly because when you program your list again and again everytime you have to write so much of code.

I am attaching some sample code here below..

    public class ExList extends List 
    {
     public function ExTileList()
     {
      super();
      this.allowMultipleSelection = true;
     }

     private var _selectAllCB:CheckBox = null;
     [Bindable]
     public function get selectAllCB():CheckBox
     {
      return _selectAllCB;
     }
     public function set selectAllCB(v:CheckBox):void
     {
      if(v==null)
       return;
      _selectAllCB = v;
      v.addEventListener(ListEvent.ITEM_CLICK, handleAllChange,false, 0 , true);
      v.addEventListener("change", handleAllChange,false, 0 , true);
     }

     private function handleAllChange(e:Event):void
     {
      if(_selectAllCB.selected)
      {
       this.selectedItems = this.dataProvider.toArray();
      }
      else
      {
       this.selectedItems = new Array();
      }
     }
}

And you can use it as...

<CheckBox id="sAll"/>
<ExList selectAllCB="{sAll}"/>

// Please note its in curly braces
Akash Kava
A: 

This is how I achieved the solution:

    <?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" height="150" verticalGap="0">
    <mx:Script>
 <![CDATA[
         import mx.events.ListEvent;
  import mx.controls.CheckBox;
  import mx.collections.ArrayCollection;

  public var listData:ArrayCollection;

  private function selectAll():void
  {
   listChkBox.selectedItems = listData.toArray();
   for each (var item:Object in listChkBox.selectedItems)
   {
    CheckBox(listChkBox.itemToItemRenderer(item)).selected = true;
          }   
  }

  private function resetAll():void
  {
   listChkBox.selectedItems = listData.toArray();
   for each (var item:Object in listChkBox.selectedItems)
   { 
                         CheckBox(listChkBox.itemToItemRenderer(item)).selected = false;
   } 
  }


  ]]>
 </mx:Script>
 <mx:List width="100%" height="100%" id="listChkBox" labelField="name" allowMultipleSelection="true"
   dataProvider="{listData}"  selectionColor="#FFFFFF" >
  <mx:itemRenderer>
   <mx:Component>
    <mx:CheckBox >
    </mx:CheckBox>
   </mx:Component>
  </mx:itemRenderer>
 </mx:List>
 <mx:HBox width="100%"  backgroundColor="#E2DEDE" paddingBottom="2" paddingLeft="2" paddingTop="2" paddingRight="2" borderStyle="solid">
  <mx:Button label="All"  id="btnAll" click="selectAll()" />
  <mx:Button label="None" click="resetAll()"/>
 </mx:HBox>
</mx:VBox>
Vidya