PropertyInjector

(This tag must be placed inside an <Injectors> tag)

An Injectors tag defined in the Event Map is a container for InjectorPropertys that will inject properties coming from a source to a target.

<Injectors target="{MyTargetClass}">
   <PropertyInjector targetKey="propertyToPopulate" source="{MyModel}" sourceKey="propertyFromMyModel" />
</Injectors>

Attributes

targetKey

String

required

The property of the target (defined in the parent Injectors tag) that needs to be injected.

source

Class or Object

The object that will be the source that will populate the target property. If this is an object, it will used as is. If this is a class, then an already instantiated object will be retrieved from the cache (instantiated by MethodInvoker or ObjectBuilder). If cache does not contain an object of this class, a new object will be created and added to the cache.

sourceKey

String

Property of the source that will be used to populate the target property. Mate will attempt to bind this property to the target property so that whenever the property on the source changes its value, the target will be updated with the new value.

If this attribute is not supplied, then the source object will be injected into the target (instead of a property of the source)

targetId

String

If you use this attribute, only targets that have this id will be injected the property. This id is the one defined in MXML.

Injecting views

You can inject values to properties declared in views. If you use the default settings in the tag InjectionSettings, then you only need to create a property in your view. Then you need a source that will store the value the view will get. For example, if you have a UserManager class that stores the current user, and you want to show information about that user in a view, you can do the following:

  1. Have a view called UserInformation
  2. In that view, have a property called "user".
  3. In your UserManager class, have a public bindable property called currentUser ( this property can be read-only by the use of getters).
  4. Inject this property into the view.

<Injectors target="{UserInformation}">
   <PropertyInjector targetKey="user" source="{UserManager}" sourceKey="currentUser" />
</Injectors>

When the view is instantiated, the property user will be injected into it with the value coming from the UserManager. If the property on the UserManager is bindable, the view will get the latest value any time it changes.

The source can be any "model" that stores data. We use "Managers", but the data could also be stored in a ModelLocator. For example:

<Injectors target="{UserInformation}">
   <PropertyInjector targetKey="user" source="{ModelLocator.getInstance()}" sourceKey="currentUser" />
</Injectors>

Our source will be an already instantiated object (the instance of the ModelLocator), and then we'll bind the property currentUser to the target property.

Injecting view adapters

You can also inject other objects into your views that are not data coming from a model.

As an example, you can inject a "view adapter" into your view. You would then send data to the adapter, which the adapter would format, massage and filter specifically for the view. Data would be send to the adapter also via injection.

<Injectors target="{UserInformation}">
   <!-- create the adapter -->
   <ObjectBuilder generator="{UserInformationAdapter}" registerTarget="true" />
   <!-- inject the adapter into the view -->
   <PropertyInjector targetKey="myAdapter" source="{lastReturn}" />
</Injectors>

In the code above, the view will contain a public property called "myAdapter". Then the view can use it to access the adapter properties to populate its controls.

In order to populate the adapter with the data, we can use injectors just like we did in the model-to-view example, but instead of injecting the view, we'll inject the adapter:

<Injectors target="{UserInformationAdapter}">
   <PropertyInjector targetKey="user" source="{UserManager}" sourceKey="currentUser" />
</Injectors>

