RSS LinkedIn Twitter

Flex: Binding to an Interface

We recently ran into a problem using our TrueMVC framework (which prescribes coding models to an interface and binding directly to the models) in that it was not obvious how to make the properties (getters/setters) of an interface bindable.

Consider the following interface:

[as3]
package model {
public interface ISimpleModel {
function get name() : String;
function set name(v : String) : void;
}
}
[/as3]

Having the following implementation:

[as3]
package model {
public class SimpleModel implements ISimpleModel {
private var _name : String = ”;

public function SimpleModel() {}

public function get name() : String { return _name; }
public function set name(v : String) : void {
_name = v;
}
}
}
[/as3]

Our goal is to bind to the name property of type ISimpleModel. If we add the [Bindable] tag above the get function declaration in the interface we get the error message:

[bash][Bindable] not allowed on global or package-level functions[/bash]

If we add the [Bindable] tag above the get function definition in the implemtation, or if we use no [Bindable] tag at all (except above our various model instances) then we get a warning:

[bash]Data binding will not be able to detect assignments to "name"[/bash]

Which when executing the code, we observe to be correct.

To get binding to work correctly, you should declare the interface bindable like this:

[as3]
[Bindable]
public interface ISimpleModel {
.
.
[/as3]

And then either declare the implementation class, or specific getter/setter pairs bindable. The warnings and errors go away, and the bindings will work.

Download the poorly commented source for this post here.

In the comments below, Alex Uhlmann suggests using a named Bindable metadata tag on the accessor in the interface.

[as3]
package model {
public interface ISimpleModel {
[Bindable(event="propertyChange")]
function get name() : String;
function set name(v : String) : void;
}
}[/as3]

There should be a corresponding Bindable metadata tag in the implementation, although the event name doesn’t have to be manually specified again. This is the solution we originally wanted since it allows us to avoid class-level binding in cases where we only want property-level.

Tags:

12 Responses to “Flex: Binding to an Interface”

  1. Windcowboy
    July 17th, 2008 at 13:08
    1

    Wow, many thanks! I hit this problem seconds ago and what could have been a big pain is fixed. You rock.

  2. AlexU
    October 20th, 2008 at 05:56
    2

    You can put named Bindable metadata on accessors within the interface. By default you have a propertyChange event.

  3. October 20th, 2008 at 09:23
    3

    @AlexU: Thanks for the suggestion, I incorporated it into my post.

  4. wc
    March 20th, 2009 at 14:39
    4

    This doesn’t work when the ISimpleModel is passed into a e.g. MXML file via a function call e.g.

    private var _model:ISimpleModel;

    private function init(model:ISimpleModel)
    {
    _model=model;
    }

    and then in your MXML if you would use

    it wouldn’t work

    you can work around it with BindingUtils.bindProperty but this requires more code and isn’t so elegant

    if you can make it work with the above mentioned configuration i would be very interested

  5. wc
    March 20th, 2009 at 14:40
    5

    seems like you can’t post brackets
    so adding the MXML example here

    mx:TextInput text=”{_model.name}”

  6. March 20th, 2009 at 15:04
    6

    I think I understand what your asking. Download the following example and see if it’s what you’re trying to do.

    I have an MXML file that extends TextInput, whose text property is bound to its ISimpleModel. The ISimpleModel is passed in via a public method, init. This method is called on creationComplete in the main MXML file, and it passes in an instance of SimpleModel.

    In the main MXML file I have a regular text input, typing and pressing enter will update the model… the bottom text input should reflect it.

    source

  7. wc
    March 21st, 2009 at 00:46
    7

    hi, thx for the quick response!

    your example is almost what I’m trying to do, except that I have no custom TextInput but I directly put {_model.name} in a normal TextInput. This makes no difference however.

    The fact is that I expected it to work withhout having to code the function updateModel(). Because that’s the point of binding. With that extra function, you’re manually putting the value of the textinput back into the model, while it should be done automatically (since binding was used. You can easily see this in action below in textinput 3 & 4). However this is still less code than coding a changewatcher and using BindingUtils to bind the values. Below is some source to clarify:

    private function updateModel() : void
    {
    _model.name = input1.text;
    }

    mx:TextInput id=”input1″ text=”{_model.name}” change=”updateModel()”/
    mx:TextInput id=”input2″ text=”{_model.name}”/
    mx:TextInput id=”input3″ /
    mx:TextInput id=”input4″ text=”{input3.text}”/

  8. March 21st, 2009 at 08:41
    8

    Ok. I see what it is you’re trying to accomplish– two way data binding. By design the data binding mechanism works only one way, you can see by looking at the method signature for BindingUtils.bindProperty.

    Here is a very simple example of two way data binding:

    <mx:TextInput id=”txtOne” text=”{txtTwo.text}” />
    <mx:TextInput id=”txtTwo” text=”{txtOne.text}” />

    If you remove one of the bindings, it only works when you edit one of the text inputs. You can extend this idea onto our example by declaring the SimpleModel (ISimpleModel) in MXML:

    <domain:SimpleModel id=”model” name=”{input.text}” />
    <mx:TextInput id=”input” text=”{model.name}” />
    <mx:Label id=”updater” text=”{model.name}” />

    Here, the text input is both bound to the model, and the model is bound to the text input’s text. The label demonstrates that the model is being updated as the text input’s text changes.

    If you don’t want to declare the model in MXML allowing you to use the binding braces syntax, your only other options are to manually update the model or to use the BindingUtils to set up the binding.

  9. wc
    March 22nd, 2009 at 02:38
    9

    Cool!

    Declaring the model in MXML is more elegant than manually updating the model or using BindingUtils.

    Thanks for clarifying!

  10. Nikos
    August 19th, 2010 at 08:10
    10

    your better off using DI in your view and making that dependacy bindable there.

  11. Danilo
    March 10th, 2011 at 09:56
    11

    Thanks!

1 trackbacks

Leave a Comment

*