Why is 'textField' not instantiated when I subclass TextArea in Flex? - apache-flex

I'm experimenting with TextArea and inheritance to implement some additional functionality on the protected textField property.
Unfortunately, when I create a new instance of the subclass, this property is set to null. I'm probably misunderstanding the way super() works, but I thought it would have been instantiated after the constructor finished.
Here's a small snippet of code which extends TextArea:
public final class ExtTextArea extends TextArea {
public function ExtTextArea() {
super();
}
public function testTextField():void {
if (textField == null)
Alert.show("null!");
}
}
}
The invoking code is simple:
var extTextArea:ExtTextArea = new ExtTextArea();
extTextArea.testTextField();
The Alert in ExtTestArea appears every time I run this code.
Why is this? Is there something more I need to do to access the textField property?

Since textField is "the internal UITextField that renders the text of this TextArea" I believe it will remain null until you add it to the display via .addChild(...). I ran a quick test to verify that once I've added it to the display, it is no longer null. You might want to add an event handler to the "creation complete" event and adjust it at that point (I think).

The Flex SDK comes with source code, so you can take a peek and see when this field is initialized. It is not initialized in the constrcutor, but you will see that a new TextField instantiated by createChildren(), which is called when the component is added to a layout container.

Related

In JavaFx, how to control focus of a custom control?

Suppose a JavaFX CustomControl node that contains, say, two TextFields.
If any of these TextFields has the focus, then CustomControl.isFocused() should return true. If none of them has focus, then CustomControl.isFocused() should return false.
How do I do that?
As your CustomControl uses composition, you can delegate to the focus properties of each TextField. Given two instances,
private final TextField tf1 = new TextField("One");
private final TextField tf2 = new TextField("Two");
The implementation of an instance method isFocused() is then straightforward:
private boolean isFocused() {
return tf1.isFocused() | tf2.isFocused();
}
Add focus listeners as shown here to see the effect.
tf1.focusedProperty().addListener((Observable o) -> {
System.out.println(isFocused());
});
tf2.focusedProperty().addListener((Observable o) -> {
System.out.println(isFocused());
});
This can't be done. The whole problem is that isFocused() is final in Node.
It seems you wanted to override isFocused() in CustomControl, but that is not possible for a final method and it would violate the notion of a single component having focus. As CustomControl is a composite, you'll need to manage focus internally. You may want to use a custom FocusModel as seen in ListView.
Try one line solution:
public BooleanBinding aggregatedFocusProperty() {
return Bindings.or(field1.focusedProperty(), field2.focusedProperty());
}
Now on a client side you may listen this aggregated focus property.

dialogPostRun method in RunBaseReport

I have a RunBaseReport which contains overrided dialog method where I'm adding couple of my controls. One of those controls is a combobox.
Controls enabled() property should be changed when I'm modifying combobox.
So basically I need to know when the value of my dfReportType dialog field changes.
public Object dialog(Object dialog)
{
DialogRunbase dialog = dialog;
;
//adding my combobox
dfReportType = dialog.addFieldValue(typeid(ReportType), ReportType:DefaultType);
//adding some other controls here
return dialog;
}
According to many articles that I found I need to override dialogPostRun Method and do something like this:
public void dialogPostRun(DialogRunbase dialog)
{
super(dialog);
dialog.dialogForm().formRun().controlMethodOverload(true);
dialog.dialogForm().formRun().controlMethodOverloadObject(this);
}
But unfortunately I don't have this method in RunBaseReport class.
Which should be there according to msdn .
Are there any other workarounds?
I'm currently on AX 2012 but I still looked at it. I have the method available in the context menu, but not on the first column. I have to go over "Plus..." to find the method in the second column.
Well, there is no dialogPostRun method in Report object that inherits RunBaseReport, but we have this method in Class that inherits RunBaseReport.
So that was my mistake. I used report object instead of class.
If you want to make custom dialog for the report but you also want to use all default controls you should:
Create class
Inherit RunBaseReport
Override dialog, getFromDialog etc.
Override lastValueElementName method
public identifiername lastValueElementName()
{
//just put name of your report object
return reportStr(YourReportName);
}
Don't forget to add main() method if you going to make call from menuItem.

Flex watch bindable property other class

I'm creating an application using Flex 4.
When the app is started, it reads a XML file and populate objects. The .send() call is asynchronous, so I would want to listen/watch to this populated object, and when it has finished, dispatch an event for other classes, so they can use it.
package model{
public class LectureService extends HTTPService{
[Bindable]
private var _lecture:Lecture;
...
}
The xml is parsed correctly and loaded inside the object lecture of the class Lecture.
If I use the MXML notation in the main.mxml app, it works fine (the object is used when the it is populated after the async request):
<mx:Image id="currentSlide" source={lectureService.lecture.slides.getItemAt(0).path} />
BUT, I have another ActionScript class and I'm not able to listen to this dispatched (by [Bindable]) event.
package components{
public class LectureSlideDisplay extends Image
{
public function LectureSlideDisplay()
{
super();
this.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onChangeTest);
}
private function onChangeTest(e:PropertyChangeEvent):void {
trace('test');
}
I have already tried:
using (like above) addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, methodName).
tried to change the [Bindable] to [Bindalbe("nameEvent")] and listen for this, nothing.
using CreateWatcher method, doesn't work.
tried to have a look to the generated code of the class, but didn't help me
if (this.hasEventListener("propertyChange")){
this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "lecture", oldValue, value));
}
How can I listen and have the populated object in another class?
Maybe the problem is that I'm listening from another class, but in this case how can I implement this?
It seems the event is dispatched, but I can't listen to it.
For who wants the answer, I have resolved changing the addEventListener object.
It is not right to use:
this.addEventListener(...)
Use instead:
lectureService.addEventListener(...)
I have changed my code to listen to this event in the main app MXML, and then inside the handler method, call the public method of your components to use the new data.
You can't solve all your problems by just extending the class. You should really look into Commands for your HTTP requests.
The change property event is used internally for watchers and won't dispatch in the overall component. What you want to do for your LectureSlideDisplay is to override the source setter. Every time it is called, a new value is being binded to it:
package components{
public class LectureSlideDisplay extends Image
{
override public function set source(value:Object):void
{
super.source = value;
// do whatever
}
public function LectureSlideDisplay()
{
super();
}
}
}
You should really read up on how Binding works.
Consider to use BindingUtils class. You can found documentation here. And a couple of usage samples: one, two.

