Remove child content from ViewStack in Flex 4 - apache-flex

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"));
}

Related

Close a Callout inside a View in Flex

I have this ViewNavigator inside a callout and the callout displays a view inside it using firstView="views.ListMenusHomeView" . Now how can I close the callout from ListMenusHomeView? Hope someone can help.
Here is my code for the callout:
<?xml version="1.0" encoding="utf-8"?>
<s:Callout xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
contentBackgroundAppearance="none"
height="300" width="300">
<fx:Declarations>
<fx:XML id="menu" source="xmldata/menu2.xml" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import spark.events.PopUpEvent;
protected function back(event:MouseEvent):void {
if(viewNav.length>1)
viewNav.popView();
}
]]>
</fx:Script>
<s:ViewNavigator id="viewNav" width="100%" height="100%" firstView="views.ListMenusHomeView">
<s:navigationContent>
<s:Button label="Back" click="back(event)"/>
</s:navigationContent>
<s:actionContent>
<s:Button label="Cancel" click="close(false)" emphasized="true"/>
</s:actionContent>
</s:ViewNavigator>
</s:Callout>
You see that there is a ViewNavigator which holds the ListMenusHomeView. This is the code for the ListMenusHomeView.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Main Menu" creationComplete="onCreationComplete()">
<fx:Declarations>
<fx:XML id="menu" source="xmldata/menu2.xml" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.adobe.serializers.xml.XMLDecoder;
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
[Bindable]
private var dataArray:ArrayCollection = new ArrayCollection();
private var object:DataArray = new DataArray();
private function onCreationComplete() : void{
var decoder:XMLDecoder = new XMLDecoder();
var resultObj:Object = decoder.decode(menu);
dataArray = object.onCreationComplete(menu, menu.menuitem, resultObj, resultObj.menuitem);
}
protected function list1_changeHandler(event:IndexChangeEvent):void
{
}
]]>
</fx:Script>
<s:List id="tileLayout"
width="100%" height="100%"
verticalScrollPolicy="off" horizontalScrollPolicy="on"
pageScrollingEnabled="true" dataProvider="{dataArray}"
itemRenderer="renderers.iconList2" change="list1_changeHandler(event)">
<s:layout>
<s:TileLayout orientation="columns" requestedRowCount="3"
verticalGap="20" horizontalGap="20"/>
</s:layout>
</s:List>
Now I want to close MyCallout whenever I click an icon inside ListMenusHomeView. The function list1_changeHandler(event:IndexChangeEvent) is responsible for that one.
What should I do?
The Callout class has a close() method, so you basically just need to access the ListMenusHomeViews parentDocument (which would be your "viewNav" ViewNavigator) and its parentDocument, which should be your ListMenusHomeView.
I haven't tested it but you might fiddle around with the parentDocument, parent and owner properties to access the correct object. Try them with a simple trace and you'll be up and running in no time.

Different set of popups for a different tab

Suppose, I have a tabbed application. Can I make Popup window to appear in a given tab only? So, if I change a tab, the related popup(-s) hides. So far, I haven't found any solution for this. So any idea would be greatly appreciated :)
You will have to handle different sets of popups by yourself : Flex can only add and remove given popups which will be displayed at the topmost level of your app.
EDIT : Here's a little sample.
<?xml version="1.0"?>
<!-- containers\navigators\TNSimple.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="onCreationComplete()"
>
<fx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import spark.components.TitleWindow;
import mx.events.IndexChangedEvent;
private var popups:Array = [];
private function onCreationComplete():void
{
popups = [[],[],[]];
}
private function createPopup():void
{
var foo:TitleWindow = new TitleWindow();
PopUpManager.addPopUp(foo, this);
PopUpManager.centerPopUp(foo);
popups[nav.selectedIndex].push(foo);
}
private function onTabChange(event:IndexChangedEvent):void
{
var i:int;
var oldArray:Array = popups[event.oldIndex];
for (i = 0; i < oldArray.length; i++) {
PopUpManager.removePopUp(oldArray[i]);
}
var newArray:Array = popups[event.newIndex];
for (i = 0; i < newArray.length; i++) {
PopUpManager.addPopUp(newArray[i], this);
}
}
]]>
</fx:Script>
<mx:TabNavigator id="nav" borderStyle="solid" x="50" y="50" change="onTabChange(event)">
<mx:VBox label="Accounts"
width="300"
height="150">
<mx:Button label="pop" click="createPopup()"/>
</mx:VBox>
<mx:VBox label="Stocks"
width="300"
height="150">
<mx:Button label="pop" click="createPopup()"/>
</mx:VBox>
<mx:VBox label="Futures"
width="300"
height="150">
<mx:Button label="pop" click="createPopup()"/>
</mx:VBox>
</mx:TabNavigator>
</s:Application>

