In ActionScript 3, tracing all properties of a value object - actionscript-3

I have a number of value objects and I want to be able to create a function within it to trace out the properties and the values without specifying them directly. It will allow me to use the same code in all value objects as opposed to referring to variables within the value object. Ideally, I would like to replace the code in blogURLVars with this code.
Here's a sample value object
package items {
public class Blog {
private var _itemID:uint;
private var _blogTitle:String;
private var _blogText:String;
private var _blogCreated:String;
private var _blogCategory:String;
private var _blogFrontpage:Boolean;
public function Blog (itemID:uint,blogTitle:String,blogText:String,blogCategory:String,blogCreated:String,blogFrontpage:Boolean=false) {
_itemID = itemID;
_blogTitle = blogTitle;
_blogText = blogText;
_blogCreated = blogCreated;
_blogCategory = blogCategory;
_blogFrontpage = blogFrontpage;
}
public function get itemID():uint {
return _itemID;
}
public function get blogTitle():String {
return _blogTitle;
}
public function get blogText():String {
return _blogText;
}
public function get blogCategory():String {
return _blogCategory;
}
public function get blogCreated():String {
return _blogCreated;
}
public function get blogFrontpage():Boolean {
return _blogFrontpage;
}
public function toString():void {
}
public function blogURLVars():String {
var s:String;
s = "itemID="+ _itemID;
s += "blogTitle="+ _blogTitle;
s += "blogText="+ _blogText;
s += "blogCategory="+ _blogCategory;
s += "blogCreated="+ _blogCreated;
s += "blogFrontpage="+ _blogFrontpage;
return s;
}
}
}

