Binding the value of a variable to a text input - apache-flex

I've been looking all over the internet but I couldn't find an answer to the following question: Is it possible to have the value of some string variable bound to the text inside a text input control? To clarify, whatever text was entered into the text input would be stored as the value of the variable.

Yes. Simply enough, you can do 2 way binding:
<fx:Script>
<![CDATA[
[Bindable] private var someObject:Object;
]]>
</fx:Script>
<s:TextInput text="#{someObject.someString}" />
With 2 way binding, any changes to the property 'someString' will change the TextInput or if you change the TextInput manually, your property 'someString' will be updated.

This may not be exactly what you're looking for but you could always have an event handler on the focusLostevent from the textInput which sets the variable you want to the textInput.text

You could set the value of the variable using the change event of the TextInput.
Example (untested):
<fx:Script>
<![CDATA[
[Bindable] public var someText:String = "foo";
protected function myText_changeHandler(event:TextOperationEvent):void
{
someText = myText.text;
}
]]>
</fx:Script>
<s:TextInput id="myText" text="{someText}" change="myText_changeHandler(event)" />

Related

Adding a text field with the click of a button using MXML or actionscript

I want to add a button which when clicked adds another text field. I am using adobe flash builder to write the application therefore it needs to be in MXML or actionscript. Any ideas as to how this could be done?
The eventhandler button currently points to this code, however after the first addition of the textbox, it stops and doesn't add any more. How do I make a loop to keep adding textfields for every time the button is clicked?
<fx:Script>
<![CDATA[
protected function tableID(event:MouseEvent):void
{
var name:TextInput = new TextInput;
addElement(name);
name.move(50, 200);
}
]]>
</fx:Script>
MXML:
<s:Button id="addBtn" x="175" y="450" label="+" click="tableID(event)" />
Just use a boolean variable for the text field. Set the variable for includeInLayout & visible for text field. On clicking the button set the condition for the boolean variable to be true or false. I think this will help you out.
You can try this way:
<fx:Script>
<![CDATA[
import mx.controls.TextInput;
protected function bt_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
var item:TextInput = new TextInput();
item.width = 50;
_parent.addElement(item);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:Tile id="_parent" width="100%" height="100%">
<s:Button id="bt" label="+" click="bt_clickHandler(event)"/>
</mx:Tile>

Assign variable to MXML component ID

I have my custom component and for example few Label. I want to pass to my component value which will be assign to label's id.
Code:
<fx:Script>
<![CDATA[
[Inspectable]
[Bindable]
public var test:String = "asd";
]]>
</fx:Script>
<s:Label id="{test}" text="etc"/>
Error: {test} is not a valid identifier
Can I even do something like that?
No you can't. You have to understand that when you write an mxml component like
<s:Group>
<s:Label id="myLabel" />
</s:Group>
it will generate ActionScript code like
public class MyClass extends Group {
public var myLabel:Label;
}
(Mind you, I grossly oversimplify the code here to convey the most important part).
As you can see your 'id' is in fact a property name. And you can't change a property's name at runtime can you?

ItemRender data change

I have a List with an ItemRenderer. When I click a button, then a property of the ArrayCollection I bound to the list is changed.
When I click the button, then it does change the property, but the list doesn't change.
How do I solve this.
Here's my code
<fx:Script>
<![CDATA[
[Bindable]
public var controllers:ControllerCollection = new ControllerCollection();
private function hideTheFirstItem(evt:MouseEvent):void
{
(controllers[0] as Controller).meetsRequirements = false;
//these methods don't work unfortunatly
controllers.itemUpdated(controllers[0]);
controllers.refresh();
}
]]>
</fx:Script>
<mx:List id="listControllers" dataProvider="{controllers}">
<mx:itemRenderer>
<fx:Component>
<solutionItems:displaySolutionItem visible="{data.meetsRequirements}" />
</fx:Component>
</mx:itemRenderer>
</mx:List>
<mx:Button label="test" click="hideTheFirstItem(event)" />
(ControllerCollection extends ArrayCollection)
Thanks!
Vincent
Two ways:
collection.refresh()
collection.itemUpdated()
Of course, ControllerCollection is not a standard Flex Collection class; so I am just assuming that it implements the ICollectionView interface.
Update:
I do notice that your code is set to modify the first element of the ArrayCollection
private function hideTheFirstItem(evt:MouseEvent):void
{
(controllers[0] as Controller).meetsRequirements = false;
//these methods don't work unfortunatly
controllers.itemUpdated(controllers[0]);
controllers.refresh();
}
I wanted to be sure to specify that the first element of the collection may not be the first element currently visible in the view. I wonder if that is causing you issues.
Without seeing your item renderer, I need to make some assumptions.
First, I will assume that your item renderer is using data binding to the meetsRequirements property. If that is the case, then the meetsRequirements property needs to notify when that property changes. If you add the [Bindable] tag to that property or the Controller class, then the meetsRequirements property will notify the itemRenderer to update that field based on your data binding.
If my assumptions are wrong, we need to see the code to give you any further thoughts.
First, don't try to create new collections if you don't need to.
I believe your problem lies with this statement: (controllers[0] as Controller).meetsRequirements = false; which should fail on compile because a collection item cannot be retrieved using the square bracket annotation. You need to use getItemAt(index:int) function.
Furthermore, you wouldn't want to set visible to false to an item renderer if you want to 'remove' it because then you'd have an empty spot. What you want to do is filter it out:
<s:Application creationComplete="onCreationComplete()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable] public var data:ArrayCollection = new ArrayCollection();
private function onCreationComplete():void
{
// TODO: need to add data here
// Adding filter function
data.filterFunction = filterItems;
}
private function filterItems(item:Object):Boolean
{
return item.meetsRequirements;
}
private function hideFirstItem():void
{
if(data.length > 0)
{
Controller(data.getItemAt(0)).meetsRequirements = false;
}
data.refresh();
}
]]>
</fx:Script>
<mx:List id="listControllers" dataProvider="{data}" />
<mx:Button label="test" click="hideFirstItem()" />
</s:Application>
This should do it. Untested though.
Try this:
<fx:Script>
<![CDATA[
[Bindable(Event="refreshMyList")]
public var controllers:ControllerCollection = new ControllerCollection();
private function hideTheFirstItem(evt:MouseEvent):void
{
(controllers[0] as Controller).meetsRequirements = false;
dispatchEvent(new Event("refreshMyList"));
}
]]>
</fx:Script>