23 responses

  1. The PropertyInjector API docs say "PropertyInjector sets a value from an object (source) to a destination (target). If the source object is an IEventDispatcher, the PropertyInjector will bind the source with the target. Otherwise, it will only set the property once."

    Because the [Bindable] tag causes the object to implement IEventDispatcher, the docs should be rewritten to say something like: "PropertyInjector sets a value from an object (source) to a destination (target). If the source object is [Bindable] or impements IIEventDispatcher, the PropertyInjector will bind the source with the target. Otherwise, it will only set the property once."
  2. Hi Mike,
    I updated the API explaining better the code.
    Now it says "If the source key is bindable, the PropertyInjector will bind the source to the targetKey"
  3. What if I wanted to inject a value into a view that contains a ProgressBar. The only way to update a progressBar value is to physically use the setValue() function. There is no bindable property on the progressBar that reflects it's current progress value.

    Hope that made sense :-\
  4. Hi Kyle,
    If that information is outside the view and you want to inject it, then use a public setter, instead of a plain public property. Then use setValue when the binding calls your setter.
    ie:
    public function set progress(value:Number):void {
       myProgressBar.setValue(value);
    }
  5. Thanks, Laura for the response. What I realized after reading the documentation further was that I could pass an object that is announcing the progress events to the ProgressBar and it takes care of the rest. My ApplicationManager contains the appUpdater as a bindable property which is then Injected into the view that contains the progressbar.
  6. hi,

    is there a way to inject objects directly. because i see that you always need a provide a source( the class to be used) and the sourceKey( the object).
    How do you inject an object which is not part of Model nor singleton.
    [Ex, if you want to inject an implementation like spring, how do achive this?]
  7. pramod,
    As stated in the docs above, if the sourceKey is not supplied, then the source object will be injected into the target. You don't have to provide the sourceKey, only the source is required.
  8. Is there anyay to inject a property using a custom method, rather than the setter?

    Some sort of method invocator that works on a targetKey, instead of a generator. Because the methid invoker creates a new object everytime to invoke the method, i need an existing object like the targetKey

    thanks!
    Peter
  9. <Injectors target="{UserInformation}">

    I'm uncomfortable with the way this works. The reference to the target is the Class and not the instance of the class. What if I have lots of instances of a class and I need to inject into a specific one?
  10. Is it possible to reference a property of a VO as the sourceKey like this ...

    <Injectors target="{VideoControlBar}" >
          <PropertyInjector targetKey="videoPlayhead" source="{AppManager}" sourceKey="videoProgressVO.playhead" />
       </Injectors>

    I use VO's in my manager and would like to then bind the properties to my Views properties.
  11. I guess I need the equivalent of a Singleton. I need to reference my instance of the AppManager so in the source I can use source="{appManagerInstance.myVO}" and then use the VO property sourceKey string.

    What's confusing me is the references to the classes and not their instances. Is it possible to create the object in the EventMap and then reference those instances in the injectors?
  12. Lee,
    Yes, Managers are cached. I think you should head to the forums and ask your questions there. I am the only one here that receives notifications for the documentation comments.

    Thanks!
  13. Hi,

    I've experienced that if the source of the PropertyInjector is an object (i.e.: myObject), this must be instantiated before Mate initializes otherwise it will complain that source is not assigned. You can instantiate the object upon its declaration, for example.

    Pay also attention to the fact that injection won't work any more if you reassign the object (i.e.: myObject = newObject). You have to copy values from newObject to myObject in order to keep things working.

    Thank you for your work guys.
    Best wishes, Alessandro
  14. Does property injector support only for primitive data type properties in the sourcekey? How about supporting custom model objects inside sourcekey objects? in the below case userinfo is a model. And primitive data type values are injected like String but a nested model inside the sourcekey is not being injected correctly. Is this case supported?

    <Injectors debug="true" target="{LoginView}">
    <PropertyInjector source="{UserManager}" sourceKey="userInfo" targetKey="userInfoObject"/>
    </Injectors>
  15. Vinoth,
    The value stored in the sourceKey can be of any type. Many of the examples show things like ArrayCollections, a User object, etc.
  16. Mostly this is a response for Lee Probert, but hopefully will be useful for everyone. It's quite hard to work out how to 'inject' into a view that already exists (such as one inside a ViewStack that at some point in the past has been at the front). I've written a post here that explains how i got around this issue:

    http://whichplug.tumblr.com/post/297255217/injecting-into-an-existing-view-with-mate
  17. Hi, i've been using Mate quite recently, i'm beginning to get the hang of it.
    but i've hit a snag with it.
    i can't seem to inject an array in another array, is that even possible in mate?
    help would be appreciated

    thanks in advance
  18. Hi, my question is related to PropertyInjector:

    I have a manager which contains a bindable object (contains set of objects). But some how the above tag is setting the property only once.

    Whereas if the object contains a simple class, then propertyInjector is working fine i.e, when ever the source is changed the target is getting the latest object.

    Also, if the first object is wrapped in ArrayCollection, propertyInjector is working fine.

    Can anybody explains what I am doing wrong. I will appreciate your response.
  19. I have the injector working properly. However, if I'm injecting the parameter 'id_user' to viewA, which contains [Bindable] public var id_user:int; , is there a way for the injector to indicate to ViewA that it just changed the value? Then I could invoke a method within viewA.

    Is their an efficient way to handle that without ditching the injector and going back to event dispatches?
  20. I'm trying to inject a class into a view but since the injector needs to wait until the class is instantiated from the results of a HTTPServiceInvoker, I'm not sure how to proceed

    <Injectors target="{myView}">
    <PropertyInjector targetKey="config" source="{myClass}">
    </Injectors>

    This would work IF I didn't need to wait for {myClass} to be instantiated by the HTTP Service. However if I change the target to myClass, it waits but it won't be injected into the view.

    Thanks.
  21. Binding on non-referenced objects (String, int...) doesn't seem to be working for me.

    For example, in my Manager I have
    [Bindable]
    public var foo : String;

    In my PresentationModel I have
    [Bindable]
    public var foo : String;

    Then I inject the Manager foo into the PresentationModel

    <Injectors target="{myPresentationModel}">
    <PropertyInjector targetKey="foo" source="{myManager}" sourceKey="foo">
    </Injectors>

    When I change the value of foo in my PresentationModel, it does not propagate to the Manager.

    Referenced objects like Arrays and such work fine, but it's logical since the reference stays the same.
  22. Just one pecision :
    The binding works in one way. When I change the value in the Manager, it is changed in the PresentationModel, but not the other way around
  23. My application uses Flex 4 and Mate framework 0.9.1. I'm facing an issue with the PropertyInjector being fired twice when there's a mapping between a manager and a view.

    I have not shared the original code here, but it looks similar to the following: Based on an event, a property (someData) in MyManager is updated. A property injector updates this new value in a target view (MyView). The issue is - when onDataChanged is invoked and the property someData is updated, the method "set someData" in the view is fired twice. I know that the view is instantiated only once because I have debugged the init and creationComplete events. The source property in MyManager is also updated only once as per the trace.

    This would indicate that the property injector is fired twice. Would anyone know under what conditions this can happen? Any pointers would be appreciated!

    MyEventMap.mxml

    <EventHandlers type="{DataChangedEvent.GET}" debug="true">
    <MethodInvoker generator="{MyManager}" method="onDataChanged"
    arguments="{[event.x,event.y,event.name]}">

    </MethodInvoker>
    </EventHandlers>


    <Injectors target="{MyView}" debug="true">
    <PropertyInjector targetKey="someData" source="{MyManager}"
    sourceKey="someData">

    </PropertyInjector>
    </Injectors>
    DataHolder.as

    public class DataHolder
    {
    public function DataHolder()
    {
    }
    public var x:Number;
    public var y:Number;
    public var name:String;
    }
    MyManager.as

    public class MyManager extends EventDispatcher
    {
    ....

    [Bindable] public var someData:DataHolder;

    public function onDataChanged(x:Number,y:Number,name:String):void{
    trace("dataChanged");
    var temp:DataHolder = new DataHolder();
    temp.name=name;
    temp.x=x;
    temp.y=y;
    someData = temp;

    }
    }
    MyView.mxml

    public function set someData(data:DataHolder):void {
    trace("setSomeData x="+data.x+",y="+data.y+",name="+data.name);
    }

Comments now closed