DescrybeType could be of help here. I'm basing this answer in this other answer (you might want to check it out): Fastest way to get an Objects values in as3
Basically, the describeType function will let you inspect the public interface of your object. That means public variables, getter/setters and methods (plus some other info not relevant to your problem). So you get a list of all the getters and with that, return the names of said properties plus their actual values for a given object. Not that this is not exactly the same as your sample code, since this will not use the private variables, but rather will call the getters.
In code, this could be something like this (based on code in the linked question).
package {
import flash.net.URLVariables;
import flash.utils.describeType;
import flash.utils.getQualifiedClassName;
public class PropertiesHelper {
public function PropertiesHelper() {
}
private static var typePropertiesCache:Object = {};
public static function getPropertyNames(instance:Object):Array {
var className:String = getQualifiedClassName(instance);
if(typePropertiesCache[className]) {
return typePropertiesCache[className];
}
var typeDef:XML = describeType(instance);
trace(typeDef);
var props:Array = [];
for each(var prop:XML in typeDef.accessor.(#access == "readwrite" || #access == "readonly")) {
props.push(prop.#name);
}
return typePropertiesCache[className] = props;
}
public static function getNameValuePairs(instance:Object):URLVariables {
var props:Array = getPropertyNames(instance);
var vars:URLVariables = new URLVariables();
for each(var prop:String in props) {
vars[prop] = instance[prop];
}
return vars;
}
}
}
Use:
var blog:Blog = new Blog(1,"title&","text","cat","created");
var urlVars:URLVariables = PropertiesHelper.getNameValuePairs(blog);
trace(urlVars);
I'm using a URLVariables object since it seems that's what you want (though not actually what you blogURLVars method does), but you could change that in the getNameValuePairs method to suit your needs if necessary. An advantage of using a URLVariables object is that it handles the url-encoding for you automatically, so reserved characters such as &, =, etc, should not be a problem.

Related

Flex - Problems in accessing static variable on another mxml page

First.mxml - Contains a Datefield control as follows:
<mx:DateField id="G2_CRTLoadDate" width="150" selectedDate="{modelProxy.G2_CRTLoadDate}" change="{modelProxy.G2_CRTLoadDate = event.currentTarget.selectedDate;changeManagerStatus()}"/>
I'm assigning this Datefield value to a static variable CERT_LOAD_DATE as follows(First.mxml):
[Bindable]
public static var CERT_LOAD_DATE:String = "";
private function changeManagerStatus():void
{
CERT_LOAD_DATE = G2_CRTLoadDate.selectedDate.toDateString();
}
Second.mxml -Here, I have a Combobox as follows:
<mx:ComboBox id="General_Release_Dates"
selectedItem="{modelProxy.General_Release_Dates}"
valueCommit="{model.General_Release_Dates = event.currentTarget.selectedItem;updateReleaseDate(event)}"
change="{model.General_Release_Dates = event.currentTarget.selectedItem;updateReleaseDate(event)}" close="closeHandler(event);" includeInLayout="true" visible="true">
</mx:ComboBox>
Inside the closeHandler function, I'm trying to access the variable CERT_LOAD_DATE as follows:
private function closeHandler(evt:DropdownEvent):void {
var CurrentDate:Date = new Date();
if(General_Release_Dates.selectedLabel.toString() == "TBD")
{
Alert.show(First.CERT_LOAD_DATE);
}
}
The alert box displays no value (null). Please help.
I can't figure out the relationship between First.mxml and Second.mxml from your question.
However, the following code can't access First.mxml.
Alert.show(First.CERT_LOAD_DATE);
Because the "First" is not the same instance as loaded "First.mxml".
How about to use singleton? It's accessible from anywhere.
1st, add MySingleton.as class like this.
package foo.bar
{
public class MySingleton
{
private var _cert_load_date:String;
public function MySingleton(internally:SingletonInternal)
{
super();
if(internally == null)
{
throw new Error("Please use getInstance() method.");
}
}
public static function getInstance():MySingleton
{
return SingletonInternal.instance;
}
public function set cert_load_date(value:String):void
{
_cert_load_date = value;
}
public function get cert_load_date():String
{
return _cert_load_date;
}
}
}
import foo.bar.MySingleton;
class SingletonInternal{
public static var instance:MySingleton
= new MySingleton(new SingletonInternal());
public function SingletonInternal(){}
}
How to use
Set value at First.mxml.
public var singleton: MySingleton = MySingleton.getInstance();
private function changeManagerStatus():void
{
singleton.cert_load_date = G2_CRTLoadDate.selectedDate.toDateString();
}
Second.mxml
public var singleton: MySingleton = MySingleton.getInstance();
private function closeHandler(evt:DropdownEvent):void {
var CurrentDate:Date = new Date();
if(General_Release_Dates.selectedLabel.toString() == "TBD")
{
Alert.show(singleton.cert_load_date);
}
}
Updated: Aug 27 10:00(JST)
I think there are two way to change First.mxml's element using singleton.
1) Binding the DateField value to singleton variables, and clear the value at Secend.mxml.
2) Assign to singleton variables whole "First", and control from Second.mxml.
I'll write here the 2nd way.
If you use this way, anything is controlable from Second.mxml.
MySingleton.as
private var _first:Object;
public function set first(value:Object):void
{
_first = value;
}
public function get first():Object
{
return _first;
}
First.mxml
singleton.first = this;
Second.mxml
public function something(): void{
First(singleton.first).G2_CRTLoadDate.selectedDate = null;
// The cast is unnecessary. Following code also works.
// singleton.first.G2_CRTLoadDate.selectedDate = null;
}
Also you can execute First.mxml's public function from Second.mxml.
singleton.first.someFunctionDefinedAtFirst();

Flash cs5: Set a variable using a function, then read that variable from a differect function

I have a public variable and I am trying to set it, then read it from a different function:
public var str:String;
public function DailyVerse()
{
function create() {
str = "hello";
}
function take() {
var message:String = str;
trace(message);
}
take();
}
My trace results says null. Why does it not give me "hello"?
I'm not sure why you have this set up this way.... if you want to get and set variable, you use the getter and setter syntax for flash.
private var myRestrictedString:String;
public function get DailyVerse():String {
if(myRestrictedString == undefined) {
//Not yet created
myRestrictedString = "Something";
}
return myRestrictedString;
}
public function set DaileyVerse(string:String):void {
myRestrictedString = string;
}
Now you can access this from outside of your class like so:
myClass.DailyVerse = "Test";
trace(myClass.DailyVerse); //Outputs "Test"

