I'm designing a data entry app that allows multiple entries to its subject. For example, a person might have received education from multiple institutions. Each educational entry is a form and app user can click on a button to add another entry, which is a blank but identical form.
I figure it involves states and custom form components but not sure how everything fits together. Can someone shed some lights on how to accomplish that? Some sample codes would be greatly appreciated.
Thanks in advance,
Required flex version if there is a requirement? or just going with the newest available Flex 4 code? Generally speaking this is a very easy task in Flex, you create a class definition in MXML of AnEntry.mxml which is just a TextInput (or a label and TextInput or whatever you need for each entry). In the click handler of the a button you in Flex 3 call this.addChild(new AnEntry()) or in Flex 4 call this.addElement(new AnEntry());. To submit you'd do a loop starting at 0 and going to this.numChildren and for each TextInput pass along as params to an HTTPService.
Two files below compiled against Flex 3.4
[AnEntry.mxml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Label text="Link:"/>
<mx:TextInput id="theTextInput"/>
</mx:Box>
[MainApplication.mxml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
minWidth="955"
minHeight="600">
<mx:Script>
<![CDATA[
import mx.rpc.http.HTTPService;
protected function button1_clickHandler(event:MouseEvent):void
{
var params:Object = {};
var paramCount:Number=0;
// TODO Auto-generated method stub
for(var i:Number = 0; i<numChildren; i++)
{
var currentChild:DisplayObject = getChildAt(i);
if(currentChild is AnEntry)
{
params[paramCount++] = (currentChild as AnEntry).theTextInput.text;
}
}
var httpService:HTTPService = new HTTPService();
httpService.method = "POST"
httpService.url = "http://www.shaunhusain.com/somewhere.php";
httpService.send(params);
}
]]>
</mx:Script>
<mx:Button label="Add Entry" click="this.addChild(new AnEntry())"/>
<mx:Button label="Submit Info" click="button1_clickHandler(event)"/>
</mx:Application>
Please let me know if this gets you going in the right direction, if you're a beginner at Flex search for the Flex in a week videos, they're a great tutorial to get you started on Flex development.
Amendment for Flex 4:
[MainApplication.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" minWidth="955" minHeight="600">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.rpc.http.HTTPService;
protected function button1_clickHandler(event:MouseEvent):void
{
var params:Object = {};
var paramCount:Number=0;
// TODO Auto-generated method stub
for(var i:Number = 0; i<numChildren; i++)
{
var currentChild:DisplayObject = getChildAt(i);
if(currentChild is AnEntry)
{
params[paramCount++] = (currentChild as AnEntry).theTextInput.text;
}
}
var httpService:HTTPService = new HTTPService();
httpService.method = "POST"
httpService.url = "http://www.shaunhusain.com/somewhere.php";
httpService.send(params);
}
]]>
</fx:Script>
<mx:Button label="Add Entry" click="this.addElement(new AnEntry())"/>
<mx:Button label="Submit Info" click="button1_clickHandler(event)"/>
</s:Application>
[AnEntry.mxml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Box 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:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:Label text="Link:"/>
<mx:TextInput id="theTextInput"/>
</mx:Box>
Related
I am new to flex and I am trying to open modules in a new window modal.
I have managed to load and add a module in a container ( vbox ) but what I really need is to open them in separate windows.
All posts that I could find are samples on how to load modules but nothing on how to show them.
I found a post here
Modules and Panels issue
and it looks by the screenshot exactly what I am looking for.
Thanks for your help.
I found a way of doing this.
Thanks for all the pointers
here is how I did it for all of you to see and maybe use. If you have suggestions to make it better, do not hesitate to comment.
I am using a component : collapsabletitlewindow
mainapp.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication 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="de.aggro.components.*">
<fx:Script>
<![CDATA[
import de.aggro.components.*;
private function createWindow():void{
var w:window = new window;
w.title = "Window " + container.numChildren;
container.addChild(w);
}
]]>
</fx:Script>
<components:CollapsableTitleWindowContainer id="container" width="100%" height="100%" >
</components:CollapsableTitleWindowContainer>
<s:Button buttonDown="createWindow()" label="Create Window" />
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:WindowedApplication>
window.mxml
<?xml version="1.0" encoding="utf-8"?>
<components:CollapsableTitleWindow 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="de.aggro.components.*" layout="absolute" width="400" height="300"
creationComplete="initApp()" >
<fx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
import mx.core.IVisualElement;
public var info:IModuleInfo;
private function initApp():void {
info = ModuleManager.getModule("mod.swf");
info.addEventListener(ModuleEvent.READY, modEventHandler);
/* Load the module into memory. Calling load() makes the
IFlexModuleFactory available. You can then get an
instance of the class using the factory's create()
method. */
info.load(null, null, null, moduleFactory);
}
/* Add an instance of the module's class to the display list. */
private function modEventHandler(e:ModuleEvent):void {
this.addElement(info.factory.create() as IVisualElement);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</components:CollapsableTitleWindow>
mod.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:LinkButton x="131" y="124" label="Module link"/>
</s:Module>
I need to dynamically create a LinkButton with an icon. The names of files (icons) have the format images/icon_0.png, images/icon_1.png, ... images/icon_1000.png. But I don't know the specific image for this button. I only know the index of the icon.
I tried this, with no success:
var path:String = "#Embed(source='images/icon_" + imageindex + ".png')";
myButton.setStyle("icon", path);
I get a runtime error:
Type Coercion failed:
*cannot convert "#Embed(source='images/icons/icon_427.png')" to Class*
Sorry that will not work.
Since imageindex is a compile-time variable, then embedding tag will trigger an error message.
Why not to override the button and add extra property like 'iconPath' that will expect a string path instead of a Class object. This way you can manually set (inside extended Button) the icon.source = iconPath without having to use embed.
pls try this.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" creationComplete="application1_creationCompleteHandler(event)"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Embed(source='icon_1.png')]
[Bindable]
private var linkButtonIcon:Class;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
lnkbutton.setStyle("icon",linkButtonIcon);
}
protected function button1_clickHandler(event:MouseEvent):void
{
[Embed(source='icon_2.png')]
var linkButtonIcon2:Class;
lnkbutton.setStyle("icon",linkButtonIcon2);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup>
<mx:LinkButton label="test" id="lnkbutton"/>
<s:Button label="change Icon" click="button1_clickHandler(event)"/>
</s:VGroup>
</s:Application>
I want to send some text value to my custom popup window when it pops up from main application which is having some text input and also I want to know how to retrieve data(of text input) which entered by a user in popup window. Any help is appreciated.
You can access popUp data using setter as example shows. Or make a popUp component as a global in your main application so you can refer component properties globally.
<!-- TitleWindow.mxml -->
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx" layout="absolute" width="600" title="" height="160">
<fx:Script>
<![CDATA[
public function get UserTypedData():String
{
return tiSomeText.text;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:TextInput id="tiSomeText" x="76" y="101"/>
<!-- Application.mxml -->
<mx:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx" layout="absolute" width="100%" >
<fx:Script>
<![CDATA[
public var popup:YourPopupWindow;
private function createPopUp():void
{
popup = YourPopupWindow(PopUpManager.createPopUp(this, YourPopupWindow, false));
}
private function getPopUpData():String
{
var retVal:String = "";
if (popUp != null)
{
// get data from setter
retVal = popUp.UserTypedData();
// of from TextInput
retVal = popUp.tiSomeText.text;
}
return retVal;
}
]]>
</fx:Script>
</mx:Application>
var popup:YourPopupWindow = PopupManager.createPopup(YourPopupWindow, true) as YourPopupWindow;
popup.someData = yourData;
I just don't get it with [Bindable] and updating a label
So here are my three pages, please tell me what I am doing wrong because when the listner sends the updated var to button2.mxml the var updates but the label does not redraw it.
application.mxml
<s:WindowedApplication
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:comps="components.*"
creationComplete="init();">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
public function init(){
btn1.addEventListener(MouseEvent.MOUSE_OVER, myFunction);
}
public function myFunction(e:MouseEvent){
var myPage:button2 = new button2();
var ranNum = Math.floor(Math.random() * 40) + 10;
myPage.myValue("ABC "+ranNum);
}
]]>
</fx:Script>
<comps:button1 y="0" id="btn1" width="100"/>
<comps:button2 y="100" id="btn2" width="100"/>
button1.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="128" height="72">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Button x="27" y="19" label="Button1" id="btn1" enabled="true"/>
</s:Group>
button2.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
[Bindable]
public var myVal:String = "Button2";
public function myValue(mV:String)
{
myVal = mV;
}
]]>
</fx:Script>
<s:Button x="10" y="32" label="{myVal}" id="btn2" enabled="true"/>
</s:Group>
Your function should be:
public function myFunction(e:MouseEvent){
var ranNum = Math.floor(Math.random() * 40) + 10;
btn2.myValue("ABC " + String(ranNum));
}
In the function that you have, you are creating a new button (without adding it as a child to anything) and setting the label on that button rather than the one you have already defined in your application.
You also do not necessarily need a [Bindable] variable for the label in button2.mxml but this depends on what you are accomplishing. You could just do btn2.label = mV; in the myValue() function definition alternatively.
The simplest way to do this is to remove your setter for myVal in button2.mxml and just set the value in myFunction like you would any other public variable:
myPage.myVal = "ABC " + ranNum;
The reason your code is not currently working is that you have implicitly overridden the myVal setter and are not dispatching a data change event, which is what makes binding work. When you add the [Bindable] metadata tag to a variable, the compiler automatically generates a setter for that variable with the proper event dispatching for you.
Hope that helps.
In my example below, when I click "Add Content", new stack content is loaded into the ViewStack as expected. But when I then click "Close Content", I'm expecting it to close the newly created content inside the ViewStack and switch to the "defaultContent" content.
Can anyone tell me where I'm going wrong please? Thanks in advance.
// TestProject.mxml (application)
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import com.NewContent;
private function addContent():void
{
var content:NewContent = new NewContent();
var navContent:NavigatorContent = new NavigatorContent();
navContent.id = 'newContent';
navContent.label = 'newContent';
navContent.width = Number('100%');
navContent.height = Number('100%');
navContent.addElement(content);
viewStack.addElement(navContent);
viewStack.selectedChild = navContent;
}
]]>
</fx:Script>
<mx:ViewStack id="viewStack" width="100%" height="100%">
<s:NavigatorContent id="defaultContent"
label="defaultContent">
<s:Button click="addContent()" label="Add Content"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:WindowedApplication>
// NewContent.mxml (component)
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
private function closeContent():void
{
FlexGlobals.topLevelApplication.viewStack.removeChild('newContent');
FlexGlobals.topLevelApplication.viewStack.selectedChild = 'defaultContent';
}
]]>
</fx:Script>
<s:Button click="closeContent()" label="Close Content"/>
</s:Group>
selectedChild expects the child itself, not the label.
Instead - try this:
public function removeContent():void
{
Viewstack(this.parent).selectedIndex = 0;
this.parent.removeChild(this);
}
Note - it's generally reccomended to avoid using FlexGlobals.topLevelApplication, as it leads to a very tightly coupled & fragile application.
Sorted it...
// TestProject.mxml (application)
private function addContent():void
{
var content:NewContent = new NewContent();
content.addEventListener("removeMe",onRemove,false,0,true);
var navContent:NavigatorContent = new NavigatorContent();
navContent.id = 'newContent';
navContent.label = 'newContent';
navContent.width = Number('100%');
navContent.height = Number('100%');
navContent.addElement(content);
viewStack.addElement(navContent);
viewStack.selectedChild = navContent;
private function onRemove(event:Event):void
{
var content:NewContent = event.currentTarget as NewContent;
content.removeEventListener("removeMe",onRemove,false);
viewStack.removeChild(content.parent.parent.parent);
}
// NewContent.mxml (component)
public function removeContent():void
{
dispatchEvent(new Event("removeMe"));
}