What TextInput event can I listen for to throw an Alert when a number is entered? The scenario is : a user enters a number into myTxt1. An Alert appears that says "Are you sure you want to enter that number?". If the user clicks Yes, do nothing/continue. If the user clicks No, leave focus on myTxt1 so he can change the number.
Problem is, I don't know what event to listen to to throw the Alert. I've tried valueCommit and focusOut. With both of these, the alert shows, but when the user clicks Yes, focus remains on myTxt1, even if the event was triggered by the user clicking on myTxt2. User tries to leave myTxt1, but sees the ALert, clicks Yes, focus remains on myTxt1, and it's a vicious cycle.
This seems like a simple issue, but I can't figure it out. Any advice?
If you are trying to prevent user from entering numbers or otherwise consider using restrict property. But if you just want user to be notified for entering number, you may use change event.
In your focusOut handler you have to store the object that is going to get the focus. That's because when you show an Alert this information is gone since the Alert window now gets the focus. See the following example on how to do it properly. I'd suggest you build your own custom component that does all the work for you...
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.managers.FocusManager;
protected var previousValue:String;
protected var nextValue:String;
protected var focusInObject:InteractiveObject;
protected function isNumber(value:String):Boolean
{
// do your check
return true;
}
protected function textInput_focusOutHandler(event:FocusEvent):void
{
var value:String = TextInput(event.currentTarget).text;
if (!isNumber(value) || value == previousValue)
return;
nextValue = value;
focusInObject = event.relatedObject;
Alert.show("Are you sure you want to enter that number?", "", Alert.YES | Alert.NO, this, alertCloseHandler);
}
protected function alertCloseHandler(event:CloseEvent):void
{
if (event.detail == Alert.NO)
return;
previousValue = nextValue;
if (focusInObject)
systemManager.stage.focus = focusInObject;
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:TextInput focusOut="textInput_focusOutHandler(event)"/>
<s:CheckBox label="Foo"/>
<s:Button label="Bar"/>
</s:Application>
I've included a small optimization. The application remembers the value if the user presses Yes. In case you get another focusOut event and the value hasn't changed since last time then the Alert won't be shown.
You can listen for the change event if its a TextArea component. If there is any change in the text area then a change event will be fired. You can then check which key is pressed.
Related
Is there a way to listen for this? I can easily listen for click which selects a RadioButton, but I can't seem to find a way to listen for when the RadioButton has been deselected.
Any ideas?
Thanks!
Back in the Flex 2 days, the "change" event triggered when a radio button was deselected. However, this little convenience disappeared in Flex 3, for some reason, and I don't believe that we were provided with any sort of replacement event.
Handling your events at the RadioButtonGroup level is all fine and well, except that there are times when you really want to handle the events on the radio button level -- particularly if you were hoping to interact with a data provider entry via an itemRenderer that is drawing the radio button.
Conveniently, I have a little bit of boilerplate code you can use as drop-in replacements for RadioButton and RadioButtonGroup that provide a "unselect" event at the radio button level. Here is the SmartRadioButton, first of all:
<?xml version="1.0" encoding="utf-8"?>
<s:RadioButton xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import events.SmartRadioButtonEvent;
public function notifyDeselect():void {
dispatchEvent(new SmartRadioButtonEvent('deselect'));
}
]]>
</fx:Script>
<fx:Metadata>
[Event(name="deselect", type="events.SmartRadioButtonEvent")]
</fx:Metadata>
</s:RadioButton>
And here is the SmartRadioButtonGroup:
<?xml version="1.0" encoding="utf-8"?>
<s:RadioButtonGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
change="selectionChanged();"
>
<fx:Script>
<![CDATA[
import spark.components.RadioButton;
import components.SmartRadioButton;
protected var oldSelection:SmartRadioButton = null;
// Notify our old selection that it has been deselected, and update
// the reference to the new selection.
public function selectionChanged():void {
var newSelection:SmartRadioButton = this.selection as SmartRadioButton;
if (oldSelection == newSelection) return;
if (oldSelection != null) {
oldSelection.notifyDeselect();
}
oldSelection = newSelection;
}
// Override some properties to make sure that we update oldSelection correctly,
// in the event of a programmatic selection change.
override public function set selectedValue(value:Object):void {
super.selectedValue = value;
oldSelection = super.selection as SmartRadioButton;
}
override public function set selection(value:RadioButton):void {
super.selection = value;
oldSelection = super.selection as SmartRadioButton;
}
]]>
</fx:Script>
</s:RadioButtonGroup>
The two property overrides are in there to make sure that we correctly update the oldSelection, in the event of a programmatic change to the group's selection.
SmartRadioButtonEvent isn't anything fancy or important. It could probably just be a plain Event, since there isn't a special payload.
I have tested the above code, and it all works, but there are surely edge conditions, and other oddities that should be addressed, if it's used in a larger system.
Currently, it seems that every time Ctrl-C is pressed within a textbox to copy its content, the textbox receives an Event.CHANGE, and thus our application decides that a change was made in the text box and enables the "apply changes" button, although no changes were made, and all the user wanted was to copy the textbox contents.
The textbox component we're using is spark.components.TextInput
On view initialization I register:
_view.hostNameTextBox.addEventListener(
Event.CHANGE, onConnectionDat‌aChanged, false, 0, true
);
And the event listener function is:
private function onConnectionDataChanged(e:Event):void {
_view.applyButton.enabled = true;
}
Any ideas ?
Thanks !
Here's a slight variation of #Sunil D.'s answer: use the operation property of the event to determine whether the current operation was a copy operation or another one:
private function inputChangeHandler(event:TextOperationEvent):void {
var operation:IOperation = event.operation;
if (operation is CopyOperation) trace("Ctrl+C was pressed");
if (operation is InsertTextOperation) trace("New text was inserted");
if (operation is DeleteTextOperation) trace("Some text was deleted");
}
This approach will also fix your issue with multiple TextInputs: only one event handler required instead of many.
The Spark TextInput dispatches a TextOperationEvent.CHANGE event on every keystroke that you make.
However, unlike the KeyboardEvent that Flextras is referring to, this event does not tell you which keys were pressed. Instead the event has an operation property which is a FlowOperation that describes the change.
But don't bother with that. Since the change event will get dispatched on every keystroke, compare the value of the TextInput with the the value from the previous change event.
private var lastTextInputValue:String = "";
private function inputChangeHandler(event:Event):void
{
if (textInput.text == lastTextInputValue)
{
}
else
{
}
lastTextInputValue = textInput.text;
}
You can try something like this:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import spark.events.TextOperationEvent;
protected function inPutText_changeHandler(event:TextOperationEvent):void
{
// TODO Auto-generated method stub
if(ctrlCPressed)
{
clickBtn.enabled = false;
ctrlCPressed = false;
}
else
{
clickBtn.enabled = true;
}
}
private var ctrlCPressed:Boolean = false;
protected function inPutText_keyDownHandler(event:KeyboardEvent):void
{
// TODO Auto-generated method stub
if(event.ctrlKey == true && event.keyCode == Keyboard.C)
ctrlCPressed = true;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:TextInput id="inPutText" change="inPutText_changeHandler(event)" text="Mahesh Parate"
keyDown="inPutText_keyDownHandler(event)"/>
<s:Button id="clickBtn" label="Click" enabled="false"/>
</s:Application>
The TextInput component contains two listeners, one for the TextInput.CHANGE event and one for the KeyboardEvent.KEY_DOWN. The keyDown listener will detect whether CTRL+C and set a flag. When the CHANGE event is handled, that listener will check whether the flag for CTRL+C is true or not and take the appropriate actions. If CTRL+C was pressed, the code will enable the button. If not, the button will be disabled and the flag reset to false.
I'm trying to use one great example of using SpriteVisualElement for item renderers from here:
The issue i have is it's impossible to detect the mouse click event when click points to the area of the renderer which doesn't have any child components. For example: if I click on the textfield, then it works and i see the mouse even dispatched. If I click on an empty spot on the renderer then no mouse event is dispatched. I've tried mouseEnabled=true (which is true by default any way) with no luck. I see from the Flex doc:
the click event is inherited from InteractiveObject. So maybe this has something to do with the focus (see the tread at the and of the page). Looking for an explanation why InteractiveObject behaves that way. Thanks!
What is happening is that you do not have anything in the renderer to click on so click will fall through your renderer, by adding and image or graphic you are creating a clickable area.
The best thing to do is to tell the render that it does not have any mouseChildren which will then make it respond to any click on it.
change this method
public function TweetRenderer()
{
this.mouseChildren = false;
percentWidth = 100;
}
I think is getting a bit clear now. The mouseChildren is a property on DisplayObjectContainer. And as the following example shows DisplayObjectContainer doesn't dispatch any mouse click events, when click occur on the area which is not taken by any of it's children. This is unintuitive because DisplayObjectContainer has a click event inherited from InteractiveObject, so one (a newbe like me) would expect it to dispatch an event if i click on the container. Setting mouseChildren=false kind of flattens the DisplayObjectContainer, so the click event on any of the children will be dispatched having target as a container. But!!! This still assumes that you click on the child, not on the empty area. There is no way to dispatch it when click is done inside the area which is not taken by the child. This example shows this: If you click on either TextField or on fill, then even is dispatched with SpriteVisualElement as target. If you click elsewhere the event is not dispatched. I'm still unclear on why this is an intended behavior, taking into account the presence of click event on the DisplayObjectContainer. Maybe because containers don't meant to detect the mouse clicks at all, but rather their children are? This is a bit unintuitive to me.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="creationCompleteHandler(event)" >
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function creationCompleteHandler(event:FlexEvent):void {
var tf:TextField = new TextField();
tf.text = "I'm inside SpriteVisualElement!";
tf.background = true;
tf.backgroundColor = 0xff0000;
tf.alpha = 0.75;
tf.selectable = false;
tf.width = 150;
tf.height = 25;
uic.addChild(tf);
uic.addEventListener(MouseEvent.CLICK, clickHandler);
uic.mouseChildren = false;
uic.mouseEnabled = true;
uic.graphics.lineStyle(1, 0xFF0000);
uic.graphics.moveTo(0,0);
uic.graphics.lineTo(uic.width,0);
uic.graphics.lineTo(uic.width,uic.height);
uic.graphics.lineTo(0,uic.height);
uic.graphics.lineTo(0,0);
uic.graphics.beginFill(0x00FF00,1);
uic.graphics.drawRect(12, 12, 178, 28);
uic.graphics.endFill();
}
protected function clickHandler(e:MouseEvent):void {
trace("click detected, target:",e.target);
}
]]>
</fx:Script>
<s:SpriteVisualElement id="uic" horizontalCenter="0" verticalCenter="0" width="200" height="50" />
</s:Application>
I have a spark borderContainer that contains a spark TextInput.
I have an mouse_down and mouse_up event handlers on the borderContainer in order to drag it around the screen; while dragging I change the cursor.
I would like to make the textInput behave as a "standard" textInput, i.e. when clicking on the textInput the user should not be able to drag the whole component but simply interact with text as he/she would normally. Also, I'd like the textInput cursor to look like a normal textInput cursor.
I'm not sure I'm doing this right. My assumption is that I need to stop the propagation of mouse_down and mouse_up on the textInput to inhibit the drag behavior from its parent, and manage rollOver and rollOut in order for the cursor to look ok. See below an example of my code (to simplify it there is no borderContainer or drag - but the code for that would be very simple - just a bit longer).
So here's the issue: if one clicks on the spark textInput and then rolls out of it the cursor turns into a combination of a textInput cursor + the standard cursor set for for the borderContainer. This doesn't seem to happen on mx textInput components (thus the two boxes), but unfortunately I need to use spark components. My guess is that I'm either not calling the cursorManager correctly or I'm not stopping the propagation of mouse_up properly - it seems like it should hit the textInput but not propagate to the borderContainer. I tried stopPropagation() as well but no luck.
Would love any advice / constructive criticism.
thank you!
f
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
creationComplete="application1_creationCompleteHandler(event)"
mouseDown="application1_mouseDownHandler(event)"
mouseUp="application1_mouseUpHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.managers.CursorManager;
[Bindable] [Embed(source="../resources/hand.png")] private var _handIcon:Class;
[Bindable] [Embed(source="../resources/Fist.png")] private var _fistIcon:Class;
private var _cursorID:int;
protected function textinput1_rollOutHandler(e:MouseEvent):void
{
e.stopImmediatePropagation();
CursorManager.removeCursor(_cursorID);
_cursorID = CursorManager.setCursor(_handIcon);
}
protected function textinput1_rollOverHandler(e:MouseEvent):void
{
e.stopImmediatePropagation();
CursorManager.removeCursor(_cursorID);
}
protected function application1_creationCompleteHandler(e:FlexEvent):void
{
_cursorID = CursorManager.setCursor(_handIcon);
}
private function stopPropagation(event:MouseEvent):void
{
event.preventDefault();
event.stopImmediatePropagation();
}
protected function textinput1_mouseDownHandler(event:MouseEvent):void
{
stopPropagation(event);
}
protected function textinput1_mouseUpHandler(event:MouseEvent):void
{
stopPropagation(event);
}
protected function application1_mouseDownHandler(event:MouseEvent):void
{
CursorManager.removeCursor(_cursorID);
_cursorID = CursorManager.setCursor(_fistIcon);
}
protected function application1_mouseUpHandler(event:MouseEvent):void
{
CursorManager.removeCursor(_cursorID);
_cursorID = CursorManager.setCursor(_handIcon);
}
]]>
</fx:Script>
<s:TextInput x="43" y="30"
rollOut="textinput1_rollOutHandler(event)"
rollOver="textinput1_rollOverHandler(event)"
mouseDown="textinput1_mouseDownHandler(event)"
mouseUp="textinput1_mouseUpHandler(event)"/>
<mx:TextInput x="43" y="70"
rollOut="textinput1_rollOutHandler(event)"
rollOver="textinput1_rollOverHandler(event)"
mouseDown="textinput1_mouseDownHandler(event)"
mouseUp="textinput1_mouseUpHandler(event)"/>
You can simply do not start drag and do not change the cursor if user clicks on input:
protected function application1_mouseDownHandler(event:MouseEvent):void
{
var container:DisplayObjectContainer = event.target as DisplayObjectContainer;
if (!container || container == textInput || textInput.contains(container))
return;
// start drag and change the cursor
}
I had a similar problem but I have several TextInput fields in the container. So to avoid checking every single of them I used this version of the idea:
if (event.target is RichEditableText) return;
Works perfectly...
Greetings, J!
I have text input boxes. There is validation for each of the boxes using numberValidator.
Now, the thing is that am using alert box to show if any error occurs.
Flowchart ::
1> Insert value in textBox.
2> NumberValidator validates the input on "trigger=change".
3> If error, alert message is displayed. The user clicks OK to go back to form.
4> Focus set back to the TextBox.
5> But, alert box makes the text input value blank / null. i.e. Both the previous error value entered by user and the default correct value will not be displayed now.
Goal : Display the most recent correct value that was entered in the text box. Not the default of any other, but the most recent correct value entered by the user.
can anyone help ??
Here is a complete answer. I used the "enter" event of the text box to do validation since the "change" event fires after only a single character is entered
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Alert
// set last correct value to a default
private var lastCorrectValue:String="411"
function handleInvalid(event:Event)
{
Alert.show("invalid");
textInput.text=lastCorrectValue
}
function handleValid()
{
Alert.show('Validation Succeeded!')
lastCorrectValue=textInput.text
}
]]>
</mx:Script>
<mx:TextInput id="textInput"
text="{lastCorrectValue}"/>
<!-- Use the enter event of the text box to do validation. The change event fires after a single character-->
<mx:NumberValidator source="{textInput}"
property="text"
integerError="Enter Integer value"
domain="int"
trigger="{textInput}"
triggerEvent="enter"
invalid="handleInvalid(event)"
valid="handleValid();"/>
</mx:Application>
You will need to store the most recent correct answer in a variable and have the click/close handler of the alert replace the value with the stored var.
here is an example of listening for alert event:
<?xml version="1.0"?>
<!-- controls\alert\AlertEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
private var lastKnownCorrectAnswer:String = "Some Answer";
private function alertListener(eventObj:CloseEvent):void {
// Check to see if the OK button was pressed.
if (eventObj.detail==Alert.OK) {
myText.text = lastKnownCorrectAnswer;
}
}
]]>
</mx:Script>
<mx:TextInput id="myAnswer"
width="150"
text="" />
<mx:Button id="myButton"
label="Copy Text"
click='Alert.show("Copy Text?", "Alert",
Alert.OK | Alert.CANCEL, this,
alertListener, null, Alert.OK);'/>
</mx:Application>
You will need to add your validation logic in there, but you get the idea. The above is from the Alert docs.
Fire a event on the Text Input FocusIn() and store whatever text value in a variable. (That would be your last correct answer). Reset the inputbox text to this value after validation... Hope I made sense :)