I want to pass a parameter to the timer's timerEvent function.
Is it possible?
I know that in c++,I can use the function object,or just use the boost::bind.
Is there something like boost::bind?
you can also extend Timer class with your custom class, for example:
public class DataTimer extends Timer
{
private var _data:Object;
public function DataTimer(delay:Number, repeatCount:int=0)
{
super(delay, repeatCount);
_data = {};
}
public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
_data = value;
}
}
and use it in your callback function
var timerObj:DataTimer = event.currentTarget as DataTimer;
trace("data: "+timerObj.data);
Related
I am having a problem that is driving me nuts.
Recently I configured my BlazeDS to use Array instead of ArrayCollection for performance reasons. Additionally I adjusted my templates to generate Array properties.
Everything wen't fine. All except one function that causes TypeError: Error #1034. These are being thrown before the result callback is called. It claims to have problems casting an ArrayCollection to Array. I removed the generated types to make Flex use Objects instead, but these did not contain any ArrayCollections. My question now is: How can I get the stack-traces of errors thrown in event-handlers?
I allready added handlers for unhandledExceptions in all of my modules and they are called if errors occur in code triggered from user-interaction, but they don't seem to be able to catch stuff thrown by event-handlers.
How can I track these Errors?
Chris
PS: The classes are:
package de.upw.ps.ucg.model.ucg.scheduler {
[Bindable]
[RemoteClass(alias="de.upw.ps.ucg.model.ucg.scheduler.Task")]
public class Task extends TaskBase {
}
}
And:
package de.upw.ps.ucg.model.ucg.scheduler {
import de.upw.ps.ucg.model.oval.common.OvalVersionedIdentifier;
import flash.utils.IExternalizable;
[Bindable]
public class TaskBase {
public function TaskBase() {}
private var _aborted:Boolean;
private var _characteristicsId:String;
private var _currentExecutorPhase:JobExecutorPhase;
private var _definitionSetName:String;
private var _definitionSetVid:OvalVersionedIdentifier;
private var _endTime:Date;
private var _enqueueTime:Date;
private var _environmentId:String;
private var _environmentName:String;
private var _messages:Array;
private var _numberOfDefinitions:int;
private var _processedNumberOfTests:int;
private var _resultsId:String;
private var _schedulerJob:SchedulerJob;
private var _startTime:Date;
private var _statusMessage:String;
private var _taskId:String;
private var _totalNumberOfTests:int;
public function set aborted(value:Boolean):void {
_aborted = value;
}
public function get aborted():Boolean {
return _aborted;
}
public function set characteristicsId(value:String):void {
_characteristicsId = value;
}
public function get characteristicsId():String {
return _characteristicsId;
}
public function set currentExecutorPhase(value:JobExecutorPhase):void {
_currentExecutorPhase = value;
}
public function get currentExecutorPhase():JobExecutorPhase {
return _currentExecutorPhase;
}
public function set definitionSetName(value:String):void {
_definitionSetName = value;
}
public function get definitionSetName():String {
return _definitionSetName;
}
public function set definitionSetVid(value:OvalVersionedIdentifier):void {
_definitionSetVid = value;
}
public function get definitionSetVid():OvalVersionedIdentifier {
return _definitionSetVid;
}
public function set endTime(value:Date):void {
_endTime = value;
}
public function get endTime():Date {
return _endTime;
}
public function set enqueueTime(value:Date):void {
_enqueueTime = value;
}
public function get enqueueTime():Date {
return _enqueueTime;
}
public function set environmentId(value:String):void {
_environmentId = value;
}
public function get environmentId():String {
return _environmentId;
}
public function set environmentName(value:String):void {
_environmentName = value;
}
public function get environmentName():String {
return _environmentName;
}
public function set messages(value:Array):void {
_messages = value;
}
public function get messages():Array {
return _messages;
}
public function set numberOfDefinitions(value:int):void {
_numberOfDefinitions = value;
}
public function get numberOfDefinitions():int {
return _numberOfDefinitions;
}
public function set processedNumberOfTests(value:int):void {
_processedNumberOfTests = value;
}
public function get processedNumberOfTests():int {
return _processedNumberOfTests;
}
public function set resultsId(value:String):void {
_resultsId = value;
}
public function get resultsId():String {
return _resultsId;
}
public function set schedulerJob(value:SchedulerJob):void {
_schedulerJob = value;
}
public function get schedulerJob():SchedulerJob {
return _schedulerJob;
}
public function set startTime(value:Date):void {
_startTime = value;
}
public function get startTime():Date {
return _startTime;
}
public function set statusMessage(value:String):void {
_statusMessage = value;
}
public function get statusMessage():String {
return _statusMessage;
}
public function set taskId(value:String):void {
_taskId = value;
}
public function get taskId():String {
return _taskId;
}
public function set totalNumberOfTests(value:int):void {
_totalNumberOfTests = value;
}
public function get totalNumberOfTests():int {
return _totalNumberOfTests;
}
}
}
Both classes are generated by my maven build from a corresponding Java Class and the Types do fit together nicely.
Do you have access to the socket class that's reading in all these messages? Trace out the buffer before the deserialisation and you should at least be able to find the class that's giving you hassle.
Failing that, trace out the object after deserialisation and it should be the very first one after the error is thrown.
This is something you'll have to debug on your own, but I have a gut feeling that the problem is because the data being sent by your java DTO is not the same as your AS3 class, even though that you have the RemoteClass metadata saying that it is.
Are you missing a property? or have a property mismatch? That is the most likely cause of your error. I suggest you debug the java side as much as you can and use something like firebug to see the request/response of the server.
I have a Flex Spark dropdownList in which I need to show the Provider FirstName,LastName:
<s:DropDownList id="providerList"
dataProvider="{model.practiceProviderList.practiceProviders}"
labelField="provider.providerName.firstName"/>
But the output shows only [object Object] & [object Object] as there are 2 providers in the DB and does not show the actual values.
The PracticeProviderList.as:
[Bindable]
[RemoteClass(alias="model.PracticeProviderList")]
public class PracticeProviderList extends PracticeProviderListBase {
private var _practiceProviderList:ArrayCollection;
public function get practiceProviders():ArrayCollection
{
return _practiceProviderList;
}
public function set practiceProviders(value:ArrayCollection):void
{
_practiceProviderList = value;
}
The PracticeProvider Object:
public class PracticeProvider {
private var _practiceId:Number;
private var _practiceProviderId:Number;
private var _provider:Provider;
public function set practiceId(value:Number):void {
_practiceId = value;
}
public function get practiceId():Number {
return _practiceId;
}
public function set practiceProviderId(value:Number):void {
_practiceProviderId = value;
}
public function get practiceProviderId():Number {
return _practiceProviderId;
}
public function set provider(value:Provider):void {
_provider = value;
}
public function get provider():Provider {
return _provider;
}
The Provider has providerName:PersonName as one of it's fields & PersonName has firstName:String & lastName:String
I need to show the First Name, Last Name in the dropdownlist. I would appreciate if someone can help in this regard.
Thanks
Harish
The labelField can't concatenate 2 values. Use a labelFunction instead.
If I understand your data model, Something like this:
public function myLabelFunction(item:Object):String{
return item['providerName']['PersonName']['firstName'] + ' ' + item['providerName']['PersonName']['lastName']
}
There are 3 properties (example 1):
[Bindable] public var name:String;
[Bindable] public var email:Number;
[Bindable] public var address:Boolean;
I needed to have 3 helper methods that will be bindable too (example 2):
[Bindable] public var name:String;
[Bindable] public var email:Number;
[Bindable] public var address:Boolean;
public function get nameIsOk():Boolean { return !Strings.isEmpty(name) }
public function get emailIsOk():Boolean { return email == 3 }
public function get addressIsOk():Boolean { return address }
Sure, the code above doesn't work. I made it work by doing this (example 3):
private var _name:String
[Bindable("nameChanged")]
public function get name():String { return _name }
public function set name(v:String):void { _name = v; dispatchEvent(new Event("nameChanged")) }
[Bindable("nameChanged")]
public function get nameIsOk():Boolean { return !Strings.isEmpty(name) }
private var _email:Number
[Bindable("emailChanged")]
public function get email():Number { return _email }
public function set email(v:Number):void { _email = v; dispatchEvent(new Event("emailChanged")) }
[Bindable("emailChanged")]
public function get emailIsOk():Boolean { return email == 3 }
private var _address:Boolean
[Bindable("addressChanged")]
public function get address():Boolean { return _address }
public function set address(v:Boolean):void { _address = v; dispatchEvent(new Event("addressChanged")) }
[Bindable("addressChanged")]
public function get addressIsOk():Boolean { return address }
It does work, but now it is bloated.
Is there a way to reduce this code (example 3) to something smaller (like example 2)?
UPDATE:
Kudos to just_a_dude for nice answer. Here is the final version:
[Bindable] public var name:String;
[Bindable] public var email:Number;
[Bindable] public var address:Boolean;
public function Remixer() {
for each (var f:String in Strings.split("name email address")) {
ChangeWatcher.watch(this, f, onChange)
}
}
private function onChange(e:PropertyChangeEvent):void {
dispatchEvent(new Event(e.property + "Changed"))
}
[Bindable("nameChanged")]
public function get nameIsOk():Boolean { return !Strings.isEmpty(name) }
[Bindable("emailChanged")]
public function get emailIsOk():Boolean { return email == 3 }
[Bindable("addressChanged")]
public function get addressIsOk():Boolean { return address }
Not sure if this is what you're looking for but you can use mx.binding.utils.ChangeWatcher to "watch" for property changes
<?xml version="1.0" encoding="utf-8"?>
<mx:Script>
<![CDATA[
import mx.events.PropertyChangeEvent;
import mx.binding.utils.ChangeWatcher;
[Bindable] public var firstName:String;
[Bindable] public var email:Number;
[Bindable] public var address:Boolean;
private var _watcher:ChangeWatcher;
private function init():void {
ChangeWatcher.watch(this, "firstName", propertyChangeHandler);
ChangeWatcher.watch(this, "email", propertyChangeHandler);
ChangeWatcher.watch(this, "address", propertyChangeHandler);
firstName = "foo";
email = 0;
address = true;
firstName = "bar";
email = 1;
address = false;
}
protected function propertyChangeHandler(event:PropertyChangeEvent):void {
var prop:Object = event.property;
var name:String = prop.toString() + "Changed";
// trace(name); // displays firstNameChanged or emailChanged or addressChanged
dispatchEvent(new Event(name));
}
]]>
</mx:Script>
Let me know if this helps
Cheers
I'm not sure if you need getters, but if not, a nice way to do it, is to just use a single function, and put your bindable strings as arguments.
if you put this in your object:
public function isOk(s:String):Boolean
{
return !Strings.isEmpty(s)
}
You would use it like this:
<mx:CheckBox selected="{yourObject.isOk(yourObject.name)}" />
Generally, if you put a function inside the "{}" with parameters which are bindable, it will be called each time that parameter changes.
I would encapsulate your functionality in a class. Do not repeat yourself :)
I have a simple flex3 project with and mxml file (with some as inside of it) and FMSConnection.as
I have something like this
public class FMSConnection extends NetConnection
{
//this methods is called from the media server
public function Message(message:String):void
{
//how to display (add it to a textarea) this message, when this method is invoked ?
}
}
//in the mxml, after FMSConnection is created:
fmsConn.addEventListener(FMSConnection.MESSAGE_RECEIVED, onMessage);
private function onMessage(e:Event):void
{
fmsConn = FMSConnection(e.target);
textArea.text += fmsConn.lastMessage;
}
//FMSConnection
public class FMSConnection extends NetConnection
{
public static const MESSAGE_RECEIVED:String = "messageReceived";
public var lastMessage:String;
public function Message(message:String):void
{
lastMessage = message;
dispatchEvent(new Event(MESSAGE_RECEIVED));
}
}
Instead of declaring the lastMessage variable, you can dispatch a custom event and store the message in it if you want to.
//MsgEvent.as
public class MsgEvent extends Event
{
public static const MESSAGE_RECEIVED:String = "messageReceived";
public var message:String;
public function MsgEvent(message:String, type:String)
{
super(type);
this.message = message;
}
override public function clone():Event
{
return new MsgEvent(message, type);
}
}
//in the mxml, after FMSConnection is created:
fmsConn.addEventListener(MsgEvent.MESSAGE_RECEIVED, onMessage);
private function onMessage(e:MsgEvent):void
{
textArea.text += e.message;
}
//FMSConnection
public class FMSConnection extends NetConnection
{
public function Message(message:String):void
{
dispatchEvent(new MsgEvent(message, MsgEvent.MESSAGE_RECEIVED));
}
}
Overriding the clone method is not necessary in this case, but it's a good practice to follow while using custom events. If you don't override the clone method, you will get a runtime error while trying to redispatch the custom event from the event handler.
I have a collection of objects and each object throws an event every time its value gets updated. Im trying to capture that event by adding a listener to the arraycollection that holds it (see main class) but its not working. Honestly I'm not sure this is the correct approach.
I'm avoiding using Collection.CHANGE because it fells into an infinite recursion ultimately ends in a stack overflow. Any ideas?
[Bindable]
public class NamesVO {
public var steveList:ArrayCollection; // array of SteveVO objects
public function NamesVO() {
steveList = new ArrayCollection();
}
public function rename():void {
for each(var steve:SteveVO in steveList) {
steve.rename();
}
}
}
[Bindable]
public class SteveVO extends EventDispatcher {
public static const VALUE_CHANGED:String = "VALUE_CHANGED";
public var code:String;
public var name:String;
public var _quantity:Number;
public function SteveVO() {
this.code = "";
this.name = "";
_quantity = 0;
}
public function get quantity():Number {
return _quantity;
}
public function set quantity(quantity:Number):void {
_quantity = quantity;
dispatchEvent(new Event(VALUE_CHANGED));
}
public function rename():void {
name = code + " - " + _quantity;
}
}
Main class:
names = new NamesVO();
names.steveList.addEventListener(SteveVO.VALUE_CHANGED, function():void {
names.rename(); // this anon function is not being executed!!
});
var steve:SteveVO = new SteveVO();
names.steveList.addItem(steve);
// names is bound on a datagrid and uses itemeditor for each SteveVO object
The VALUE_CHANGED event is not dispatched by the steveList array Collection so won't be detected by your listener. You could encapsulate the functionality you want inside the NamesVO class by detecting when an item is added to the array collection and adding a listener to the new steveVO object that dispatches the same event from NamesVO. Then just listen for that event in your main class.
Is there a reason to change all the names when one quantity is changed. Would it be better simply to call rename inside the set function of the steveVO class?
To implement the change:
import flash.events.Event;
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
[Bindable]
public class namesVO
{
public var steveList:ArrayCollection; // array of SteveVO objects
public function namesVO()
{
steveList = new ArrayCollection();
steveList.addEventListener(CollectionEvent.COLLECTION_CHANGE,collChanged);
}
private function collChanged(e:CollectionEvent):void
{
if (e.kind == CollectionEventKind.ADD)
e.items[0].addEventListener(steveVO.VALUE_CHANGED,valueChanged);
}
private function valueChanged(e:Event):void
{
dispatchEvent(new Event(steveVO.VALUE_CHANGED));
}
public function rename():void
{
for each(var steve:steveVO in steveList)
{
steve.rename();
}
}
}
In the main class use:
names = new namesVO();
names.addEventListener(steveVO.VALUE_CHANGED, function():void
{
names.rename();
});
steve = new steveVO();
names.steveList.addItem(steve);
steve.quantity = 12;
Of course this is only an example and only includes the case where one item is added at a time.