views:

40

answers:

1

On creation complete my parent component executes an "init" function which simply sets public bindable variables in child components. I'd like the child components to watch these variables and upon being set use them. However, for some reason the ChangeWatcher is not firing with the change of the variable. Below is my code; anyone see what's wrong? Thanks.

Parent Component

private function init():void
{
 userInfo.user = new User("Tom");
}

Child Component -- "userInfo"

...
[Bindable] public var user:Object;

private function init():void
{
  ChangeWatcher.watch(this, "user", function(evt:PropertyChangeEvent):void
  {
    Alert.show(evt.property);
  }
}
A: 

You said:

On creation complete my parent component executes an "init" function which simply sets public bindable variables in child components. I'd like the child components to watch these variables and upon being set use them.

It breaks encapsulation to try to have the child component access the parent. Parents can access, children, but children should never access parents. However, any given component should be aware of when it's values changes and update itself accordingly. The use of get/set properties and the Flex Component LifeCycle are the proper way to do that.

When you make a component Bindable that means it can be used as the source of data binding. It almost sounds to me like you're trying to use said properties as the target for data binding and are struggling to update your component.

If I understand what you're after, I wouldn't use the ChangeWatcher at all. Just expand your user property into a get/set property and either implement your changes in the set method of the property, or possibly in commitProperties using a flag.

Something like this:

private var _user : Object;
[Bindable]
public function get user():Object{
 return this._user;
}

public function set user(value:Object):void{
 this._user = value;
 Alert.show(value);
}

Or even better:

protected var userChanged : Boolean = false;
private var _user : Object;
[Bindable]
public function get user():Object{
 return this._user;
}
public function set user(value:Object):void{
 this._user = value;
 this.inalidateProperties()
 userChanged = true;
}

public function commitProperties():void{
 if(userChanged == true){
   Alert.show(value);
   userChanged = false;
 }
}
www.Flextras.com
@Flextras: Thanks for the explanation. Your suggestions achieve EXACTLY what I was after. However, why is the 2nd approach better then the 1st?
tommac
@tommac The 2nd approach is better because it allows you to coordinate different property changes at the same time, and consolidate code for implementing changes. The need is not obvious in This simple example. But, if I take take a more complex component, such as the Flextras Calendar I can better demonstrate. Three properties control which month is displayed: displayedMonth, displayedDate, and displayedYear. All execute similar code when changed. By using the component lifeCycle, if someone changes all 3 in succession, the component only updates itself once not three times. Make sense?
www.Flextras.com
@Flextras: From your example, I conceptually understand the difference and benefit of using the 2nd approach. With that said, I'm curious to see it implemented. Do you know where I can find an example implementation?
tommac
Read up on the component lifecycle and then open any Flex Framework component. The full source is available. You could also check out The Flex Show screencast series on Creating Flex Components, which goes over the component lifecycle in depth.
www.Flextras.com
Thanks for the heads-up on "The Flex Show"; the screencasts where very helpful.
tommac
Glad you enjoyed the screencasts. I created them. You can get our series on creating Flex 4 Components through our Pledge Drive. ( http://www.theflexshow.com/CWFRTB/index.cfm )
www.Flextras.com