0

I know that it is possible to make a parameter of a component depend on a variable, provided that variable contains the [Bindable] tag. This means that updating the value of the Bindable variable automatically updates the component.

Is it possible to make another variable depend on a Bindable variable?

In the example below I have a variable btnClicked that is bound. When btnClicked is changed by the function btnClick() being called, the text in the TextArea is updated as expected.

I would like to be able to make another variable, btnText, be updated when btnClicked is updated. I do not know how to communicate this dependency. In the code below the value of btnText is initially "clickMe" as expected. However, when btnClicked changes, the text on the button does not update to "unclickMe".

<fx:Script>
    <![CDATA[
        [Bindable]
        public var btnClicked:Boolean = false;

        public function btnClick():void{
            btnClicked = !btnClicked;
        }

        [Bindable]
        public function get btnText():String{
            return btnClicked?"unclickMe":"clickMe";
        }
    ]]>
</fx:Script>

<s:Button click="btnClick()" label="{btnText}"/>

<s:TextArea y="50" text="{btnClicked?'Button is clicked':'Button is unclicked'}"/>

How can I change the code above so that btnText automatically updates when btnClicked is changed?

Would it be possible to have an arbitrarily long chain of connected variables each of which updates when the previous one updates?

danxinnoble
  • 155
  • 1
  • 6

3 Answers3

3

You can also use a ChangeWatcher to detect when your bindable property is updated :

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="init(event)">

    <fx:Script>
        <![CDATA[

            import mx.binding.utils.ChangeWatcher;
            import mx.events.FlexEvent;

            public var watcher:ChangeWatcher;

            [Bindable]
            public var btnClicked:Boolean = false;
            [Bindable]
            public var btnText:String = 'clickMe';

            protected function btnClick():void {
                btnClicked = !btnClicked;
            }

            protected function init(event:FlexEvent):void
            {
                watcher = ChangeWatcher.watch(this, 'btnClicked', watcherListener);
            }

            protected function watcherListener(event:Event):void {
                btnText = btnClicked ? 'unclickMe' : 'clickMe';
            }

        ]]>
    </fx:Script>

    <s:Button x="303" y="30" label="{btnText}" click="btnClick()"/> 
    <s:TextArea x="303" id="txt" y="96" text="{btnClicked ? 'Button is clicked' : 'Button is unclicked'}"/>

</s:Application>

Hope that can help.

akmozo
  • 9,829
  • 3
  • 28
  • 44
  • Is it possible to make the ChangeWatcher watch multiple variables? I have asked this as a separate question [here](http://stackoverflow.com/questions/33571103/flex-is-it-possible-for-a-changewatcher-to-watch-multiple-variables) – danxinnoble Nov 06 '15 at 16:19
  • @danxinnoble I think that you can **NOT** use one `ChangeWatcher` for multiple properties. – akmozo Nov 06 '15 at 16:59
2

In this case, all you have to do is update your btnClick function to dispatch a PropertyChangeEvent:

public function btnClick():void{
    btnClicked = !btnClicked;
    dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE));
}

This works because of the way [Bindable] works - see What does [Bindable] mean in actionscript? for a nice explanation. Using the Bindable metadata tag and Binding to functions, Objects, and Arrays are good resources for background reading, too.

Edit: Don't forget the import statement!

import mx.events.PropertyChangeEvent;

Flash Builder will insert the import statement for you if you ctrl-space while typing PropertyChangeEvent.

Community
  • 1
  • 1
Brian
  • 3,850
  • 3
  • 21
  • 37
  • See my edit. I didn't even think of writing out the import because Flash Builder handles imports for me based on autocomplete. – Brian Nov 04 '15 at 16:24
  • Hmm. The value of btnText still does not change when I click the button. Or at least the text displayed on the button does not change. Is the button's text changing from 'clickMe' to 'unclickMe' for you? – danxinnoble Nov 04 '15 at 16:28
  • @danxinnoble `addEventListener`(for the custom event) section is supposed to be inserted where you want to check the value. – coner Nov 05 '15 at 07:06
  • Yeah. I tested it before I posted my answer. What version of Flex are you using? – Brian Nov 05 '15 at 16:40
  • I'm using Apache Flex SDK 4.14.1. – danxinnoble Nov 06 '15 at 14:24
  • 1
    @coner is right, I needed to add a listener. I have done this as follows: `import mx.events.FlexEvent; private function init(event:FlexEvent):void{ myBtn.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateBtnText); }` I also needed to add `creationComplete="init(event);"` to the application tag. This works, but I find akmozo's solution simpler. – danxinnoble Nov 06 '15 at 14:29
1

I have found a solution, but if someone has a cleaner solution that makes use of in built Flex features please post it.

The following code updates the value of btnText each time the value of btnClicked is changed. It does this by having a setter function for btnClicked that explicitly calls function updateBtnText. See this explanation for more information about how getters and setters allow you to call other functions any time a variable is read or written.

<fx:Script>
    <![CDATA[
        private var _btnClicked:Boolean = false;

        [Bindable]
        public function get btnClicked():Boolean{
            return _btnClicked;
        }

        public function set btnClicked(newBtnClicked:Boolean):void{
            _btnClicked = newBtnClicked;
            updateBtnText();
        }

        private function updateBtnText():void{
            btnText = btnClicked?"unclickMe":"clickMe";
        }

        public function btnClick():void{
            btnClicked = !btnClicked;
        }

        [Bindable]
        public var btnText:String = btnClicked?"unclickMe":"clickMe";

    ]]>
</fx:Script>

<s:Button click="btnClick()" label="{btnText}"/>

<s:TextArea y="50" text="{btnClicked?'Button is clicked':'Button is unclicked'}"/>
danxinnoble
  • 155
  • 1
  • 6