Dynamic Flex Form Duplication

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>

Flex: Delete visual element

I have a VGroup in my application that contains several custom components of type MyComponent. Now I have a delete method in MyComponent that should once ran delete the element from the VGroup. I know I should use parentDocument.vgroupId.removeElement() but what to pass as a reference?
Note: I want to do the delete within a method from MyComponent
UPDATE: here is my source:
In my main application
<s:VGroup id="vgroupId" width="100%" height="100%" />
Now I add my custom component as:
var cust:FunctionElement = new MyComponent(); // MyComponent extends spark Panel
vgroupId.addElement(cust);
And from MyComponent I call
parentDocument.vgroupId.removeElement(this) // get this error => TypeError: Error #1034: Type Coercion failed: cannot convert global#5ed30d1 to mx.core.IVisualElement.
If I cast it as this as IVisualElement I get an error that it is equal to null
This example will show how you can do it..
ExampleApp.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">
<fx:Script>
<![CDATA[
protected function button1_mouseUpHandler(event:MouseEvent):void
{
vgroup.addElement(new MyComponent());
}
]]>
</fx:Script>
<s:VGroup id="vgroup" top="30" />
<s:Button label="Add" mouseUp="button1_mouseUpHandler(event)"/>
</s:Application>
Define MyComponent.mxml like this...
<?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="35">
<fx:Script>
<![CDATA[
import spark.components.VGroup;
protected function button1_mouseUpHandler(event:MouseEvent):void
{
// A few useful traces to see what's what and where.
trace(this);
trace(this.parent);
trace((this.parent as VGroup).getElementIndex(this));
// But all we actually need is ...
var vgroup:VGroup = (this.parent as VGroup);
vgroup.removeElement(this);
// (this.parent as VGroup).removeElement(this); // Would also work fine.
}
]]>
</fx:Script>
<s:Button mouseUp="button1_mouseUpHandler(event)" label="Kill me!"/>
</s:Group>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:s="library://ns.adobe.com/flex/spark">
<mx:Script>
import mx.core.IVisualElement;
import spark.components.Button;
private function getNewElement():IVisualElement
{
var btn:spark.components.Button = new spark.components.Button();
btn.label = "button " + myContent.numElements;
return btn;
}
private function addFirstElement():void
{
myContent.addElementAt( getNewElement(), 0 );
}
private function removeFirstElement():void
{
if( myContent.numElements > 0 )
myContent.removeElement( myContent.getElementAt( 0 ) );
}
private function removeLastElement():void
{
if( myContent.numElements > 0 )
myContent.removeElementAt( myContent.numElements - 1 );
}
</mx:Script>
<mx:Button label="addFirst" click="addFirstElement();" />
<mx:Button label="removeFirst" click="removeFirstElement()" />
<mx:Button label="removeLast" click="removeLastElement()" />
<mx:Button label="removeAll" click="myContent.removeAllElements()" />
<mx:VBox id="myContent">
</mx:VBox>
</mx:Application>

How to set Source of s:BitmapFill dynamically? (Flash Builder, Code Inside)

In Flash Builder (flex 4) I try to use next code to set selected by user (from file system) Image as a repeated background. It worked with mx:Image but I want to use cool repited capabiletis of s:BitmapFill.
BTW: Technic I use also does not work with S:BitmapImage. Also FP does not return any errors. What Shall I do with my code to make it work?
<?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:net="flash.net.*"
minWidth="955" minHeight="600" >
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.utils.ObjectUtil;
private function btn_click(evt:MouseEvent):void {
var arr:Array = [];
arr.push(new FileFilter("Images", ".gif;*.jpeg;*.jpg;*.png"));
fileReference.browse(arr);
}
private function fileReference_select(evt:Event):void {
fileReference.load();
}
private function fileReference_complete(evt:Event):void {
img.source = fileReference.data;
Alert.show(ObjectUtil.toString(fileReference));
}
]]>
</fx:Script>
<fx:Declarations>
<net:FileReference id="fileReference"
select="fileReference_select(event);"
complete="fileReference_complete(event);" />
</fx:Declarations>
<s:Rect id="backgroundRect" left="0" right="0" top="0" bottom="0">
<s:fill>
<s:BitmapFill id="img" source="#Embed('1.jpg')" fillMode="repeat" />
</s:fill>
</s:Rect>
<mx:Button id="btn"
label="Browse and preview..."
click="btn_click(event);" />
</s:Application>
Check this code:
private function fileReference_complete(evt:Event):void {
var loader:Loader = new Loader();
loader.loadBytes(fileReference.data);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderCompleteHandler);
}
private function loaderCompleteHandler(evt:Event):void{
img.source = evt.target.content;
}
So you need to use a loader in order to create the bitmap object.

Resources