Action Script 3 NumericStepper validation for empty value - actionscript-3

I have a simple NumericStepper which looks like this:
<mx:NumericStepper id="nsPort"
minimum="0"
maximum="65535"
stepSize="1"
value="{PORT_DEFAULT}"/>
I wrote a Validator for it (which doesn't work as I expect):
<mx:NumberValidator
required="true"
source="{nsPort}"
property="value"/>
However, every time I don't enter anything into NumericStepper it passes zero, not NULL or something else, which is...well...a valid value. I suspect that this is done on purpose. So, how can I make blank value at NumbericStepper to be invalid?
Please note that I'm restricted to a ver.3 of Action Script.

Example code base from https://flexscript.wordpress.com/2008/09/22/flex-creating-custom-validators/ with a little modification:
package flexScript
{
import mx.validators.ValidationResult;
import mx.validators.Validator;
//Class should extend mx.validators.Validator
public class NumericStepperValidator extends Validator {
public function NumericStepperValidator() {
// Call base class constructor.
super();
}
// Class should override the doValidation() method.
//doValidation method should accept an Object type parameter
override protected function doValidation(value:Object):Array {
// create an array to return.
var ValidatorResults:Array = new Array();
// Call base class doValidation().
ValidatorResults = super.doValidation(value);
// Return if there are errors.
if (ValidatorResults.length > 0)
return ValidatorResults;
if (String(value).length == 0)
return ValidatorResults;
if ( value == 0)//as your required.
return ValidatorResults;
var RegPattern:RegExp = /\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/; //Change to your customize regExpression
var a:Array = RegPattern.exec(String(value));
if (a == null)
{
ValidatorResults.push(new ValidationResult(true, null, "NumbericStepper Error","You must enter an Number"));
return ValidatorResults;
}
return ValidatorResults;
}
}
}
<flexScript:NumbericStepperValidator source="{{nsPort}}" property="number"/>

Related

How can I define a boolean function argument to be optional?

In ActionScript 3, is there a clean way to define a function that accepts an optional boolean argument ? As you may know, this is invalid :
public function test(param:Boolean = null):void {
trace(param);
}
This triggers the following error: VerifyError: Error #1102: Illegal default value for type Boolean. Since, Boolean is a primitive, I guess it makes sense that it cannot be set to null. The only workaround I found is to cast the parameter to an object :
public function test(param:Object = null):void {
trace(Boolean(param));
}
However, this does not feel very clean, particularly if you are developing libraries. ASDoc will generate API documentation that says the expected parameter is an Object whereas what is really needed is a Boolean.
Is there a better approach ?
When you say optional, I assume that you mean if there isn't a value supplied then something different should happen compared to if you had a default value of true or false.
You could make your own object to handle the three states that you need and maintain code readability by using a class like this:
public class Condition
{
private var _value:* = null;
public function Condition(initial:* = null)
{
value = initial;
}
public function set value(n:*):void
{
if(_value === null || _value === false || _value === true)
{
_value = n;
}
}
public function get value():*{ return _value; }
}
And then your function could be:
function test(param:Condition = null):void
{
if(param && param.value != null)
{
trace(param.value);
}
}
test( new Condition() );
test( new Condition(true) );
As you said Boolean can not be set to null value.
Therefore, you should specify a default value that is either true or false.
public function test(param:Boolean = false):void {
trace(param);
}
But because you need the third case where nothing is set, one option could be to accept any Object but throw an exception if it is not null and not a boolean:
public function test(param:* = null):void
{
if (param != null)
{
if ((param == true) || (param == false))
{
trace(Boolean(param).toString());
}
else
{
throw new CustomError("param should be a boolean");
}
}
else
{
// Do nothing
}
}
Note that this solution also accept objects or primitives that can be compared to true or false such as 0, 1, or [].
From the good suggestions and discussion above I think that, in a library scenario and for simplicity's sake, the best way remains to type the parameter as Object with a default value of null but to request a Boolean in the API documentation :
/**
* #param param Boolean object or null
*/
public function test(param:Object = null):void {
trace(Boolean(param));
}
This allow the user of the library to pass a either a Boolean or nothing at all. Thanks everyone.
There was a tonne of discussion on my previous answer, but this is the correct way to have a function that accepts one of three states. My previous answer attempted to retain the use of a Boolean value like you were requesting, but that is not the right way to go about it.
Create a class that defines three values:
class State
{
public static const EMPTY:int = -1;
public static const FALSE:int = 0;
public static const TRUE:int = 1;
}
Your function will accept an int (the type of each of the three properties within your State class). It will deal with the three possible values. You can use concise commenting to notify the developer of what thee values the function is expecting, referencing the State class. The default value can be -1 aka State.EMPTY.
/**
* Function description.
* #param state One of three states, defined by State.
*/
function test(state:int = -1):void
{
switch(state)
{
case State.EMPTY:
// No value given.
break;
case State.TRUE:
// True.
//
break;
case State.FALSE:
// False.
//
break;
default:
throw new ArgumentError("Unsupported value for test()");
break;
}
}

ActionScript - Determine If Value is Class Constant

i'd like to throw an argument error if a particular function doesn't work without a passed value that also happens to be a public constant of the class containing the function.
is there anyway to determine if a class owns a public constant instead of having to iterate thru all of them?
something like this:
public static const HALIFAX:String = "halifax";
public static const MONTREAL:String = "montreal";
public static const TORONTO:String = "toronto";
private var cityProperty:String;
public function set city(value:String):void
{
if (!this.hasConstant(value))
throw new ArgumentError("set city value is not applicable.");
cityProperty = value;
}
public function get city():Strig
{
return cityProperty;
}
currently, for this functionality i have to write the city setter function like this:
public function set city(value:String):void
{
if (value != HALIFAX && value != MONTREAL && value != TORONTO)
throw new ArgumentError("set city value is not applicable.");
cityProperty = value;
}
is this the only way to accomplish this task?
Yes, if you use reflections:
private var type:Class;
private var description:XML;
private function hasConstant (str : String ) : Boolean
{
if (description == null)
{
type = getDefinitionByName (getQualifiedClassName (this)) as Class;
description = describeType (type);
}
for each ( var constant:XML in description.constant)
{
if (type[constant.#name] == str) return true;
}
return false;
}
Note that for this to work, all constants must always be String objects declared public static const.
I was looking for an answer to this question myself and found it annoying that hasOwnProperty() did not work for static properties. Turns out though, that if you cast your class to a Class object, it does work.
Here's an example:
public final class DisplayMode
{
public static const one: String = "one";
public static const two: String = "two";
public static const three: String = "three";
public static function isValid(aDisplayMode: String): Boolean {
return Class(DisplayMode).hasOwnProperty(aDisplayMode);
}
}
I owe this solution to jimmy5804 from this discussion, so hats off to him.
You should be able to use bracket notation to do this. For example:
var foo:Sprite = new Sprite();
foo.rotation = 20;
trace( foo["x"], foo["rotation"]); // traces "0 20"
or more specific to your case:
var bar:String = "rotation";
trace( foo[bar] ); // traces "20"
The only thing you have to look out for here, is that the bracket accessor will throw a ReferenceError if you ask for an object property that isn't there, such as:
trace ( foo["cat"] ); // throws ReferenceError
But it will not throw if you are asking for a static property:
trace ( Sprite["cat"] ); // traces "undefined"
So in your case you might try:
if ( this[value] == undefined ) {
throw new ArgumentError("set city value is not applicable.");
}
EDIT:
Sorry, I was confusing the const's names with their values.
For this to work on your problem you would have to make the String value the same as the const's name, so for example:
public static const HALIFAX:String = "HALIFAX";
then you could use the query as described above and it would give you the desired result.

Get all static variables in a class

I have this ObjectType class which is a class to help me do something like this:
object.type = ObjectType.TWO
//ObjectType.as
package
{
public class ObjectType
{
public static var ONE:String = "one";
public static var TWO:String = "two";
public static var THREE:String = "three";
public function ObjectType()
{
}
}
}
Let's suppose I'm creating a new class and I need a property named type. In that property set function I want to make sure that it's value is one of the ObjectType variables. How can I achieve this?
public function set type(value:String):void
{
for (var o:Object in ObjectType) {
if (value == o)
this._type = value;
} else {
//error
}
}
}
Not performance aware but without modifying anything you can use describeType function to check the static field and get the value back:
function valueInClass(clazz:Class, value:*):Boolean {
return describeType(clazz).variable.(clazz[#name.toString()] == value).length() != 0
}
public function set type(value:String):void
{
if (valueInClass(ObjectType, value)) {
this._type = value;
} else {
//error
}
}
I suppose the second code example you presented doesn't work...
I think it is because you're using the for in loop a little bit wrong.
for (var blah:String in somewhere){
// blah represents a KEY of the somewhere object
// to get the value of this key, use:
var theValue = somewhere[blah];
}
It's the for each loop that loops through the values. But for now I'll use the for in.
Also, it's not in ObjectType, but rather in the class' prototype, that is in ObjectType.prototype.
So, to fix this:
for (var o:* in ObjectType.prototype) {
if (value == ObjectType.prototype[o])
this._type = value;
} else {
//error
}
}
You can solve this using reflection.
A similar question was asked just a few days ago, you should be able to use the same solution, found here.
It should be noted that while the the accepted answer is right, it's also really slow. Not something that you want to do a lot. There are three simpler solutions.
One: Check the value itself:
public function set type(value:String):void
{
if( value != ObjectType.ONE && value != ObjectType.TWO && value != ObjectType.THREE )
return;
}
Obviously, the more constants you have the check the harder this becomes.
Two: Use ints as your constants
Change your ObjectType class to use ints:
public class ObjectType
{
public static var NONE:int = 0;
public static var ONE:int = 1;
public static var TWO:int = 2;
public static var THREE:int = 3;
public static var TOTAL:int = 4;
}
Notice the NONE and TOTAL in there? This makes it easy to check if your value is in the right range:
public function set type(value:int):void
{
if( value <= ObjectType.NONE || value >= ObjectType.TOTAL )
return;
}
You can add more values as needed and you just need to update TOTAL and it'll still work. This needs each value to be in order though.
Three: Use Enums
While Flash has no in-build class for enums, there's a lot of solutions available. Check our the Enum class from Scott Bilas: http://scottbilas.com/blog/ultimate-as3-fake-enums/
Using this as your base class your ObjectType class becomes:
public final class ObjectType extends Enum
{
{ initEnum( ObjectType ); } // static ctor
public static const ONE:ObjectType = new ObjectType;
public static const TWO:ObjectType = new ObjectType;
public static const THREE:ObjectType = new ObjectType;
}
And your check now becomes:
public function set type(value:ObjectType):void
{
...
}
Here, your setter now becomes type safe and will throw errors if anything other than an ObjectType is used.
It turns out that if using an ENUM type of check you should check for the constants property, not variables as showin in the example here:
ActionScript - Determine If Value is Class Constant

Array.filter to dynamically test values

this is from Adobe docs:
package {
import flash.display.Sprite;
public class Array_filter extends Sprite {
public function Array_filter() {
var employees:Array = new Array();
employees.push({name:"Employee 1", manager:false});
employees.push({name:"Employee 2", manager:true});
employees.push({name:"Employee 3", manager:false});
trace("Employees:");
employees.forEach(traceEmployee);
var managers:Array = employees.filter(isManager);
trace("Managers:");
managers.forEach(traceEmployee);
}
private function isManager(element:*, index:int, arr:Array):Boolean {
return (element.manager == true);
}
private function traceEmployee(element:*, index:int, arr:Array):void {
trace("\t" + element.name + ((element.manager) ? " (manager)" : ""));
}
}
}
The problem is the Array class filter method. It works this way: you pass a function as an argument of filter and an array is returned based on the function you pass. The problem is that it seems you can't add any other parameter. So, if you must create (for example inside a for loop) 4 arrays from the same array and you want to use the same function, you can only test against a property of the class you must previously set to the value you want to test.
Is there any other way to add that parameter?
When filtering by a variable object properties in an array, I wrapped the filtering into another function:
protected function FilterByProperty(input_array:Array, extra_testing:Object):Array
{
function FilterFunction(element:Object, index:int, array:Array):Boolean
{
return element.property == extra_testing; // Arbitrary test
}
return input_array.filter(FilterFunction);
}
var filtered_array:Array = FilterByProperty(unfiltered_array, test_property);
You can use second parameter of filter() method to pass data to filter function. It will be avaliable as "this" variable. To do that first parameter must be a closure, not a class method.
var array:Array = [...];
var params:Object = {"param1": value1, "param2": value2};
var filterFunction:Function = function(item:*, index:int, array:Array):Boolean {
var param1 = this["param1"];
var param2 = this["param2"];
};
array.filter(filterFunction, params);
You want to use something like Delegates or function binding, or closures. Depending on your coding and terminology preferences. The idea behind all of them is that you create a dynamic function wrapper for the core "filter" function. That wrapper will have access to extra parameters that you pass. So, the first time you call it, you might go:
a.filter(Delegate.create(myFunc, param1));
and the next time:
a.filter(Delegate.create(myFunc, param2));
and you function would have something like this:
private function myFunc(item:*, index:Number, a:Array, param:Object=null):Boolean{}
A quick an dirty method is to just pass an inline function like this:
a.filter(
function(item:*, index:Number, a:Array):Boolean {
return myFunc(item,index,a,param1);
}
);
where param1 is passed using the closure created by the function definition.

Trying to understand the AsyncToken in Flex/Actionscript

I am trying to understand the way the AsyncToken works in actionscript. How can I call a remote service and ensure that a specific parameter is available in the result or fault event functions? I think it is the async functionality I want to use.
The following code will hopefully explain what I am trying to do. Feel free to modify the code block as your explanation.
Thanks.
public function testSerivceCall(data:Object, callBackCommand:String):void
{
// Assume callBackCommand == "FOO";
// How can I pass in callBackCommand as a parameter to the result or fault events?
// How do I create an async token here?
var remoteObject:RemoteObject;
remoteObject = new RemoteObject();
remoteObject.destination = "zend";
remoteObject.source = "MyService";
remoteObject.endpoint = "http://example.com/service";
remoteObject.test.addEventListener(ResultEvent.RESULT, _handleTestResult);
remoteObject.test.addEventListener(FaultEvent.FAULT, _handleTestFault);
remoteObject.test(data);
}
private function _handleTestResult( event:ResultEvent ) : void
{
// How do I get the async token value?
// How can I get the value of callBackCommand in this code block?
if (callBackCommand == "FOO")
{
// do something related to "FOO"
}
else
{
// do something else with the result event
}
}
private function _handleTestFault( event:FaultEvent ) : void
{
// How do I get the async token value?
// How can I get the value of callBackCommand in this code block?
}
An edit to make this question more clear:
Assume I make the following method call somewhere in my code:
testSerivceCall(personObject, "LoginCommand");
How do I get access to the actual string "LoginCommand" inside the _handleTestResult function block?
The reason I want to do this is because I want to dynamically call back certain functions and hand off the result data to specific commands that I know ahead of time when I am making the service call.
I am just having a time grokking the AsyncToken syntax and functionality.
I did not even need closures. I added a class as below which I called externally.
The call was like this:
public class MyClass
{
...
var adminServerRO:AdminServerRO = new AdminServerRO();
adminServerRO.testSerivceCall("FOO",cptyId);
}
public class AdminServerRO
{
private function extResult( event:ResultEvent, token:Object ) : void
{
//the token is now accessed from the paremeter
var tmp:String = "in here";
}
private function extFault( event:FaultEvent ) : void
{
var tmp:String = "in here";
}
public function testSerivceCall(callBackCommand:String, cptyId:String):void
{
var remoteObject:RemoteObject = new RemoteObject();
remoteObject.destination = "adminServer";
var token:AsyncToken = remoteObject.getCounterpartyLimitMonitorItemNode(cptyId);
token.addResponder(new AsyncResponder(extResult,extFault,cptyId));
}
}
While the accepted answer will accomplish what the original submitter wants it does not actually answer the question which was asked. An AsyncToken is created as a result of a remote method call and is accessible from the ResultEvent. Since AsyncToken is a dynamic class you can add whatever property to it that you want. The code below should demonstrate this:
public function testSerivceCall(data:Object, callBackCommand:String):void
{
var remoteObject:RemoteObject;
remoteObject = new RemoteObject();
remoteObject.destination = "zend";
remoteObject.source = "MyService";
remoteObject.endpoint = "http://example.com/service";
remoteObject.test.addEventListener(ResultEvent.RESULT, _handleTestResult);
remoteObject.test.addEventListener(FaultEvent.FAULT, _handleTestFault);
var token:AsyncToken = remoteObject.test(data);
token.callBackCommand = callBackCommand;
}
private function _handleTestResult( event:ResultEvent ) : void
{
if (event.token.callBackCommand == "FOO")
{
// do something related to "FOO"
}
else
{
// do something else with the result event
}
}
private function _handleTestFault( event:FaultEvent ) : void
{
//event.token.callBackCommand should be populated here too
}
If you want to access the properties used during the remote call (parameters to the call and/or AsycToken), you can make use of closures. Just define the result event handler inside the calling method as a closure. It can then access any variable in the calling function.
public function testSerivceCall(data:Object, callBackCommand:String):void
{
var _handleTestResult:Function = function( event:ResultEvent ) : void
{
// token is visible here now
if (callBackCommand == "FOO")
{
// do something related to "FOO"
}
else
{
// do something else with the result event
}
}
var remoteObject:RemoteObject;
remoteObject = new RemoteObject();
remoteObject.destination = "zend";
remoteObject.source = "MyService";
remoteObject.endpoint = "http://example.com/service";
remoteObject.test.addEventListener(ResultEvent.RESULT, _handleTestResult);
remoteObject.test.addEventListener(FaultEvent.FAULT, _handleTestFault);
var token = remoteObject.test(data);
}
If I'm reading your question correctly, you're trying to figure out how to access the actual data returned by the ResultEvent ?
If so, assuming you've made the call correctly and you've gotten data back in a format you're expecting:
private function _handleTestResult( event:ResultEvent ) : void
{
// you get the result from the result property on the event object
// edit: assuming the class Person exists with a property called name
// which has the value "John"
var person : Person = event.result as Person;
if (person.name == "John")
{
Alert.show("John: " + person.name);
}
else
{
Alert.show("Not John: " + person.name);
}
}
private function _handleTestFault( event:FaultEvent ) : void
{
// Maybe you know the type of the returned fault
var expectedFault : Object = event.fault as MyPredefinedType
if (expectedFault.myPredefinedTypesPredefinedMethod() == "BAR")
{
// something here
}
}
The ResultEvent has a property called result which will hold an instance of the object returned by the result (it might be the output of an XML file if using a web service, or a serialized object if using AMF, for example). This is what you want to access. Similarly, FaultEvent has a fault property that returns the fault information.
Edit: Changed code in _handleTestResult() in response to Gordon Potter's comment.