in Flex DropDownList, is there a way to bind to a property of an item in dataProvider?

I have following code.
<s:DropDownList dataProvider={_dataProvider}/>
<fx:Script>
private var _dataProvider:ArrayCollection = new ArrayCollection([{label:"one", data:1}, {label:"two", data:2}]);
</fx:Script>
I want to bind the data property of the selectedItem in the DropDownList. Is there a way to do this?
Not sure if this another approach to the question... but I created a custom dropdownlist and binded the selectedItem to incoming changes. When the value of my desired data changes it will trigger the dropdownlist to change its selection.
DropDownListBindable.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DropDownList 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;
[Bindable] public var valueField:String = "";
override public function set selectedItem(value:*):void{
try{
for(var i:uint=0;i<this.dataProvider.length;i++){
if(this.dataProvider[i][this.valueField]==value){
this.selectedIndex=i;
break;
}else{
this.selectedIndex=-1;
}
}
}catch(e:Error){}
}
]]>
</fx:Script>
</s:DropDownList>
On the application I import the custom dropdownlist and bind the valuefield with whatever needs to be binded... in your case its 'data'. I also created an object called 'mydata' for the dropdownlist to listen to for changes. When mydata changes the list will too. I've added a button to demonstrate how the list changes.
main.mxml
<?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"
xmlns:components="com.components.*">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable] private var myData:Object = new Object();
[Bindable] private var _dataProvider:ArrayCollection = new ArrayCollection([{label:"one", data:1}, {label:"two", data:2}]);
]]>
</fx:Script>
<s:HGroup>
<components:DropDownListBindable
dataProvider="{_dataProvider}"
prompt="--select one--"
selectedItem="{this.myData}"
id="ddl"
valueField="data"
labelField="label"/>
<s:Button label="change datafield" click="this.myData=1"/>
</s:HGroup>
</s:Application>
I'm pretty sure the answer is no, but just to be clear; I'm confused.
If your dataProvider contains objects like this:
{label:"one", data:1}
First off, this syntax will create a generic object with no customization. If none of the properties on that object are explicitly defined, none of them can implement the Bindable metadata tag, and therefore when used as the source for data binding, the target will never update.
Second off, even if you created your own non-generic object with properties being bindable, binding doesn't usually go multiple levels deep into an object's properties of an array.
The selectedItem will point to an object like are in your _dataProvider, or possibly null, based on user interaction with the dropDownList. Binding the selectedItem to a property inside the item doesn't make sense; because you'd be comparing an literal to an object and nothing would ever be selected.
I'm unclear, without looking, what happens in the DropDownList when you try to set selectedItem to an item not in your dataProvider. I imagine it resets the selection, though.
If you can expand on what exactly you're trying to accomplish we may be able to help more.
<s:DropDownList id="ddl" dataProvider="{_dataProvider}"/>
<s:Label text="{ddl.selectedItem.data.toString()}"/>
Yes. You can do this. It is quite simple, actually. I do it all the time:
<s:DropDownList dataProvider="{_dataProvider}" selectedItem="#{_selectedItem}" />
With ActionScript that looks like this:
private var _dataProvider:ArrayCollection = new ArrayCollection([{label:"one", data:1}, {label:"two", data:2}]);
[Bindable] private var _selectedItem;
Every time the user selects an item in the drop down list, the _selectedItem will get set.

