Is it possible to create an instance of the main MXML and use it inside the ActionScript class.
public var obj:classname= new classname();
When i try to call a components id through obj.textfieldID... it does not...
though obj is an instance of the classname.mxml.
I'm not sure but it's possible that control instances are generated as protected. Try adding a public property/method that wraps access to your textfield. You should then be able to access that public member from outside the MXML file.
FYI, though, it's better practice to use binding to populate MXML components. You can add a binding via code using BindingUtils.bindProperty. Even then, though, you would bind a property on the MXML file (either in an <mx:Script> or in 'code-behind' via inheritance) and then have your textField bind to the property:
private var _displayText : String;
[Bindable] // only required on get
public function set displayText(value : String) : void
{
return _displayText;
}
public function set displayText(value : String) : void
{
_displayText = value;
}
Then your field would be declared:
<mx:Label id="displayNameLabel" text="{displayName}" />
Now displayNameLabel.text will automatically change everytime you change your (public) displayName property.
Related
Help me understand data Binding
When I create a variable in a class:
[Bindable] private var _name:String;
and then generate getters and setters, I get:
private var _name:String;
[Bindable]
public function get name():String
{
return _name;
}
public function set name(value:String):void
{
_name = value;
}
Why does it generate the tag '[Bindable]' only on the get function?
To me, it would seem that it should be on the set function, as I would want to know when the
value changes, not when the value is just read.
What might help to understand what is going on here is the code that the MXML compiler will generate for you when you make something [Bindable]. The MXML compiler wraps your [Bindable] property in it's own getter/setter. It does this so that the wrapper setter method can dispatch a "propertyChange" event when a new value is set. This event notifies the parties binding to the property that the value has changed.
Getters/setters in Actionscript are considered to be properties of the object (they are not methods of the object). So it doesn't matter whether your annotate the getter or the setter as [Bindable], the generated code does the right thing.
It's worth noting that you can avoid the generated code and optimize the situation by dispatching your own event when your property changes. To do this, your [Bindable] metadata tag needs to include the event name that will be dispatched when the property changes:
private var _name:String;
[Bindable("nameChanged")]
public function get name():String
{
return _name;
}
public function set name(value:String)
{
if (_name == value)
return;
_name = value;
dispatchEvent(new Event("nameChanged"));
}
Because the bindable metadata contains an event string, no extra code is generated. Note, the compiler won't warn you if you forget to dispatch the event from the setter. In fact, you can dispatch your custom binding event from anywhere in your class (this can be useful with functions that are bindable).
In Flex (Flash Builder 4), I need a way to know if something in an array collection has changed.
I have a custom object:
[Bindable]
public var _myobject:MyObject;
It's basically just a class containing a bunch of different String and Number properties.
I need a reliable way to know if any of the properties have been changed. For example, I am binding the properties to a user interface (fields), but it's also possible for some of the properties to change through code.
Is there a way to do this? I found ChangeWatcher, but that looks like it only looks at a single simple property, such as a String or Number. I need to watch or detect changes in all the properties in my object, hopefully without having to add ChangeWatcher events to every property. Is this possible?
You're probably better off just dispatching binding events on the specific properties you want bindable. Better yet, dispatch a custom binding event, so that all of the things that are bound don't have to filter for "is this the property I care about?" It's really easy with Flash Builder 4.5 to do this, just select your variable name and press Ctrl-1, select "Create getter and setter," select getter and setter and check "Bindable" and "create custom event."
This will create code for you that looks something like this:
private var _yourProperty:String;
[Bindable (event='yourPropertyChange')]
public function get yourProperty():String {
return _yourProperty;
}
public function set yourProperty(value:String):void {
if (value !=== _yourProperty) {
_yourProperty = value;
dispatchEvent(new Event('yourPropertyChange'));
}
}
This will be much less verbose and more performant than the code that Flash Builder generates for you behind the scenes when you just use the Bindable tag on its own.
If you use defined classes as VO/DAO and apply the [Bindable] tag to the class, this will do binding on all properties for you (so long as they are read/write).
Anonymous object detection is difficult at best, let alone adding additional headaches of loosing compiler type checking.
Super basic example: - the key is to tie it to the dispatcher, so internally it can send out the PropertyChangeEvent.
[Bindable]
public class Actor extends EventDispatcher
{
public var fName:String;
public var lName:String;
public var age:uint;
public function get displayName():String
{
return lName +', '+ fName;
}
public function Actor()
{
super();
}
}
public class BindableDictionary extends EventDispatcher {
public function BindableDictionary() {
super();
}
public var dictionary:Dictionary = new Dictionary();
[Bindable("change")]
public function get(key:Object):Object {
return dictionary[key];
}
public function put(key:Object, value:Object):void {
dictionary[key] = value;
dispatchEvent(new Event(Event.CHANGE));
}
}
maybe this class will give you some new idea
I have an actionscript class MyClass that extens NavigatorContent. I instantiate the class as a custom MXML NavigatorContnent component for an Accordion component. MyClass has a Button component that I have tried to attach an event listener to. I want the event to bubble so that I can have the handler in the Accordion component.
MyClass
package comp
{
import flash.events.Event;
import flash.events.MouseEvent;
[Event(name="selectEvent", type="flash.events.Event")]
public class MyClass extends NavigatorContent
{
public function MyClass()
{
super();
btnSelect.addEventListener(MouseEvent.CLICK, selectClickDispatcher);
}
public function selectClickDispatcher(event:MouseEvent):void
{
event.currentTarget.dispatchEvent(new Event("selectEvent",true));
}
}
}
From here I have the instantiated component nested in the Accordion. I am pretty sure the problem is in this class definition because when I set a breakpoint at the selectClickHandler, the code does not break. In case I am wrong I will post the rest of the components.
Custom component named MySubComp.mxml
<comp:MyClass
...I have a few more spark components here and nothing else...
/>
Accordion
<mx:Accordion>
<fx:Script> //omitted CDATA tags to save space
protected function selectEventHandler(event:Event):void
{
Alert.show("Value Selected");
}
</fx:Script>
//custom components are in the navs package
<navs:MySubComp selectEvent = "selectEventHandler(event)"/>
</mx:Accordion>
You have added the metadata to the class definition
[Event(name="selectEvent", type="flash.events.Event")]
so all you need to do in mxml is
<comp:MyClass selectEvent="event_handler(event)"
..... />
In AS3, you add an event listener by
myClass.addEventListener("selectEvent", event_handler);
P.S. Your class will have to extend EventDispatcher
Your class either needs to extend a DisplayObject class, or directly inherit from EventDispatcher in order to be able to use events. Forget about implementing IEventDispatcher as there's a special piece of black code somewhere that means that EventDispatcher is the only class that can set the target property of the Event class (I've tried it before).
Consider using other alternatives. Events in Flash tend to be slow and create objects all the time. Callbacks are a good system if you need something simple.
public class A
{
public var onSomething:Function = null;
public function foo():void
{
if( this.onSomething != null )
this.onSomething();
}
}
public class B
{
public function B()
{
var a:A = new A;
a.onSomething = this._somethingCalled; // set the callback
a.init();
}
private function _somethingCalled():void
{
trace( "hello there" );
}
}
You can also take a look at the Signals project: https://github.com/robertpenner/as3-signals/wiki
Signals are vastly superior to normal Flash events, and there's no restriction on the type of object that can use them (i.e. non-DisplayObject objects can still add event listeners and dispatch events). It's also faster and has a smaller memory footprint.
In case someone needs the real Actionscript-3 event dispatching to be used >>> this <<< is very helpful. I don't know if it is really slow but it meets the AS-3 standards.
I am rather new to flex and am trying to figure out how to listen for a custom event I have created. Let me give you a little background on my app first.
My directory structure is as follows.
assets
components
control
events
model
util
In the model class (which is bindable) I have an ArrayCollection which will get loaded with data via a web service call and a datagrid in a specific component will bind to that ArrayCollection and display the data. The web service is invoked via a button press which initiates the search through an event.
model/ApplicationModel.as
[Bindable]
public class ApplicationModel
{
//put specific model components here
public var data:ArrayCollection;
//the one instance in this Singleton
private static var _instance:ApplicationModel;
public function ApplicationModel()
{
if (_instance != null) throw new Error("ApplicationModel already exists!");
}
public static function getInstance():ApplicationModel
{
if (_instance == null) _instance = new ApplicationModel();
return _instance;
}
}
components/SearchBox.mxml
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import com.homedepot.di.tp.SCVTools.events.*;
private function doSearch():void
{
var query:String = searchTI.text;
//only want to dispatch an event if there is something to query
if (query) dispatchEvent(new CustomEvent(CustomEvent.UPDATE_START,query));
}
]]>
</mx:Script>
<mx:Label text="Enter Search Term"/>
<mx:TextInput id="searchTI" enter="doSearch()" />
<mx:Button label="Search" click="doSearch()"/>
</mx:HBox>
This search functionality works fine and will return the data that I want. What I need to be able to know is when this web service call is done so the view component can update other aspects of the view accordingly (hide columns of datagrid based on the data returned as an example).
My Application.mxml file will wire up my controller to listen for the CustomEvent. The controller will then delegate the work to actually call the web service and get the data. The delegate will create an HTTPService object and get the data. It will also process results of the HTTPService. I am currently trying to dispatch a new event in the function that handles the result of the HTTPService call. This does not seem to be working and it makes sense since the event will never bubble to my view component.
snippet of control/DataUpdateDelegate.as
public override function parse(event:ResultEvent):void
{
super.parse(event);
try
{
Application.debug("DataUpdateDelegate:parse");
var data:Object = event.result.records.record;
model.data = data as ArrayCollection;
dispatchEvent(new CustomEvent(CustomEevent.UPDATE_END) );
}
catch (error:Error)
{
handleError(error);
}
}
I have tried to wire this UPDATE_END event up in the Application.mxml file but that does not seem to work either.
Does anyone have any suggestions on how my view to listen to this event that is not dispatched from a child component but rather from an ActionScript class that knows nothing about the view component?
Thanks,
Thomas
You could bind a specific function to the data property using BindingUtils when your ApplicationModel is first set in your view:
public function set model(applicationModelInstance:ApplicationModel):void
{
_applcationModelInstance = applicationModelInstance;
BindingUtils.bindSetter(dataRefreshed, _applicationModelInstance, "data");
}
protected function dataRefreshed(value:Object):void
{
// do whatever you need to do here.
// value==applicationModelInstance.data
}
De-registering a binding like this to avoid memory leaks is a bit tricky, but since your ApplicationModel is a singleton you don't need to anyways.
I have a dynamic ActionScript Class that is used to send parameters to a WebService. Some of these parameters are always present, so they are public properties of the Class:
package
{
[Bindable]
public dynamic class WebServiceCriteria
{
public var property1:int;
public var property2:String;
public var property3:String;
public var property4:String;
}
}
But, I am also adding properties at runtime that can change over time:
criteria.runTimeProperty = "1";
I'm not very familiar with using dynamic classes, so I was wondering if it is possible to "remove" the new property. Let's say the next time I call the WebService I don't want that property sent - not even as a null. How can I remove it from the Class instance without creating a new instance each time?
I believe all you'd need to do is this:
delete criteria.runTimeProperty;
or
delete criteria["runTimeProperty"];
Either should do the same thing.
See the delete documentation for specifics.