(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:
- Have a view called UserInformation
- In that view, have a property called "user".
- In your UserManager class, have a public bindable property called currentUser ( this property can be read-only by the use of getters).
- 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>
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."
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"
Hope that made sense :-\
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);
}
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?]
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.
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
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?
<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.
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?
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!
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
<Injectors debug="true" target="{LoginView}">
<PropertyInjector source="{UserManager}" sourceKey="userInfo" targetKey="userInfoObject"/>
</Injectors>
The value stored in the sourceKey can be of any type. Many of the examples show things like ArrayCollections, a User object, etc.
http://whichplug.tumblr.com/post/297255217/injecting-into-an-existing-view-with-mate
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
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.
Is their an efficient way to handle that without ditching the injector and going back to event dispatches?
<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.
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.
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
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);
}