Flex 3 event bubbling set to false.. how to make it bubble then?

I have a flex app with lots of nested views and popup windows..
I'd love to catch all the CHANGE events in the application at the top level.. all of them, simply to notify the user that he has changed something (trust me it makes sense in my app).
Now, I tried to add an event listener in the Application creationComplete handler like this:
private function init():void {
this.addEventListener(flash.events.Event.CHANGE, function f():void {...})
}
but it does not work.. why? I read in the docs that event bubbling for the CHANGE event is set to false before dispatching. How can I change that? Is there any other way to achieve my goal?
thanks
Try listening to events on the SystemManager instead of the Application. As far as I understand, SystemManager sits at the very top of the display list, adding the application, popups and other UI entities as children.
In Flex 3 and below, you can retrieve it via Application.application.systemManager.
Read more on the SystemManager on Deepa's blog:
http://iamdeepa.com/blog/?p=11
I am also having trouble with a group of TextArea controls where I would like to listen for the change event on their container (parent) instead.
What I did in the end was to extend the TextArea class and create a listener for the change event. From the listener I would then dispatch a custom event that could bubble.
public class BubblingTextArea extends TextArea
{
public function BubblingTextArea()
{
super();
addEventListener(TextOperationEvent.CHANGE, changeHandler);
}
private function changeHandler(event:TextOperationEvent):void
{
dispatchEvent(new ChangeBubbleEvent(ChangeBubbleEvent.BUBBLE_CHANGE));
}
}
The custom event:
public class ChangeBubbleEvent extends Event
{
public static const BUBBLE_CHANGE:String = "bubbleChange";
public function ChangeBubbleEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
I am sure someone can come up with a more elegant solution since I am still quite new to Flex and AS3 myself.
As far as I know, PopUps happen outside of the Application's main displayList, so that's probably why you're not seeing bubbling. In this case, you'll need to manually add listeners to popups. The Flash change event does bubble according to the docs: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/Event.html#CHANGE
I personally like to use a framework such as RobotLegs or Parsley.
The basic idea is that each view and popup gets a mediator. The mediator's job is to communicate between the view and the command/model. Those mediators can listen directly to the view and the view's components.

How do I make sure the text of an ActionScript TextInput is updated when the Object property defining that text is updated?

Not an easy question to decipher, so let me boil it down. I'm trying to convert an MXML component to an ActionScript Class. The component consists of a Form with a TextInput, TextArea, and two buttons - Save and Cancel, and a Validator for the TextInput, and other logic to handle events that occur. This component is currently extended by several other components.
Now, in the MXML component binding the TextInput text property to a property in an Object was very easy:
<mx:TextInput text="{_itemToEdit.name}" />
But in ActionScript, I'm creating the TextInput and setting the text property before the Object is set, and the TextInput is not being updated:
public var itemToEdit:Object = {};
private var nameInput:TextInput = new TextInput();
public function MyClass()
{
nameInput.text = itemToEdit.name;
}
How can I make sure that the TextInput text property is bound to the specified property in the Object?
Binding is all about firing change events. you'll need to modify your 'itemToEdit' class to be an EventDispatcher for this hack to work. here goes
//item to edit class
private var _name:String;
public function set name(value:String):void
{
_name = value;
dispatchEvent(new Event("NAME_CHANGED"));
}
//whatever the binding class is
private var _itemToEdit:ItemToEdit;
private var _textField:TextField;
public function set itemToEdit(value:ItemToEdit):void
{
if (_itemToEdit) removeEventListeners();
_itemToEdit = value;
if (_itemToEdit) addEventListeners();
}
private function addEventListeners():void
{
_itemToEdit.addEventListener("NAME_CHANGED", itemToEdit_nameChangedHandler);
itemToEditChangedHandler(null);
}
private function itemToEdit_nameChangedHandler(event:Event):void
{
_textField.text = _itemToEdit.name;
}
Obviously this was done just for speed, you'll need custom events and some better names etc, but this is the basic jist.
Apparently it's slightly more complex than a simple assignment to bind purely in AS, here's a couple tutorial/docs to show you how to pull it off.
http://cookbooks.adobe.com/index.cfm?event=showdetails&postId=6802
http://raghuonflex.wordpress.com/2007/08/30/binding-in-mxml-as/
Compile your MXML component with the -keep option. Examine the ActionScript code that was generated by mxmlc and do something similar.
You may also do it using the Proxy object - I blogged about it over here: http://flexblog.faratasystems.com/?p=433
If "itemToEdit" is a pure AS3 Object, then the binding probably doesn't work properly anyway. That is, it will work when the object is initially created, but any changes to "name" in the object won't be detected. (I could be wrong...haven't done extensive tests)
Anyway, your problem is easy to solve with getters/setters:
private var _itemToEdit:Object;
public function get itemToEdit():Object { return _itemToEdit; }
public function set itemToEdit(value:Objecy):void {
_itemToEdit = value;
nameInput.text = value.name;
}
Binding isn't necessary here.

Resources