views:

212

answers:

3

I have various custom component instances in my flex app. I want to loop through them recursively and get their instance Ids. The recursive part is very important to me. Can someone tell me what's the best way to do it? I have tried doing this, but it didn't do recursive:

for each (var myItem:* in this.MasterContainer.childDescriptors)
{
   trace(myItem.id);
}
+2  A: 

This will do it:

private function findControlsRecursive(current:DisplayObjectContainer, controls:ArrayCollection):void
{
 for(var idx:int = 0; idx < current.numChildren; idx++)
 {
  var child:DisplayObject = current.getChildAt(idx);
  controls.addItem(child.name);
  var childContainer:DisplayObjectContainer = child as DisplayObjectContainer;
  if(childContainer)
  {
   findControlsRecursive(childContainer, controls);
  }
 } 
}

public function findControls():ArrayCollection
{
 var controls:ArrayCollection = new ArrayCollection();
 findControlsRecursive(Application.application as DisplayObjectContainer, controls);
 return controls;
}
Dan Monego
+2  A: 

I use this to iterate over all components in several methods, with some methods building up results in the accumulator acc (e.g., writing to a String, keeping a count of all, whatever). Iteration includes component chrome when useRaw is true.

 /**
  * Descends through subcomponents applying function
  */
 public static function visitComponent(component:Object, fn:Function, useRaw:Boolean = false, acc:Object = null):Object {
  var newAcc:Object = fn.call(null, component, acc);

  if (component is mx.core.Container) {
   var kids:mx.core.Container = mx.core.Container(component);
   var childList:IChildList;
   if (useRaw) {
    childList = kids.rawChildren;
   } else {
    childList = kids;
   }
   for (var i:int = 0; i < childList.numChildren; ++i) {
    visitComponent(childList.getChildAt(i), fn, useRaw, newAcc);
   }
  } else if (component is DisplayObjectContainer) {
   var displayObjContainer:DisplayObjectContainer = component as DisplayObjectContainer;
   for (var j:int = 0; j < displayObjContainer.numChildren; ++j) {
    visitComponent(displayObjContainer.getChildAt(j), fn, useRaw, newAcc);
   }    
  }
  return newAcc;
 }

 /**
  * Randomly resets backgroundColor of subcomponents
  */
 public static function colorizeComponent(component:Object):void {
  var fn:Function = function(c:Object, acc:Object):Object {
   if (c is UIComponent) {
    (c as UIComponent).setStyle("backgroundColor", Math.random() * uint.MAX_VALUE);
    (c as UIComponent).setStyle("backgroundAlpha", 0.2);
   }
   return null;
  }

  visitComponent(component, fn);
 }
Michael Brewer-Davis
+1  A: 

Michael Brewer-Davis' function is more through than this example (handling rawchildren, non-flex components, etc), but there's no need for recursion to traverse a tree:

function toEveryComponentDo(f:Function):void
{
    var component:UIComponent = Application.application;
    var components:Array = component.getChildren();
    f(component);

    while (components.length > 0)
    {
        var childComponents:Array = [];

        for each (component in components)
        {
            f(component);
            if (component is Container)
            {
                childComponents = childComponents.append(Container(component).getChildren());
            }
        }

        components = childComponents;
    }
}
Sophistifunk
I liked your function, but it seems it has some syntax errors.There is no .getChildren() function for UIComponent.
Q-rius
That's what happens when you write code in-browser :)
Sophistifunk