I have a class like this. Property "isPag" is based on filed "ecboardid", I found that when ecboardid is changed, UI controls seem not be able to detect that "isPag" is also changed. So, how to make a property like this bindable?
[Bindable]
public class Encoder extends EventDispatcher
{
public var ecboardid : String;
/*-.........................................Methods..........................................*/
public function copyFrom(newEncoder:Encoder):void
{
ecboardid = newEncoder.ecboardid;
this.dispatchEvent(new Event('isPagChanged'));
}
[Bindable (event="isPagChanged")]
public function get isPag():Boolean
{
if(this.ecboardid != null)
{
if(this.ecboardid.search('xxx') != -1)
{
return false;
}
return true;
}
else
{
return false;
}
}
}
Edit:
If I change the property to a static function,
[Bindable]
public class Encoder extends EventDispatcher
{
public var ecboardid : String;
/*-.........................................Methods..........................................*/
public function copyFrom(newEncoder:Encoder):void
{
ecboardid = newEncoder.ecboardid;
this.dispatchEvent(new Event('isPagChanged'));
}
public static function isPag(String ecboardid ):Boolean
{
if(ecboardid != null)
{
if(ecboardid.search('xxx') != -1)
{
return false;
}
return true;
}
else
{
return false;
}
}
}
Will bind like this :
visible = {Encoder.isPag(encoder.ecboardid)}
work? Will visible change when encoder.ecboardid change?
I don't believe you can make read only properties Bindable, since Flex uses calls to the setter method for a property to issue the change events. Take a look here at the section on binding to properties of objects.
You need to have a setter as well as a getter.
Also, you have the class marked as bindable, if you weren't specifying the event name, then the [Bindable] on the method would be redundant.
Usually the compiler complains if you have just a getter and no setter and try to mark it [Bindable]
Code like this:
visible = {Encoder.isPag(encoder.ecboardid)}
Isn't how binding works. The {var} notation is for use in MXML. And isPag isn't static, so you can't refer to it as a class property. You need an instance of the Encoder class for this to be legal.
This is a simple change - just create getters/setters and dispatch your change event in the setter (after changing the value), like this:
private var _ecboardid : String;
public function get ecboardid():String
{
return _ecboardid;
}
public function set ecboardid(value:String):void
{
_ecboardid = value;
this.dispatchEvent(new Event('isPagChanged'));
}
Related
I am just looking design patterns used in Flex. Please tell me about value object design pattern and how is it implemented in Flex. Thank you.
A Value Object is really nothing more than a data object. It is OK to have some methods on a Value Object, in my opinion... but they exist for convenience and don't really add any behavior. For instance, here is an example of a VO:
[Bindable]
public class PersonVO {
public var firstName:String;
public var lastName:String;
public function PersonVO(firstName:String, lastName:String) {
this.firstName = firstName;
this.lastName = lastName;
}
public function clone():PersonVO {
return new PersonVO(firstName, lastName);
}
}
Note that this class is mutable by default which is why I added the [Bindable] tag. You are likely to want to use data binding with this class and you need [Bindable] (or some equivalent) to make that happen.
I actually prefer immutable value objects in many cases. Here is how you would implement a mutable VO:
public class PersonVO {
private var _firstName:String;
private var _lastName:String;
public function PersonVO(firstName:String, lastName:String) {
_firstName = firstName;
_lastName = lastName;
}
public function get firstName():String { return _firstName; }
public function get lastName():String { return _lastName; }
}
A VO is similar to a bean if you are from a Java background. I would code a VO as
public class UserVO
{
private var _name:String;
public function set name(value:String):void
{
_name = value;
}
public function get name():String
{
return _name;
}
}
Here we declare private variables and provide setter and getter methods to set the value for the members variables. Although it is not advised, you can perform range checking before assigning values inside the setter method. You can access the members as :
var userVo:UserVO = new UserVO();
userVo.name = "some name";
The following site is worth to have a look: http://www.flashmonkey.co.uk/using-value-objects-in-flash/
Assume i have a costum actionscript class.
public class myClass
{
private var myVariable:ArrayCollection;
...
}
Suppose also that i have a different class, that changes a second variable, which has the metadatatag [Bindable]. What methods and events do i have to implement in either of these classes, to make myVariable change, whenever the other is changend?
If you make the myVariable public, then you can just use [BindingUtils.bindProperty()][1]:
public class MyClass
{
public var myVariable:ArrayCollection;
public function MyClass(other:OtherClass) {
BindingUtils.bindProperty(this, "myVariable", other, "propertyName");
}
}
If you prefer to keep myVariable private, then you can use [BindingUtils.bindSetter()][2]:
public class MyClass
{
private var myVariable:ArrayCollection;
public function MyClass(other:OtherClass) {
BindingUtils.bindSetter(
function(newVal:*):void {
this.myVariable = newVal;
}, other, "propertyName");
}
}
I would like to dispatch an event from my class along with a url.
I know that I can do the following:
import flash.events.EventDispatcher;
private function thumbClick(e:MouseEvent):void
{
dispatchEvent(new Event("clicked"));
}
But I don't know how I would send params along with the event...?
Also, in my main app runner, I try:
var my_ev:Event = new Event("clickedImage");
my_ev.hasOwnProperty(e.currentTarget.link);
dispatchEvent(my_ev);
...but I'm not sure that this would be the correct syntax.
Thanks for any help,
jml
Allan is correct, you will want to make a custom event. Couple of things to note:
import flash.events.Event;
public class ThumbnailEvent extends Event
{
public static var THUMB_CLICKED:String = "thumbClicked";
private var _url:String;
public function get url():String { return _url }
public function ThumbnailEvent (type:String, url:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type,bubbles,cancelable);
_url = url
}
override public function clone():Event
{
return new ThumbnailEvent(type, url, bubbles, cancelable);
}
}
Custom events need to always override clone. If the event is bubbled or relayed in anyway it needs this method. Custom properties should be private with a read-only getter. This is a standard convention to prevent the alteration of properties throughout the life of the event.
Using this approach would change your code to:
private function thumbClick(e:MouseEvent):void
{
dispatchEvent(new ThumbnailEvent(ThumbnailEvent.THUMB_CLICKED, myUrlString));
}
//elsewhere
addEventListener(ThumbnailEvent.THUMB_CLICKED, thumbClickedHandler);
private function thumbClickedHandler(event:ThumbnailEvent):void
{
var link:String = event.url;
}
Custom Event tutorial at adobe.com
I just make a custom event class.
import flash.events.Event;
public class ThumbnailEvent extends Event
{
public static var THUMB_CLICKED:String = "thumbClicked";
public var url:String;
public function ThumbnailEvent (type:String,url:String)
{
super(type);
this.url = url
}
}
and then use it like:
var thumbEvent:ThumbnailEvent = new ThumbnailEvent(ThumbnailEvent.THUMB_CLICKED,"myURL");
dispatchEvent(thumbEvent);
I have a function called DrawPlaybook which listens to two events, one mouseclick event and one custom event.
public function DrawPlaybook(...):void
{
//...... other stuff
panel.addEventListener(MouseEvent.CLICK,
function(e:MouseEvent){onClickHandler(e,this.panel)});
panel.addEventListener(CustomPageClickEvent.PANEL_CLICKED,
onCustomPanelClicked);
}
I am planning to call the custom event from within "onClickHandler" like this:
public function onClickHandler(e:MouseEvent,panel):void
{
var eventObj:CustomPageClickEvent = new CustomPageClickEvent("panelClicked");
eventObj.panelClicked = panel;
dispatchEvent(eventObj);
}
private function onCustomPanelClicked(e:CustomPageClickEvent):void {
Alert.show("custom click");
}
And here is the class definition for CustomPageClickEvent:
package
{
import flash.events.Event;
import mx.containers.Panel;
public class CustomPageClickEvent extends Event
{
public var panelClicked:Panel;
// Define static constant.
public static const PANEL_CLICKED:String = "panelClicked";
public function CustomPageClickEvent(type:String){
super(type);
//panelClicked = panel;
}
// Override the inherited clone() method.
override public function clone():Event {
return new CustomPageClickEvent(type);
}
public function getPanelSource():Panel{
return panelClicked;
}
}
}
The issue is that "onCustomPanelClicked" never gets invoked at all. Please let me know if you notice anything that I missed.
It's because you have registered the event listener for CustomPageClickEvent on the Panel, but you're dispatching it from DrawPlaybook
Just change this:
var eventObj:CustomPageClickEvent = new CustomPageClickEvent("panelClicked");
eventObj.panelClicked = panel;
dispatchEvent(eventObj)
to this:
var eventObj:CustomPageClickEvent = new CustomPageClickEvent("panelClicked");
eventObj.panelClicked = panel;
panel.dispatchEvent(eventObj)
... or change the event listener to this.addEventListener(CustomPageClickEvent.PANEL_CLICKED,
onCustomPanelClicked);.
Let me know if that works.
I am having a problem where I dispatch a custom event but the listener does not receive it (i.e. myHandler() in the code below). If I put everything in one mxml file, it works. When I separate the responsibilities in to separate classes, it fails. It is not clear to me what I am missing.
Any help you be appreciated.
Here is my code (update() in ViewModel.as is the entry point):
ChangeEvent.as
import flash.events.Event;
public class ChangeEvent extends Event
{
public function ChangeEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
// Set the new property.
this.isEnabled = isEnabled;
}
// Define static constant.
public static const ENABLE_CHANGED:String = "enableChanged";
// Define a public variable to hold the state of the enable property.
public var isEnabled:Boolean;
// Override the inherited clone() method.
override public function clone():Event {
return new ChangeEvent(type, isEnabled);
}
}
Model.as
public class Model extends EventDispatcher
{
private function TriggerEvent():void
{
var eventObj:ChangeEvent = new ChangeEvent(ChangeEvent.ENABLE_CHANGED);
dispatchEvent(eventObj);
}
}
ViewModel.as
public class ViewModel
{
import mx.controls.Alert;
import ChangeEvent;
private var model:Model;
public function ViewModel()
{
model = new Model();
addEventListener(ChangeEvent.ENABLE_CHANGED, myHandler);
}
public function update():void {
model.LoadData();
}
private function myHandler(event:Event):void {
Alert.show("An event occurred.");
}
}
Do I have to 'register' the event in ViewModel.as similar to the metadata tag in mxml?
e.g.
[Event(name="enableChange", type="ChangeEvent")]
You have to add the event listener on the model object (since it is the one dispatching the event).
model = new Model();
model.addEventListener(ChangeEvent.ENABLE_CHANGED, myHandler);
Hope that helps.