I have a list of check boxes that when selected the getEventName method should reurn the key that matches the label. For example if the label is "NEW", the key should be returned when map[key] = "new". These have been defined in the LABEL_EVENTTYPE function below. It is always returning an empty string and can't seem to figure out why.
public static const LABEL_EVENTTYPE_MAP:Object = {
"CANCEL":["cancelled","expired", "doneForDay"],
"NEW":["new"],
"TRADE":["trade"],
"AMEND":["replaced"],
}
private function getEventName(label:String):String{
var map:Object = ReplayConstants.LABEL_EVENTTYPE_MAP;
for each(var key:String in map){
if (map[key] == label){
return key;
}
}
return "";
}
Iterating through object properties requires for..in loop instead of for each.. in
for (var key:String in map){
if (map[key] == label){
return key;
}
}
Also take into account, that objects in your map are arrays, that's why your comparison map[key] == label will always return false.
Related
I try to sort an arrayCollection with this Sort:
private function sortArray(questions:ArrayCollection):void
{
questions.sort = new Sort();
questions.sort.fields = [new SortField("rank")];
questions.sort.compareFunction = rankFunction;
questions.refresh();
}
private function rankFunction(a:int, b:int, array:Array = null):int
{
if(a == b)
{
return 0;
}
if(a>b)
{
return 1;
}
else
{
return -1;
}
}
There are 23 Objects and all have the rank = 0
I expected that nothing will be changed but after the refresh the items at postion 0 and 11 of the ArrayCollection swapped their position.
In the rankFunction, there is always returned 0.
Can anyone tell me what is going wrong here?
ASDoc says that compare function should have following signature:
function [name](a:Object, b:Object, fields:Array = null):int
and that the fields array specifies the object fields.
So Sort doesn't extract field values for you. You should do it yourself.
Concerning your question, it seems that AS3 implicitly converts Objects to ints invoking rankFunction. If so items are compared by some internal code that somehow corresponds to the order of items creation.
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;
}
}
This is kinda related to my other question: flex dictionary bug?
The HashMap has a method getValues() which returns an array of values:
protected var map:Dictionary = null;
public function HashMap(useWeakReferences:Boolean = true)
{
map = new Dictionary( useWeakReferences );
}
public function getValues() : Array
{
var values:Array = [];
for (var key:* in map)
{
values.push( map[key] );
}
return values;
}
In my unit test class, I have:
private var map:IMap;
[Before]
public function setUp():void
{
map = new HashMap();
map.put("a", "value A");
map.put("b", "value B");
map.put("c", "value C");
map.put("x", "value X");
map.put("y", "value Y");
map.put("z", "value Z");
}
[Test]
public function testGetValues():void
{
assertEquals(map.getValues(), /*what should I put here*/);
}
the loop for (var key:* in map) iterates the keys of the dictionary map, but it seems its implementation does it in some random way. What is the best way to write a test since I don't know what the array returned by getValues method will contain?
I thought I could do it by calling the sort method, and compare the values, is there a better way to do it?
assertEquals(map.getValues().sort(), "value A,value B,value C,value X,value Y,value Z");
Yes. If I understand your problem properly, you are trying to see if the inserted values are there in the mapValues array you are getting back. You can use the indexOf function on the array and check something like
//start a loop to go through the arrays.
if( mapValues.indexOf("value A") >= 0 )
{
continue;
}
Hope this helps!
I have a form with checkboxes, on form submit.
If one checked, it comes in as string, if multiple checked, it comes in as an json array.
How do I get the object as an array?
TypeReference<HashMap> typeRef = new TypeReference<HashMap>(){};
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory);
HashMap<String, Object> bean = mapper.readValue(formBean, typeRef);
bean.get("somevarible") < I want to get this as array regardless how many boxes checked
Thanks
EDIT
I am using this function, how can I update it?
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
I had a similar issue deserializing json (aka "the checkbox problem"). My (ugly) work-around was to use #JsonAnySetter to manually do the "right" thing with the incoming (string/list) value.
// q is always just a string.
#JsonProperty("q")
private String query;
// fq could be a string or a list.
private List<String> filterQuery;
// (get/set/add omitted)
// XXX - this is an evil hack to support 1 or >1 fq values
// there must be a better way to support 2-way deserialization
#JsonAnySetter
void addEntry(String key, Object value)
{
if ("fq".equals(key))
{
if (value == null)
{
// can this even happen?
} else if (String.class.equals(value.getClass()))
{
addFilterQuery((String) value);
} else
{
setFilterQuery((List<String>) value);
}
}
}
The task was meant to be quite simple: I needed to initialize variable with new keyword dynamically, depending on it's type. For example:
public var object:Sprite;
...
object = new Sprite();
In this case type is Sprite, but it could be anything and a method which actually instantiates it with new, doesn't know with what type it was declared. Of course I could store type (or class name) in string variable and instantiate object with it. But I just wonder if I could get that type info from the object itself, 'cause it's declared in a class and logically thinking it's type info might be stored somewhere and be retrievable.
Yes, you can, but the variable must be public (or have accessor methods), and you need its name as a String:
Use describeType() to get an XML Description of your class, then get accessors and variables as XMLList, iterate until you find your variable's name, and get the class by calling getDefinitionByName(). Here's an example:
var className : String = "";
var type:XML = describeType (this);
var variables:XMLList = type..variable;
for each (var variable:XML in variables) {
if (variable.#name == myVariableName) {
className = variable.#type;
break;
}
}
if (className == "") {
var accessors:XMLList = type..accessor;
for each (var accessor:XML in accessors) {
if (accessor.#name == myVariableName) {
className = accessor.#type;
break;
}
}
}
if (className=="") {
trace ("no such variable");
return;
}
var ClassReference : Class = getDefinitionByName( className.replace ("::", ".") ) as Class;
myVariable = new ClassReference( );
I can't figure out how to "reply" to an answer, otherwise I would add this to the current top answer.
If you have a list of known types that the object could be, you could test against those types using typeof.
switch(typeof unknownVar)
{
case typeof Function:
unknownVar = new Function();
break;
case typeof String:
unknownVar = "Bruce Lee";
break;
case typeof Number:
unknownVar = 3.14;
break;
default:
trace(typeof unknownVar); // This is not normally helpful...
}
In short no, you can't get the type of an uninitialised variable.
Sounds like this is kind of a factory pattern implementation. Your best bet is to pass a reference of the Class to the method
method:
public function create(class:Class) : void
{
return new class();
}
calling code:
public var object:Sprite;
...
object = createObject(Sprite)