Quick background. I have a series of editable text areas in which I want to be able to add a variable on the click of a button.
If I click the button the textarea loses focus and so I cant code which textarea I need to add the variable into. Can anyone think of a way of keeping focus on the textbox, inserting the variable and then allowing the user to carry on typing.
I'm not sure if this is part or fully possible but any help would be much appreciated. I've been playing around with the setFocus function trying to get this to work with no success.
Here is a snippet of my code:
public function addFirstName(myText:string):void{
myText = myText + "<<firstname>>";
}
<mx:TextArea id="txt1" change="text1=txt1.text" text="{text3}" editable="true"/>
<mx:TextArea id="txt2" change="text2=txt2.text" text="{text2}" editable="true"/>
<mx:Button label="Insert First Name" click="addFirstName(focusedtextarea)"/>
its the focusedtextarea part Im stuck on
Thanks in advance!
Write some code using the focus out event to store which text area needs to be changed. Conceptually something like this:
var textAreaToBeChanged : TextArea;
protected function onTextAreaLoseFocus(event:FocusEvent):void{
// I'm pretty sure Target is the right property to use here; but didn't test
textAreaToBeChanged = target;
}
Later in your MXML, add the event listener.:
<mx:TextArea id="txt1" change="text1=txt1.text" text="{text3}" editable="true" focusOut="{onTextAreaLoseFocus(event)}"/>
<mx:TextArea id="txt2" change="text2=txt2.text" text="{text2}" editable="true" focusOut="{onTextAreaLoseFocus(event)}"/>
Sorted!
public var textAreaToBeChanged : Object;
public var textposition:int
//when leaving focus on a textbox, record the textarea and text position. If a button is clicked to add a variable, it needs to be added at this position
protected function onTextAreaLoseFocus(event:FocusEvent):void{
textAreaToBeChanged = event.target;
textposition = textAreaToBeChanged.caretIndex;
}
//split the text from the recent textbox at the position the cursor has just been. The restructure the text with the firstname variable in the middle.
public function addFirstName():void{
var firstbit:String = textAreaToBeChanged.text.substr(0,textposition);
var myString:String = firstbit;
myString = myString + firstnameVar;
var lastbit:String = textAreaToBeChanged.text.substr(textposition);
myString = myString + lastbit;
textAreaToBeChanged.text = myString;
//set the focus back to the textarea.
textAreaToBeChanged.setFocus();
//place the cursor after the variable we just added.
textAreaToBeChanged.setSelection(textposition + firstnameVar.length, textposition + firstnameVar.length);
}
and the MXML:
<mx:TextArea id="txt1" change="text1=txt1.text" text="{text3}" editable="true" focusOut="{onTextAreaLoseFocus(event)}"/>
<mx:TextArea id="txt2" change="text2=txt2.text" text="{text2}" editable="true" focusOut="{onTextAreaLoseFocus(event)}"/>
<mx:Button label="Insert First Name" click="addFirstName()"/>
Related
I want to open a dialog box with some questions when I click on a column in a Flex Datagrid. After the dialog is closed, I want to fill that cell with information from the dialog.
What I have until now is this:
public function startEdit(event:DataGridEvent):void {
// event.dataField is null, so we figure it out ourselves
var column:DataGridColumn = dgQObjects.columns[event.columnIndex];
if (column.dataField == "parameters") {
// depending on the type, we can fill in parameters
var type:String = ListCollectionView(dgQObjects.dataProvider).getItemAt(event.rowIndex).type;
switch(type) {
case "Gauge":
event.preventDefault();
quartzObjects[event.rowIndex].parameters = "foo";
updateLocalStorage();
dgQObjects.validateNow();
break;
case "Indicator":
break;
case "New Row":
event.preventDefault();
break;
}
}
}
It sets the 'parameters' to 'foo', so that's good, but it doesn't show that in the datagrid (validateNow() does nothing). Also, if I put in an Alert(), the startEdit keep triggering, and I can never close the Alertbox. The grid is defined as follows:
<QuartzUI:DoubleClickDataGrid width="800" x="10" y="10" height="337"
id="dgQObjects"
editable="true"
itemEditBegin="{startEdit(event)}"
itemEditEnd="{checkQuartzObjects()}"
creationComplete="{initDataGrid()}"
>
(A DoublieClickDataGrid is a subclass of DataGrid)
You should do this through data binding on the model object. It'll make your life a lot easier. Assume the following DataGrid:
<s:DataGrid id="dg" dataProvider="{dp}"
doubleClickEnabled="true"
doubleClick="editSelectedItem()">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="name" />
</s:ArrayList>
</s:columns>
</s:DataGrid>
doubleClickEnabled is false by default, so we have to set it explicitly to be able to catch the doubleClick events. Now let's have a look at the editSelectedItem() method:
private function editSelectedItem():void {
var popup:MyEditor = new MyEditor();
popup.data = dg.selectedItem as MyClass;
PopUpManager.addPopUp(popup, this, true);
PopUpManager.centerPopUp(popup);
}
We just create a new view and pass it the currently selected datagrid item. Then we open it as a modal popup. (note that I haven't added any code to close the popup again to keep my example as simple as possible). Now the MyEditor view looks like this:
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:m="net.riastar.model.*"
title="Edit label"
width="400" height="300" >
<fx:Declarations>
<m:MyClass id="data" />
</fx:Declarations>
<s:TextInput text="#{data.name}" />
</s:Panel>
We use two-way data binding to edit the name property of the MyClass instance (note that this property must be marked Bindable for this to work). This is enough for a working example: if you now edit the value in the TextInput, you'll see the according value change in the DataGrid in the background.
I inserted a dateField component. On clicking, it displays calendar. I would like to add 2 comboboxes, one shows hours (0 to 23) and other for minutes (0 to 59), to the calendar so that the user can select the time along with the date, and that will be displayed in the text input as date and time. One more thing I would like to add is clear button to clear the selected date in the calendar.
Since a DateField is essentially a TextInput coupled with a DateChooser, why not do that yourself? Also add your two ComboBox, make your TextInput editable="false" text="{dateTime}" where dateTime is a Bindable string variable you create as the concatenation of the values in the DateChooser and the two ComboBox. Call the function that creates the dateTime string on the change event of all three inputs.
Finally, add your clear Button, and have its click event call a function where you set the DateChooser to today, and the two combo boxes to default values, and update dateTime string as needed (to blank or to current date/time depending on what you are trying to do.)
Edit:
As you asked nicely, and as I am studying for the ACE exam and thought this made a nice excercise, here is what I came up with. I made the following custom component in a package named 'components' and called it 'myCustomDateField.mxml'
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="resetDisplay()">
<mx:DateFormatter id="dateFormat" formatString="DD-MMM-YYYY JJ:NN" />
<mx:Script>
<![CDATA[
[Bindable]
public var dateTime:Date;
private function updateDisplay():void {
var userDate:Date = new Date();
userDate.date = cal.selectedDate.date;
userDate.month = cal.selectedDate.month;
userDate.fullYear = cal.selectedDate.fullYear;
userDate.hours = hour.value;
userDate.minutes = minute.value;
dateTime = userDate;
}
private function resetDisplay():void {
var now:Date = new Date();
cal.selectedDate = now;
hour.value = now.hours;
minute.value = now.minutes;
dateTime = now;
}
]]>
</mx:Script>
<mx:Label text="Select Date and Time:" />
<mx:TextInput id="display" text="{dateFormat.format(dateTime)}" editable="false" />
<mx:DateChooser id="cal" yearNavigationEnabled="true" change="updateDisplay()" />
<mx:Label text="Hour:" />
<mx:NumericStepper id="hour" minimum="0" maximum="23" change="updateDisplay()" />
<mx:Label text="Minute:" />
<mx:NumericStepper id="minute" minimum="0" maximum="59" change="updateDisplay()" />
<mx:Button label="Clear" click="resetDisplay()" />
</mx:HBox>
In my application, I added the xmlns:cust="components.*" in the declaration tag, and inserted one <cust:myCustomDateFeild id="myDate" />. I was able to access the entry in the parent by using {myDate.dateTime}.
I made a few design assumption that you may decide to change, like the formatter, and I replaced your combo boxes with NumericStepper.
I'm having issues with the property "editable" of textArea control.
I have a component: OrderView.mxml and it's associated data class OrderViewData.as.
Orderview.mxml is inside a viewStack to enable navigation from a component to another.
In this particular case, OrderView.mxml is called by another component: SearchResult.mxml. I can thus navigate from SearchResult.mxml to OrderView.mxml, and back to SearchResult.mxml...
OrderView.mxml has textArea and textInput control, that have to be editable or nonEditable depending on the property var isEditable:Boolean from OrderViewData.as.
When the application is launched, isEditable = true. So, all textInput and textArea controls are editable the first time the user gets to OrderView.mxml. When the user clicks on the button order from OrderView.mxml, isEditable = false. When the user goes back to SearchResult.mxml, isEditable = true (again) --> Until here, everything works fine.
The thing is: when the user goes back to OrderView.mxml for the second time (and beyond), even if the property isEditable = true, textArea controls are still non editable... But the textInput controls are editable!
Here is some code for your comprehension:
OrderView.mxml
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="#F3EDEC">
<mx:TextArea
id="contentTA"
text="{OrderViewData.instance.contentTA}"
enabled="{OrderViewData.instance.isEnabled}"
width="100%" height="51"
maxChars="18" styleName="ORTextInput"
focusIn="if(OrderViewData.instance.isEditable) contentTA.setSelection(0, contentTA.length)"
editable="{OrderViewData.instance.isEditable}"/>
<mx:TextInput id="contentTI"
text="{OrderViewData.instance.contentTI}"
width="40" height="18" maxChars="4"
styleName="ORTextInput"
change="contentTI_change()"
focusIn="if(OrderViewData.instance.isEditable) contentTI.setSelection(0, contentTI.length)"
editable="{OrderViewData.instance.isEditable}"/>
</mx:Canvas>
Am I missing something?
Did you make your isEditable variable [Bindable]?
Well, looks like anybody has more ideas...
I came up with a not really clean solution. But it works...
I used a init function in the show event of the component, where I create the control and add it to the proper parent. Thus, the mxml code written before has been deleted =)
This init function looks like this:
private function init():void
{
// contentTA
if(contentTA != null && parentBox.contains(contentTA))
parentBox.removeChild(contentTA);
contentTA = new TextArea;
contentTA.text = OrderViewData.instance.contentTA;
contentTA.enabled = OrderViewData.instance.isEnabled;
contentTA.percentWidth = 100;
contentTA.height = 51;
contentTA.maxChars = 50;
contentTA.styleName = "ORTextInput";
contentTA.editable = OrderViewData.instance.isEditable;
contentTA.addEventListener(FocusEvent.FOCUS_IN, focusIn);
parentBox.addChild(contentTA);
// same thing for all the other textAreas of my component
...
}
I am new to flex, how do you change the text inside of a text control when a user has clicked a button. I could not find a way to do this. I used an event handler to input a .xml to a string and then to the text control. This doesn't seem to work. Any suggestions?
let's see if I can do this off the top of my head:
<mx:Button [all your button properties] onClick"buttonClick()"/>
<mx:Script>
<![CDATA[
public function buttonClick():void{
myText.text = "My new String";
}
]]>
yeah, that should do it.
Say I have a phone-number validator in flex and I have two TextInput controls for phone numbers. I don't want to have two separate validator controls defined that have essentially the same attributes... but each validator has only one "source" attribute. How can I use the same validator on multiple control? (or any equivalent solution)
Not inline, but you can perform the validation programmatically, say, on submission of a form, or when a user tabs out of a control, etc. Here's an example using a single PhoneNumberValidator to validate two form fields; the validation happens when the Submit button gets clicked:
<mx:Script>
<![CDATA[
private function validatePhoneNumber(txt:TextInput):void
{
v.listener = txt;
v.validate(txt.text);
}
private function btn_click():void
{
validatePhoneNumber(p1);
validatePhoneNumber(p2);
}
]]>
</mx:Script>
<mx:PhoneNumberValidator id="v" allowedFormatChars="()- .+" property="text" requiredFieldError="Required." wrongLengthError="Invalid length." invalidCharError="Invalid character." />
<mx:Form>
<mx:FormItem label="Phone Number 1">
<mx:TextInput id="p1" />
</mx:FormItem>
<mx:FormItem label="Phone Number 2">
<mx:TextInput id="p2" />
</mx:FormItem>
<mx:FormItem>
<mx:Button id="btn" label="Submit" click="btn_click()" />
</mx:FormItem>
</mx:Form>
Hope it helps!
Steps to reproduce:
TextInput creates dynamically
textInputBox = new MyTextInput;
textInputBox.restrict = “0-9.”;
textInputBox.maxChars = 24;
amountValidator = new NumberValidator();
amountValidator.source = textInputBox;
amountValidator.property = “text”;
amountValidator.allowNegative = false;
amountValidator.domain = “real”;
amountValidator.precision = 4;
amountValidator.required = false;
amountValidator.maxValue = 999999999999.9999;
amountValidator.trigger = textInputBox;
amountValidator.triggerEvent = Event.CHANGE;
amountValidator.addEventListener(ValidationResultEvent.VALID, amountValid);
amountValidator.addEventListener(ValidationResultEvent.INVALID, amountInvalid);
private function amountValid(event:ValidationResultEvent):void
{
valid = true;
fieldsValidated = true;
}
private function amountInvalid(event:ValidationResultEvent):void
{
valid = false;
fieldsValidated = true;
}
As mention in the creation, when we exceed the limit, it shows error my red color border, and the same time if you delete them by DEL key when it come to the given acceptable limit, automatically become to green soon.
Leave from the field and change values of another textinput(this is just a textinput, this is a form there are some more form elemets), then come back to value exceeded textfield by SHIFT+TABS and remove the additional entered numbers, when you come to green soon your value is accepted.
Now again enter more values and now you are in the warn zone, then leave from the field and do the few changes in other form elements.
Then come back to the value exceeded text filed by MOUSE CLICK, and start delete from DEL, even though you removed additional values, still fields shows that you are in warn zone.
Actual Results:
Even when remove additional numbers,still field is Red
Expected Results:
if remove additional numbers, field should come its normal status.
Picture of this issue can be viewed at View Screen Shot