How to pass a reference to class into another class

The question is a bit silly. I am trying to implement a skill updating system. So to explain.
There is a class
class AppInfo
{
public static var power:int = 10;
public static var speed:int = 20;
}
and class SmartButton which should take a reference to one of the static variables e.g. power in a constructor and increment it on the given value.
e.g.
class SmartButton
{
public function onClick(skillReference:int = <AppInfo.power>, incrementVAlue:int = 10)
{
skillReference += incrementVAlue
}
}
I want this code to update the value of the power in AppInfo class. But this doesn't happen... I assume because the skill was passed as value not as reference...
Can you suggest a way of solving the task?
Thanks
Your assumption is correct, ints are passed by value rather than reference. One direct approach would be to encapsulate power into a reference type (a class) rather than a value type:
class Skill {
public var value:int;
public function Skill(val:int) {
this.value = val;
}
}
class AppInfo
{
public static var power:Skill = new Skill(10);
public static var speed:Skill = new Skill(20);
}
Then passing power should pass it as a reference to the instance. Though you would have to change your implemenation a bit to use skillReference.value instead.
Aside from that, I think there are a couple of ways to abstract what you want out. One way would be use an interface and leverage some dependency injection.
interface ISkills
{
function get power():int;
function set power(val:int):void;
}
class AppInfo implements ISkills
{
private static _power:int = 0;
public function get power():int { return _power; }
public function set power(val:int):void { _power = val; }
}
class SmartButton
{
public function onClick(skills:int = ISkills, skill:String = "power", incrementVAlue:int = 10)
{
skills[skill] += incrementVAlue
}
}
The idea here that you want to decouple your usage from your implementation. In this case SmartButton doesn't need to know how Skills work just how to operate on them. It loses its reference to the static class AppInfo in favor of an injectable instance. There are some advantages to this approach, it makes it easier to test and easier to swap implementations later if you decide that a static class isn't the best implementation idea without having to update a bunch of classes/code. Also, rather than injecting ISkills into the method, you could inject it into the constructor of SmartButton, and keep a private reference to the skill container.
Another approach would be to use a functional approach.
class SmartButton
{
public var defaultWorker:Function = function(val:int):void {
AppInfo.power += val;
}
public function onClick(worker:Function = undefined, incrementValue:int = 10):void
{
if(worker == undefined) worker = defaultWorker;
worker.call(this, incrementValue);
}
}
Again, in this case, rather than tightly coupling your implementation to use the AppInfo class directly, you inject a "worker" for it do the work for you (if the worker is undefined then use the default worker. You can then swap out which property gets changed by changing the closure that gets passed in. For instance if you wanted to change speed instead then you would call:
var smartButton:SmartButton;
smartButton.onClick(function(val:int):void { AppInfo.speed += val});
Not quite as succinct as it could be, but it gets the job done.
The obligatory "elegantly sophisticated" approach using the command pattern:
Interface Command {
function execute():void;
}
Class UpdatePower implements Command {
private var appInfo:AppInfo;
private var delta:int;
public function UpdatePower(appInfo:AppInfo, delta:int) {
this.appInfo = appInfo;
this.delta = delta;
}
public function execute():void {
appInfo.delta += delta;
}
}
Class SmartButton {
var command:Command;
public function SmartButton(command:Command) {
this.command = command;
}
public function onClick(event:Event):void {
command.execute();
}
}
I would probably implement this in a slightly different way.
Maybe something like;
class Properties {
private var _properties:Dictionary = new Dictionary();
public function setValue(key:String, value:int) {
_properties[key] = value;
}
public function getValue(key:String):int {
if( !_properties[key] ) return 0;
else return _properties[key];
}
public function modifyValue(key:String, value:int) {
setValue(key, getValue(key) + value);
}
}
class SmartButton
{
public function onClick(target:Properties, key:String, incrementValue:int = 10) {
target.modifyValue(key, incrementValue);
}
}
Or something along those lines.

AS3 1120 Error on instantiating

I am trying to create a basic functionality in AS3.
I have a class like this:
package tax
{
public class Calculator
{
public function Calculator()
{
}
private var grwage:Number;
private var taxes:Number;
private var superannuation:Number;
private var insurance:Number;
private var net:Number;
public function getGrwage():Number {
return grwage;
}
public function setGrwage(grwage:Number):void {
this.grwage = grwage;
}
public function getTaxes():Number {
return grwage;
}
public function setTaxes(taxes:Number):void {
this.taxes = grwage * 0.2;
}
public function getSup():Number {
return superannuation;
}
public function setSup(superannuation:Number):void {
this.superannuation = superannuation * 0.05;
}
public function getIns():Number {
return insurance;
}
public function setIns(insurance:Number):void {
this.insurance = insurance * 0.1;
}
public function getNet():Number {
return net;
}
public function setNet(net:Number):void {
this.net = grwage - taxes - superannuation - insurance;
}
}
}
Just some getters and setters.
And in my mxml file:
import tax.Calculator;
public var calculate:Calculator = new Calculator();
calculate.setGrwage(1000);
trace(calculate.getTaxes());
trace(calculate.getSup());
trace(calculate.getIns());
trace(calculate.getNet());
I get an error 1120 Access to undefinded property when I try to access calculate. Do you have any ideas?
Thanks.
I guess you're mixing up things a bit between getters and setters. If a variable depends on another, you have to write the calculation in its getter. This variable shouldn't exist as a private member and the accesses to it must always be done through the appropriate getter.
for example:
public function getNet():Number {
return getGrwage() - getTaxes() - getSup() - getIns();
}
So here, you only need one setter (setGrwage), you can remove the others ones and put the calculation in the getters.
Note that there is a more appropriate syntax for setters and getters in AS3.
class GetSet
{
private var privateProperty:String;
public function get publicAccess():String
{
return privateProperty;
}
public function set publicAccess(setValue:String):void
{
privateProperty = setValue;
}
}
There are multiple issues with your class. So lets redesign it
The main issue you had was you were not initiating the vars before you accessed them as they had a NULL value the flash player was throwing you that error.
As you can see in the constructor I set a default value of 0 so that they will never be NULL.
package tax {
public class Calculator{
private var _grwage:Number;
private var _taxes:Number;
private var _superannuation:Number;
private var _insurance:Number;
public function Calculator() {
this._grwage = 0;
this._taxes = 0;
this._superannuation = 0;
this._insurance = 0;
}
public function get grwage():Number {
return this._grwage;
}
public function set grwage(val:Number):void {
this._grwage = val;
}
public function get taxes():Number {
return this._taxes;
}
public function set taxes(val:Number):void {
this._taxes = val * 0.2;
}
public function get superannuation():Number {
return this._superannuation;
}
public function set superannuation(val:Number):void {
this._superannuation = val * 0.05;
}
public function get insurance():Number {
return this._insurance;
}
public function set insurance(val:Number):void {
this._insurance = val* 0.1;
}
public function get net():Number {
return this._grwage - this._taxes - this._superannuation - this._insurance;
}
}
}
import tax.Calculator;
public var calculate:Calculator = new Calculator();
//Now due to the fact we are using true setter/getter methods.
calculate.grwage = 1000;
trace( calculate.taxes); // should be 0 as we are defaulting to the initial value
trace( calculate.superannuation );// should be 0 as we are defaulting to the initial value
trace( calculate.insurance );// should be 0 as we are defaulting to the initial value
trace( calculate.net );// should be 1000 as we are defaulting to the initial values of everything but grwage
The answers here are all good, but they all miss the primary point:
You're trying to get your variables before you set them.
import tax.Calculator;
public var calculate:Calculator = new Calculator();
calculate.setGrwage(1000);
trace(calculate.getTaxes());
trace(calculate.getSup());
trace(calculate.getIns());
trace(calculate.getNet());
This will throw an error (due to the way you've set up your class), because you never called setSup(), setIns(), and setNet() before trying to use them.
While your class may not be written in the best way, it is syntactically sound.
Try calling each setter before your getter. I think you'll solve your issue.

undefined method in object?

I get an error when I want to compile the following code...
I get undefined method when I'm trying to set a variable with the Filters class..
trace(filters.txt()); // returns undefined method
trace(filters); // returns [object Filters]
but I'm using this same object in other scripts without problems?
package player {
import flash.display.Sprite;
import filters.Filters;
public class Time_bar extends Sprite {
private var bar = null;
public var color = null;
public var _w = 0;
public var _h = 0;
public var _x = 0;
public var _y = 0;
public function Time_bar(){
this.bar = new Sprite();
addChild(this.bar);
}
public function cnstr(){
this.bar.graphics.beginFill('0x'+this.color);
this.bar.graphics.drawRect(0, 0, this._w, this._h);
this.bar.graphics.endFill();
this.bar.x = this._x;
this.bar.y = this._y;
this.bar.alpha = 0.75;
this.bar.scaleX = 0;
var filters = new Filters();
trace(filters);
trace(filters.txt());
//filters.txt(this.bar);
}
public function progress(float){
this.bar.scaleX = float;
}
}
}
the Filters class looks like this:
package filters {
import flash.display.Sprite;
import filters.Filters_glow;
public class Filters extends Sprite {
private var Glow = new Filters_glow();
public function txt(instance){
Glow.color = '93fafe';
instance.filters = [Glow.filter()];
}
public function loader(instance){
Glow.color = '93fafe';
Glow.alpha = 0.5;
instance.filters = [Glow.filter()];
}
}
}
Filter_glow:
package filters {
import flash.filters.GlowFilter;
public class Filters_glow {
public var color = '000000';
public var alpha = 0.25; // range: 0-1
public var blurX = 4; // range: 0-255; optimized values: 2,4,8,16 etc
public var blurY = 4; // range: 0-255; optimized values: 2,4,8,16 etc
public var strength = 1; // range: 0-255
public var quality = 3; // range: 0-15
public var inner = false;
public var knockout = false;
public function filter(){
this.color = '0x'+this.color;
return new GlowFilter(this.color, this.alpha, this.blurX, this.blurY, this.strength, this.quality, this.inner, this.knockout);
}
}
}
var _filters = new Filters();
_filters.txt(this.bar);
aparently filters is a reserved property name.. after changing filters to _filters the error disapeared :)
To verify whether the method "txt" exists on the filters object you'd have to write trace(filters.txt);. Instead you're executing the txt-method with a missing parameter by adding the brackets. And while executing, it tries to access instance which is undefined. I agree with Matti though that the error message should say something else.
As to why filters.txt(this.bar); doesn't work, I suspect the problem lies elsewhere, can you include the invoking code and the Filters_glow class?
The error is clearly visible. You are not passing the only required argument to the function txt.
public function txt(instance){
Glow.color = '93fafe';
instance.filters = [Glow.filter()];
}
So you can only call txt function by passing it an instance even. something like:
trace(filters.txt(YourObject));
I assume the argument is an instance of the object you want to apply the filter to or something like that. Well it's your function...
try modifying your code as follows, this might help with the error:
//...
public class Filters extends Sprite {
private var Glow: Filters_glow;
public function Filters(){
Glow = new Filters_glow();
}
public function txt(instance: DisplayObject = null): Boolean{
if(!instance){
return false;
}
Glow.color = '93fafe';
instance.filters = [Glow.filter()];
return true;
}
//...