Sunday, May 1, 2011

Flex databinding a function

Does anyone know how to programmatically bind a property to a function that isn't a getter? IE: I have a function that returns a translated string based on the identifier you pass it. How do I do this in AS3 rather than MXML? (reason being - I have a dynamic layout that I render based on XML and so have create and add all children programmatically).

From stackoverflow
  • You can bind functions to any event that is dispatched when the property changes. use the addEventListener() member method to add a handler. Read the Flex 3.0 documentation here.

  • You can call a setter function using BindingUtils.bindSetter(). You can use this to call a setter function that calls your translation function and sets the return value to a specified place. Unfortunately you can't dynamically specify the host of the setter like you can with BindingUtils.bindProperty().

  • I'm not sure this is what you're looking for, but I've done something similar this way:

    Say you've declared a Label using your function:

    <mx:Label text="{LocaleUtil.getMessage('label.description')}"/>
    

    That getMessage function reads a XML file depending on the selected Locale.

    If the user changes the Locale, you should call executeChildBindings(true) on any container or on the whole application:

    this.parentApplication.executeChildBindings(true);
    

    That will force every child UIComponent to execute the bindings again.

  • Since functions are object in actionscript3.0, you may add properties to them, the same as you would any other object,

    var f : Function = function() : void{ 
       trace("Value of testProp: " + arguments.callee.testProp ); 
    };
    (f as Object).testProp = 'TESTING';
    f();
    

    arguments.callee is used like the this keyword. arguments.callee holds a reference to the function it is used inside of.

    I'm not sure if this is what you wanted, but this is how you would add a property to a function.

    I'm sorry I think i got it backwards, you want to add a function to a property, not add a property to a function. O well, hope you enjoy this post anyway.

  • Ok so to be honest I managed to resolve this one myself by doing:

    public function loadStringBinding(aIdentifier:String, aField:UIComponent, aProperty:String, aAddtlChars:String = null):Function 
    {
     return function():void {
      var str:String;
      if(aAddtlChars)
      {
       str = aAddtlChars;
      }
      else
      {
       str = '';
      }
     if(_localePacks.get(currentLocale))
     {
      if(XML(_localePacks.get(currentLocale)).translatedString.(@identifier==aIdentifier).@translation.toString().length > 0)
      {
       aField[aProperty] =  XML(_localePacks.get(currentLocale)).translatedString.(@identifier==aIdentifier).@translation + str;
       return;
      }
      else
      {
       aField[aProperty] =  aIdentifier + str;
       return;
      }
     }
     else
     {
      //TODO: Replace with webservice call to get individual string
     }
    
     aField[aProperty] =  'No locale pack' + str; 
     return;
     }
    }
    

    What this does is return the function that it gets bound to, so I can pass it which ever component I want the property go get bound to. It is implemented like:

    _currentWatchers.addItem(BindingUtils.bindSetter(LocaleManager.instance().loadStringBinding('firstName, myCFormItem, 'label', '*'), LocaleManager.instance(), 'newLocale'));
    

    I'm sure that it doesn't really make sense to anyone seeing as the rest of the code isn't here and it's a bit involved of an application, but just know that the solution is that the bindSetter function takes a funciton as the first parameter, so I created a function that creates a function that executes the binding that I wanted. If that makes sense to anyone else.. awesome! Thanks for anyone who contributed though!

  • If you want to bind the result of a function, you will have to mention the type of event that will be triggered when the function's result changes (see point 2).

    private var foo:int;
    
    [Bindable(event="myCustomFunctionBinding")]
    public function myFunction():String
    {
        return "This is foo :" + foo;
    }
    

    Then, when you want all elements to update the binded value, you must dispatch the event yourself :

    private function bar():void
    {
        foo++;
        dispatchEvent(new Event("myCustomFunctionBinding"));
    }
    

    In which case, you can bind like this :

    <mx:TextArea text="{myClass.myFunction()}" />
    

0 comments:

Post a Comment