How do I create a bidirectional data binding in Flex 3?

I need to bind a property to an edit control and have the control write its value back to the same property. The problem is, I'm setting the source value before the control is created:
<mx:Panel>
<mx:Script>
<![CDATA[
[Bindable] public var editedDocument: XML;
]]>
</mx:Script>
<mx:TextInput id="docLabel" text="{editedDocument.#label}"/>
<mx:Binding source="docLabel.text" destination="editedDocument.#label"/>
</mx:Panel>
I call this like so:
var xmlDoc: XML = <document label="some label" />;
var myPanel: MyPanel = new MyPanel();
myPanel.editedDocument = xmlDoc;
parent.addChild(myPanel);
What happens is this:
the docLabel text field ends up blank (equal to "")
the xmlDoc's #label attribute is set to ""
What I want is this:
the docLabel text field should contain "some label"
the xmlDoc's #label attribute should change only when the docLabel's text property changes.
How do I accomplish this, using Flex 3?
Edit
I have also tried this:
<mx:Panel>
<mx:Script>
<![CDATA[
[Bindable] public var editedDocument: XML;
]]>
</mx:Script>
<mx:TextInput id="docLabel"/>
<mx:Binding source="editedDocument.#label" destination="docLabel.text"/>
<mx:Binding source="docLabel.text" destination="editedDocument.#label"/>
</mx:Panel>
The result is the same.
You can try using BindingUtils to programmatically create the binding after the class has been created:
http://life.neophi.com/danielr/2007/03/programmatic_bindings.html
There are many variations of this that I've used to tackle similar problems. If you can't figure it out from the link post a comment and I'll dig through my source code and see what I can find.
private function init():void
{
var xmlDoc: XML = <document label="some label" />;
var myPanel: MyPanel = new MyPanel();
myPanel.editedDocument = xmlDoc;
parent.addChild(myPanel);
BindingUtils.bindProperty(docLabel, "text", editedDocument, "label");
//or maybe it should be one of these, I have not done binding to an XML attribute before
BindingUtils.bindProperty(docLabel, "text", editedDocument, "#label");
BindingUtils.bindProperty(docLabel, "text", editedDocument, "{#label}");
}
Take a look at Two-way data binding.
Take a look at the part of the text:
In Flex 3, if you want to set
two-way binding using the
mx:Binding
tag you need to set it twice:
mx:Binding source="a.property" destination="b.property"/>
mx:Binding source="b.property" destination="a.property"/>
which becomes:
mx:Binding source="a.property" destination="b.property" twoWay="true"/>
In Flex 3 you would be better of doing something like this. Also not sure you can bind directly to XML?
Instead do something like this:
[Bindable] public var tmpString: String;
public var onChange():void {
tmpString = docLabel.text;
//set the XML string, etc.
}
]]>
</mx:Script>
<mx:TextInput id="docLabel" text="{tmpString}" change="onChange()" />
I think bidirectional data binding is a new feature in Flex 4.
This is straight from Adboe http://opensource.adobe.com/wiki/display/flexsdk/Two-way+Data+Binding, and it's Flex 3 too!
I created custom controls that programmatically create two-way bindings when given a provider object that has a suitable property whose name matches the control's id. Here's an example for a TextInput:
public class BoundTextInput extends TextInput
{
// some code omitted for brevity:
// Create getter / setter pair, call invalidateProperties()
// and set internal flag for efficiency
// create bindings in commitProperties:
override protected function commitProperties():void
{
if (this._fProviderChanged) {
this._fProviderChanged = false;
if (null != this._provider && this._provider.hasOwnProperty(this.id) && this._provider[this.id] is String) {
// this is the core bit
BindingUtils.bindProperty(this, "text", this._provider, this.id);
BindingUtils.bindProperty(this._provider, this.id, this, "text");
}
}
// Normally, you call the overridden method first,
// but we want to see the values initialized by the new
// binding right away, so we first create the bindings
// and then commit all inherited properties
super.commitProperties();
}
}
This is an example of how I use it inside one of my other components (a popup dialog). The data property is set to an instance of the appropriate model class, which is always a dumb, [Bindable] container.
<?xml version="1.0" encoding="utf-8"?>
<PopUp xmlns="com.econemon.suite.gui.components.*" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Form width="100%" height="100%" >
<mx:FormHeading label="Server-URL" />
<mx:FormItem label="URL" >
<!--
If it is available, and of type String, data.urlServer
is bound to the text property of this TextInput
-->
<BoundTextInput id="urlServer" provider="{this.data}"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="OK" click="this.submit(event)" />
</mx:FormItem>
</mx:Form>
</PopUp>

Resources