To check if an object is empty or not - apache-flex

I want to check in my function if a passed argument of type object is empty or not. Sometimes it is empty but still not null thus I can not rely on null condition. Is there some property like 'length'/'size' for flex objects which I can use here.
Please help.
Thanks in advance.

If you mean if an Object has no properties:
var isEmpty:Boolean = true;
for (var n in obj) { isEmpty = false; break; }

This is some serious hack but you can use:
Object.prototype.isEmpty = function():Boolean {
for(var i in this)
if(i != "isEmpty")
return false
return true
}
var p = {};
trace(p.isEmpty()); // true
var p2 = {a:1}
trace(p2.isEmpty()); // false

You can also try:
ObjectUtil.getClassInfo(obj).properties.length > 0
The good thing about it is that getClassInfo gives you much more info about the object, eg. you get the names of all the properties in the object, which might come in handy.

If object containes some 'text' but as3 doesn't recognize it as a String, convert it to string and check if it's empty.
var checkObject:String = myObject;
if(checkObject == '')
{
trace('object is empty');
}

Depends on what your object is, or rather what you expect it to have. For example if your object is supposed to contain some property called name that you are looking for, you might do
if(objSomeItem == null || objSomeItem.name == null || objSomeItem.name.length == 0)
{
trace("object is empty");
}
or if your object is actually supposed to be something else, like an array you could do
var arySomeItems = objSomeItem as Array;
if(objSomeItem == null || arySomeItems == null || arySomeItems.length == 0)
{
trace("object is empty");
}
You could also use other ways through reflection, such as ObjectUtil.getClassInfo, then enumerate through the properties to check for set values.... this class help:
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
public class ReflectionUtils
{
/** Returns an Array of All Properties of the supplied object */
public static function GetVariableNames(objItem:Object):Array
{
var xmlPropsList:XMLList = describeType(objItem)..variable;
var aryVariables:Array = new Array();
if (xmlPropsList != null)
{
for (var i:int; i < xmlPropsList.length(); i++)
{
aryVariables.push(xmlPropsList[i].#name);
}
}
return aryVariables;
}
/** Returns the Strongly Typed class of the specified library item */
public static function GetClassByName($sLinkageName:String):Class
{
var tObject:Class = getDefinitionByName($sLinkageName) as Class;
return tObject;
}
/** Constructs an instance of the speicified library item */
public static function ConstructClassByName($sLinkageName:String):Object
{
var tObject:Class = GetClassByName($sLinkageName);
//trace("Found Class: " + tMCDefinition);
var objItem:* = new tObject();
return objItem;
}
public static function DumpObject(sItemName:String, objItem:Object):void
{
trace("*********** Object Dump: " + sItemName + " ***************");
for (var sKey:String in objItem)
{
trace(" " + sKey +": " + objItem[sKey]);
}
}
//}
}
Another thing to note is you can use a simple for loop to check through an objects properties, thats what this dumpobject function is doing.

You can directly check it as follow,
var obj:Object = new Object();
if(obj == null)
{
//Do something
}

I stole this from a similar question relating to JS. It requires FP 11+ or a JSON.as library.
function isEmptyObject(obj){
return JSON.stringify(obj) === '{}';
}

can use use the hasProperty method to check for length
var i:int = myObject.hasProperty("length") ? myObject.length: 0;

Related

Flex DatagridColumn LabelFunction Additonal Parameters

I have a datagridcolumn where a labelFunction is defined:
private function myLabelFunction(item:Object, column:DataGridColumn):String
{
var returnVal:String;
var nm:NumericFormatter;
nm.decimalSeparatorTo = ".";
nm.precision = additionalParameter;
returnVal = nmTwoDecimals.format(item[column.dataField]);
if (returnVal == '0.00')
{
returnVal = '';
}
return returnVal;
}
Would it be possible to add an additional parameter so that I could pass the property values for the formatter which I intend to use?
Like for example:
private function myLabelFunction(item:Object, column:DataGridColumn, precisionParam:int):String
{
var returnVal:String;
var nm:NumericFormatter;
nm.decimalSeparatorTo = ".";
nm.precision = precisionParam;
returnVal = nmTwoDecimals.format(item[column.dataField]);
if (returnVal == '0.00')
{
returnVal = '';
}
return returnVal;
}
Thanks.
You would have to extend the DataGridColumn class. After creating your new class simply override the existing itemToLabel function:
public function itemToLabel(data:Object):String
{
if (!data)
return " ";
if (labelFunction != null)
return labelFunction(data, this);
if (owner.labelFunction != null)
return owner.labelFunction(data, this);
if (typeof(data) == "object" || typeof(data) == "xml")
{
try
{
if ( !hasComplexFieldName )
data = data[dataField];
else
data = deriveComplexColumnData( data );
}
catch(e:Error)
{
data = null;
}
}
if (data is String)
return String(data);
try
{
return data.toString();
}
catch(e:Error)
{
}
return " ";
}
The line 'return labelFunction(data, this);' is what calls the labelFunction (will also check the owner datagrid for a labelfunction). 'data' in 'itemToLabel' is your object. You could either include the precision value you want in the object or hard code it in the extended class (or inject, or singleton, class var, whatever you like).
At this point you can go ahead and pass it as a third parameter to your new labelFunction.
In your label function for the datagrid column, you can access the assigned data field by using the dataField property, see the following syntax below:
"supposing your label function is called formatNumbers_LabelFunction"
private function formatNumbers_LabelFunction(item:Object, column:DataGridColumn):String{
//Write any code logic you want to apply on your data field ;)
//In this example, I'm using a number formatter to edit numbers
return myCustomNumberFormatter.format(item[column.dataField]);
}
This way, you can use a generic label function to handle some unified operations on your displayed data
And besides that, you can also access to any data field that is in the data provider by just calling its name like this:
item.YourFieldName
where item is the firs parameter [of type Object] in your label function method
This would work:
<DataGridColumn labelFunction="{function(item:Object, column:DataGridColumn):String { return anotherLabelFunction(item,column,2) }}" />
// Elsewhere ...
function anotherLabelFunction(item:Object,column:DataGridColumn,precision:int):String
{
// Do your business
}

flex select value from Combo

My goal is to create a generic function that selects a value in a combobox accoring to a value.
(My comoBox holds arrayCollection as dataProvider.)
The difficulty is infact to get a propertyname in runtime mode
public function selectComboByLabel(combo:ComboBox , propetryName:String, value:String):void {
var dp:ArrayCollection = combo.dataProvider as ArrayCollection;
for (var i:int=0;i<dp.length;i++) {
if (dp.getItemAt(i).propertyName==value) {
combo.selectedIndex = i;
return;
}
}
}
the line if (dp.getItemAt(i).propertyName==value)
is of course incorrect.
It should be arther something like: dp.getItemAt(i).getPropertyByName(propertyName)
Any clue on how to that ?
Don't use Object Property notation. Do this:
dp.getItemAt(i)[propertyName]
In addition to what Flextras said, you could also redo your for loop to make it easier to read:
for each(var item:Object in dp) {
if(item[propertyName] == value) {
combo.selectedItem = item;
return;
}
}

More efficient way to remove an element from an array in Actionscript 3

I have an array of objects. Each object has a property called name. I want to efficiently remove an object with a particular name from the array. Is this the BEST way?
private function RemoveSpoke(Name:String):void {
var Temp:Array=new Array;
for each (var S:Object in Spokes) {
if (S.Name!=Name) {
Temp.push(S);
}
}
Spokes=Temp;
}
If you are willing to spend some memory on a lookup table this will be pretty fast:
private function remove( data:Array, objectTable:Object, name:String):void {
var index:int = data.indexOf( objectTable[name] );
objectTable[name] = null;
data.splice( index, 1 );
}
The test for this looks like this:
private function test():void{
var lookup:Object = {};
var Spokes:Array = [];
for ( var i:int = 0; i < 1000; i++ )
{
var obj:Object = { name: (Math.random()*0xffffff).toString(16), someOtherProperty:"blah" };
if ( lookup[ obj.name ] == null )
{
lookup[ obj.name ] = obj;
Spokes.push( obj );
}
}
var t:int = getTimer();
for ( var i:int = 0; i < 500; i++ )
{
var test:Object = Spokes[int(Math.random()*Spokes.length)];
remove(Spokes,lookup,test.name)
}
trace( getTimer() - t );
}
myArray.splice(myArray.indexOf(myInstance), 1);
The fastest way will be this:
function remove(array: Array, name: String): void {
var n: int = array.length
while(--n > -1) {
if(name == array[n].name) {
array.splice(n, 1)
return
}
}
}
remove([{name: "hi"}], "hi")
You can also remove the return statement if you want to get rid of all alements that match the given predicate.
I don't have data to back it up but my guess is that array.filter might be the fastest.
In general you should prefer the old for-loop over "for each" and "for each in" and use Vector if your elements are of the same type. If performance is really important you should consider using a linked list.
Check out Grant Skinners slides http://gskinner.com/talks/quick/ and Jackson Dunstan's Blog for more infos about optimization.
If you don't mind using the ArrayCollection, which is a wrapper for the Array class, you could do something like this:
private function RemoveSpoke(Name:String, Spokes:Array):Array{
var ac:ArrayCollection = new ArrayCollection(Spokes);
for (var i:int=0, imax:int=ac.length; i<imax; i++) {
if (Spokes[i].hasOwnProperty("Name") && Spokes[i].Name === Name) {
ac.removeItemAt(i);
return ac.source;
}
}
return ac.source;
}
You could also use ArrayCollection with a filterFunction to get a view into the same Array object
Perhaps this technique (optimized splice method by CJ's) will further improve the one proposed by Quasimondo:
http://cjcat.blogspot.com/2010/05/stardust-v11-with-fast-array-splicing_21.html
Here's an efficient function in terms of reusability, allowing you to do more than remove the element. It returns the index, or -1 if not found.
function searchByProp(arr:Array, prop:String, value:Object): int
{
var item:Object;
var n: int = arr.length;
for(var i:int=n;i>0;i--)
{
item = arr[i-1];
if(item.hasOwnProperty(prop))
if( value == item[prop] )
return i-1;
}
return -1;
}

How do I dynamically instantiate a class, and set a property at runtime in Flex 3?

Using org.as3commons.reflect I can look-up the class name, and instantiate a class at runtime. I also have (non-working) code which invokes a method. However, I really want to set a property value. I'm not sure if properties are realized as methods internally in Flex.
I have a Metadata class which stores 3 pieces of information: name, value, and type (all are strings). I want to be able to loop through an Array of Metadata objects and set the corresponding properties on the instantiated class.
package com.acme.reporting.builders
{
import com.acme.reporting.model.Metadata;
import mx.core.UIComponent;
import org.as3commons.reflect.ClassUtils;
import org.as3commons.reflect.MethodInvoker;
public class UIComponentBuilder implements IUIComponentBuilder
{
public function build(metadata:Array):UIComponent
{
var typeClass:Class = ClassUtils.forName(getTypeName(metadata));
var result:* = ClassUtils.newInstance(typeClass);
for each (var m:Metadata in metadata)
{
if (m.name == "type")
continue;
// Attempting to invoke as method,
// would really like the property though
var methodInvoker:MethodInvoker = new MethodInvoker();
methodInvoker.target = result;
methodInvoker.method = m.name;
methodInvoker.arguments = [m.value];
var returnValue:* = methodInvoker.invoke(); // Fails!
}
return result;
}
private static function getTypeName(metadata:Array):String
{
if (metadata == null || metadata.length == 0)
throw new ArgumentError("metadata is null or empty");
var typeName:String;
// Type is usually the first entry
if (metadata.length > 1 && metadata[0] != null && metadata[0].name == "type")
{
typeName = metadata[0].value;
}
else
{
var typeMetadata:Array = metadata.filter(
function(element:*, index:int, arr:Array):Boolean
{
return element.name == "type";
}
);
if (typeMetadata == null || typeMetadata.length != 1)
throw new ArgumentError("type entry not found in metadata");
typeName = typeMetadata[0].value;
}
if (typeName == null || typeName.length == 0)
throw new Error("typeName is null or blank");
return typeName;
}
}
}
Here's some usage code:
var metadata:Array = new Array();
metadata[0] = new Metadata("type", "mx.controls.Text", null);
metadata[1] = new Metadata("text", "Hello World!", null);
metadata[2] = new Metadata("x", "77", null);
metadata[3] = new Metadata("y", "593", null);
this.addChild(new UIComponentBuilder().build(metadata));
I realize that I have to declare a dummy variable of the type I was to instantiate, or use the -inculde compiler directive. An unfortunate drawback of Flex.
Also, right now there's code to account for typecasting the value to it's specified type.
Dynamic execution in AS3 is much simpler than in other languages. This code:
var methodInvoker:MethodInvoker = new MethodInvoker();
methodInvoker.target = result;
methodInvoker.method = m.name;
methodInvoker.arguments = [m.value];
var returnValue:* = methodInvoker.invoke(); // Fails!
can be simplified to this:
var returnValue:* = result[method](m.value);
EDIT:
Since it's a property, it would be done like this:
result[method] = m.value;
and there is no return value (well, you can call the getter again but it should just return m.value unless the setter/getter do something funky.

Access the function object (closure) of a setter

Assume I have the following class:
class Example
{
function set something(value:String):void
{
trace("set something");
}
function doSomething():void
{
trace("something");
}
}
I can access the functions as objects like this:
var example:Example = new Example();
var asdf:Function = example.doSomething;
// this also works - example["doSomething"];
asdf(); // this trace: "something"
You do this all the time with events, for example. So, my big question is: Is there any way to get a handle on the setter? Is there some crazy function on Object or somewhere that I don't know about (please say yes :)
I want something like the following
var example:Example = new Example();
// the following won't work, because example.something is a string
var asdf:Function = example.something;
asdf("a value"); // this trace: "something"
The statement var asdf:Function = example.something; won't work because compiler treats example.something as a getter and returns string (or throws a write-only error if the getter is not implemented).
But since something is a property, you can do something like:
example["something"] = "a value"; //will trace 'set something'
//or
var property:String = "something";
example[property] = "some value"; //will trace 'set something'
You may try this:
class Example{
function set something(value:String):void{
trace("set something");
}
function doSomething():void{
trace("something");
}
}
class AnotherClass{
function callOtherClassFunction(funcObj:Obj):void{
if (funcObj.type == "method") {
funcObj.func.apply();
}
else if (funcObj.type == "setter") {
funcObj.obj[funcObj.func] = "something";
}
else if (funcObj.type == "getter") {
trace(funcObj.obj[funcObj.func]);
}
}
}
class Test{
function Test():void{
var e:Example = new Example();
var a:AnotherClass = new AnotherClass();
a.callOtherClassFunction({obj:e, type:"setter", func:"something"});
a.callOtherClassFunction({obj:e, type:"method", func:e.doSomething});
}
}

Resources