(This tag must be placed inside an <EventHandlers> tag, <MessageHandlers> tag or <Injectors> tag)
When placed inside an EventHandlers block, and the list of handlers is executed, it will create an object of the class specified in the "generator" attribute. You can pass arguments to the constructor of this class that come from a variety of sources, such as the event itself, a server result object, or any other value. Unless you specify cache="false", this object instance will be "cached" and not instantiated again when using the MethodInvoker or PropertyInjectors
Example:
<ObjectBuilder generator="ClassNameToInstantiate"
constructorArguments="{['argument1','argument2']}" />
The above example would be the same as doing the following in ActionScript code:
var myObject:ClassNameToInstantiate = new ClassNameToInstantiate('argument1', 'argument2');
Attributes
generator
required
The generator attribute specifies what class should be instantiated.
Suppose you have a class called "MyClass" in the package com.yourdomain.business.
You can specify a complete path to com.yourdomain.business.MyClass:
<ObjectBuilder generator="com.yourdomain.business.MyClass" />
Generally you may want to use a binding to specify the class name. Assuming you have an import statement like this in your Event Map:
import com.yourdomain.business.MyClass;
or simply:
import com.yourdomain.business.*;
You can then instantiate your worker using bindings:
<ObjectBuilder generator="{MyClass}" />
The advantage of using this syntax is that if you are using Flex Builder, you can press the command key (Mac) or the Ctrl key (Windows) and click on the generator class (MyWorker in the example) and it will take you to the class definition.
constructorArguments
Array
If the constructor of you class requires arguments, you can pass them via the "constructorArguments" attribute. Suppose your constructor has the following signature:
public function MyClass(name:String, value:Number)
then instantiating the class as follows will work:
<ObjectBuilder generator="{MyClass}"
constructorArguments="{['Tom', 36]}"/>
Note that the constructorArguments attribute expects an array. Besides passing literal values, you can pass values coming from the event that triggered the handlers list:
<ObjectBuilder
generator="{MyClass}"
arguments="{[event.userName, event.age]}"/>
This assumes that the event contained a userName property and an age. See Passing Arguments for more information.
cache
either "global", "inherit", "local" or "none"
The cache attribute lets you specify whether this newly created object should be kept live so that the next time an instance of this class is requested, this already created object is returned instead. The instance can be requested by a MethodInvoker or a PropertyInjector.
For example, you may want to have a MethodInvoker use an already instantiated instance created by an ObjectBuilder. Since the default value for this attribute is "inherit", it will do that by default. On the other hand, if you wanted to have two different instances, then you must set this attribute to "none".
The value "inherit" will globally cache the object in a normal EventMap and it will locallly cache the object in a LocalEventMap. If you want to cache globally in a LocalEventMap so that the object can be accessed from other event maps, set the value to "global".
<EventHandlers type="myEventType">
<ObjectBuilder generator="{MyClass}" />
</EventHandlers>
<EventHandlers type="myOtherEventType">
<MethodInvoker generator="{MyClass}" method="doWork" />
</EventHandlers>
Inner tags
Properties
You can add properties to your instantiated object by using the Properties tag inside the ObjectBuilder tag.
These properties must be public.
Suppose you are creating an instance of a ShippingCalculator class. This class has a property called weightFactor and flatFee. In order to set those two properties, you can use the <Properties> inner tag. As attributes of the Properties tag, you can specify the names of your properties and set the values of those properties by setting the value of those attributes as follows:
<ObjectBuilder generator="{ShippingCalculator}">
<Properties weightFactor="0.5" flatFee="3" />
</ObjectBuilder>
Besides specifying literal values, you can assign values coming from the event that triggered the sequence:
<ObjectBuilder generator="{ShippingCalculator}">
<Properties weightFactor="{event.factor}" flatFee="{event.fee}" />
</ObjectBuilder>
This assumes that the original event contained a factor property and a fee property.
Other sources can include service results or faults, values returned by a MethodInvoker, etc.
<EventHandlers type="{PopupLoginForm.SHOW}" debug="true">
<InlineInvoker method="showLoginScreen();" />
</EventHandlers>
with
private function showLoginScreen()
{
var login:LoginScreen = LoginScreen(PopUpManager.createPopUp( this, LoginScreen , true));
}
declared in a script block. Did work.
What do I do wrong, please?
Thanks,
Sergei.
"Did not work" instead of "Did work"
Sorry.
<ObjectBuilder
generator="{MyClass}"
arguments="{[event.userName, event.age]}"/>
Thanks,
Rost
thanks,
euge
First set cache=none when you create them. Create the first then use DataCopier to copy the lastReturn into data.instance1. Then create the second and DataCopier lastReturn to data.instance2.
great thanks!
But in the following example it seems that mate tries to instantiate the object again:
<EventHandlers type="{FlexEvent.PREINITIALIZE}">
<ObjectBuilder
generator="{TerminalPresentationModel}"
constructorArguments="{scope.dispatcher}" />
</EventHandlers>
// ... few lines later
<Injectors target="{TerminalPresentationModel}">
<PropertyInjector targetKey="date" source="{DateManager}" sourceKey="currentDate" />
</Injectors>
I get the following error:
- ERROR: Wrong number of arguments supplied when calling the constructor
- TARGET: TerminalPresentationModel
- TAG: PropertyInjector
- METHOD: constructor
- FILE: TerminalMainEventMap
- NO ARGUMENTS SUPPLIED
When I'm debugging I notice that the TerminalPresentationModel is instantiated (with the dispatcher as constructor argument). The error occurs after the TerminalPresentationModel is instantiated.
Any hints what's wrong with my code?
<Injectors target="{yourUI}>
<ObjectBuilder generator="{TerminalPresentationModel}"
constructorArguments="{scope.dispatcher}"
registerTarget="{true}"/>
<PropertyInjector targetKey="{model}"
source="{lastReturn}"
sourceKey="modelSource"/>
</Injectors>
However, I typically don't add the dispatcher in the constructor, but rather inject into the presentation model in the injectors so that you can use the presentation model with different "yourUI" instances if you cache it locally.
I am using <HttpInvoker instace"some method to get the HttpService">
How to pass a parameter to above instance method. Please give me some sample code.
Thansk
Sri
Thank you very much, this was the problem :)
Your hint about don't adding the dispatcher in the constructor is perhaps a better solution, but in my case not necessary.
@Sri:
http://mate.asfusion.com/page/documentation/tags/services/httpserviceinvoker
Look at the request inner tag. This should solve your issue.
I've encountered the same thing recently and my workaround is actually derived from Mark's suggestion (don't use constructor to pass the dispatcher reference). I'm not understanding 100% why but this works for me:
1. Remove the constructor with dispatcher argument in TerminalPresentationModel
2. Create a setter for mateDispatcher in TerminalPresentationModel
3. Use this configuration
<EventHandlers type="{ FlexEvent.PREINITIALIZE }">
<!-- It is important to know that registerTarget has to be TRUE in order to reuse in Injectors
and all the properties will be set later in Injectors -->
<ObjectBuilder generator="{ TerminalPresentationModel }" registerTarget="{true}"/>
</EventHandlers>
<Injectors target="{TerminalPresentationModel}">
<!-- set globalDispatcher reference here. You can add additional property injectors to make it like DI -->
<PropertyInjector targetKey="mateDispatcher" source="{scope.dispatcher}" />
<PropertyInjector targetKey="date" source="{DateManager}" sourceKey="currentDate" />
</Injectors>
<Injectors target="{SomeView}">
<!-- reference here -->
<PropertyInjector targetKey="presenter" source="{TerminalPresentationModel}" />
</Injectors>
"For example, you may want to have a MethodInvoker use an already instantiated instance created by an ObjectBuilder. Since the default value for this attribute is "inherit", it will do that by default."
However:
<mate:EventHandlers type="{FlexEvent.PREINITIALIZE}">
<mate:ObjectBuilder generator="{ModuleControl}"/>
</mate:EventHandlers>
<mate:EventHandlers type="{ModuleControlEvent.LOAD}">
<mate:MethodInvoker arguments="{[currentEvent.sModuleName]}" generator="{ModuleControl}" method="load"/>
</mate:EventHandlers>
<mate:EventHandlers type="{ModuleControlEvent.READY}">
<mate:EventAnnouncer generator="{ModuleControlEvent}" type="{ModuleControlEvent.LOAD}"/>
</mate:EventHandlers>
package shared.controllers
{
import com.asfusion.mate.core.GlobalDispatcher;
import shared.events.ModuleControlEvent;
public class ModuleControl
{
public function ModuleControl()
{
trace("Hi there!");
var oGlobal:GlobalDispatcher = new GlobalDispatcher();
oGlobal.dispatchEvent(new ModuleControlEvent(ModuleControlEvent.READY));
}
public function load(sModuleName:String=""):void{
trace("LOAD THE: "+sModuleName);
}
}
}
Creates an infinite loop because the methodInvoker creates a new instance rather than using cache.
1. I would turn on debugger in tags.
2. Would put a breakpoint in the ModuleControl constructor and then you can use the FlashBuilder debugger to look at the stack trace. Sometimes this will lead you to something else at the root, vs. what you think. If you expect global cache (which I beilieve is your scenario), you would only hit it once. If more times, then you get the stack trace each time to see where it started.
3. I would comment out the dispatchEvent line, how many times do you hit the contstructor then?
The following does not work since "id" is reserved:
<ObjectBuilder generator="{Object}" cache="none">
<Properties id="{event.list}" />
</ObjectBuilder>
This does not work either since event.list should be bound:
<RemoteObjectInvoker instance="{jobService}" method="DeleteJob" arguments="{{id:event.list}}">
Is there any other way to send an "id" to a server API?