Flex: Delete visual element - apache-flex

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>

Related

Draw line in Flex in ActionScript

i really don't understand what i am doing wrong:
It's simple example, but when i click on the button nothing happens..
<?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[
private function drawLine():void
{
var myShape:Shape = new Shape();
myShape = new Shape() ;
myShape.graphics.lineStyle(2, 0x990000, .75);
myShape.graphics.moveTo(100, 100);
myShape.graphics.lineTo(25, 45);
this.addChild(myShape);
}
]]>
</fx:Script>
<!--<mx:Label text="Hello World"/>-->
<mx:Button label="Click" click="drawLine()" />
</s:Application>
Use SpriteVisualElement for adding simple non-flex objects.
<s:SpriteVisualElement width="500" height="500" id="spr"/>
spr.addChild(myShape)

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.

Flex 4: Event Listener created, but not being called?

I'm trying to call an event I've created in another component. I've added trace() into my methods so I can see what's being called. Everything except for the event listener (myEvent) is being called. Can anyone tell me why this is please?
Any help would be greatly appreciated. Thanks in advance.
// TestApp.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"
xmlns:com="com.*"
creationComplete="initApp()">
<fx:Script>
<![CDATA[
import com.MyPopUp;
import mx.managers.PopUpManager;
protected function initApp():void
{
var popUp:MyPopUp = new MyPopUp();
PopUpManager.addPopUp(popUp, this);
}
]]>
</fx:Script>
<com:MyComp/>
</s:WindowedApplication>
// MyComp.mxml (component)
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup 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%"
creationComplete="initComp()">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.DynamicEvent;
protected function initComp():void
{
trace('init MyComp()');
this.addEventListener('myEvent', myEvent);
}
private function myEvent(event:DynamicEvent):void
{
trace('myEvent()');
Alert.show('Event Called!', 'Success');
}
]]>
</fx:Script>
</s:VGroup>
// MyPopUp.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.events.DynamicEvent;
import mx.managers.PopUpManager;
private function call(event:MouseEvent):void
{
trace('call()');
PopUpManager.removePopUp(this);
var evt:DynamicEvent = new DynamicEvent('myEvent');
evt.value1 = '1234';
dispatchEvent(evt);
}
]]>
</fx:Script>
<s:Button click="call(event)" label="Call Event"/>
</s:Group>
MyComp and MyPopup aren't in the same display list hierarchy, so the bubbling event isn't being seen.
If you are wanting to send messages across components in this way consider using some sort of global event dispatcher, using using a shared model between the two components in order to see data changes.

Remove child content from ViewStack in Flex 4

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

Working on a Global Search tool - Just like on MAC

Hi I am working on a search tool for my website in Flex. I want it to work exactly like the "Spotlight" tool on MAC desktop. "http://www.recipester.org/images/6/66/How_to_Use_Spotlight_to_Search_on_Mac_OS_X_42.png" The link is to an image of spotlight.
I want to create almost the same thing in FLEX.
What I currently have is a "Autocomplete" box, and I get all the data I want in it. Code for the autocomplete is below:
<auto:AutoComplete borderStyle="none" id="txt_friends_search"
textAlign="left" prompt="Search Friends" dataProvider="{all_friends_list}"
allowEditingNewValues="true" allowMultipleSelection="true" allowNewValues="true"
backspaceAction="remove" labelField="label"
autoSelectEnabled="false" matchType="anyPart"
height="23" right="400" top="1" dropDownItemRenderer="{new ClassFactory(weather.index_cloud_global_search_item_renderer)}" />
And my ItemRenderer looks like :
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox
xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%" height="100%"
verticalGap="0" horizontalGap="0"
creationComplete="init()"
verticalScrollPolicy="off" horizontalScrollPolicy="off"
verticalAlign="middle">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.collections.ArrayCollection;
import com.hillelcoren.utils.StringUtils;
import mx.utils.StringUtil;
import mx.events.FlexEvent;
import mx.controls.List;
public function init():void
{
}
]]>
</mx:Script>
<mx:HBox width="100%" verticalGap="0" horizontalGap="0">
<mx:HBox borderThickness="1" width="75" borderStyle="solid" horizontalAlign="left" horizontalScrollPolicy="off">
<mx:Label id="type" text="{data.type}" fontSize="12"/>
</mx:HBox>
<mx:HBox borderThickness="1" width="75" borderStyle="solid" horizontalAlign="left" horizontalScrollPolicy="off">
<!--mx:Label id="nameLabel" text="{data.label}" fontSize="12"/-->
<mx:List id="names" dataProvider="{all}"
</mx:HBox>
</mx:HBox>
<!--mx:Box id="colorBox" borderStyle="solid" width="50" height="25"/-->
<mx:Spacer width="15"/>
This shows the type and label of everything, example:
Friends ABC
Friends XYZ
Messages This is the message
Messages example for messages
Files filename1
Files filename123
I believe you get my point there.
But what I want to create is something like:
Friends ABC
XYZ
Messages This is the message
example for messages
Files filename1
filename123
MoreFiles
Can someone plz help me in this.
I actually have no idea how to move forward in this.
Let me know if you want more clarification on anything.
Regards
Zeeshan
Since you're offering a bounty, I'll submit a different answer (as the previous one is technically valid).
Step #1: Download the Adobe Autocomplete Component integrate the class into your project.
Step #2: Create a new component that is derived from AutoComplete (I called mine SpotlightField.mxml)
<?xml version="1.0" encoding="utf-8"?>
<AutoComplete
xmlns="com.adobe.flex.extras.controls.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init()"
labelField="value"
itemRenderer="SpotlightFieldRenderer">
<mx:Script>
<![CDATA[
private function init() : void
{
this.filterFunction = substringFilterFunction;
}
private function substringFilterFunction(element:*, text:String):Boolean
{
var label:String = this.itemToLabel(element);
return(label.toLowerCase().indexOf(text.toLowerCase())!=-1);
}
]]>
</mx:Script>
</AutoComplete>
Step #3: Create the ItemRenderer you want to apply to this new component (I called mine SpotlightFieldRenderer.mxml). Note that the code is the same as the previous example, but I'll post it again for completeness.
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
]]>
</mx:Script>
<mx:HBox width="100%">
<mx:Label width="100" text="{data.type}" />
<mx:Label text="{data.value}" />
</mx:HBox>
</mx:Canvas>
Step #4: Update the AutoComplete.as class as follows:
/**
* #private
* Updates the dataProvider used for showing suggestions
*/
private function updateDataProvider():void
{
dataProvider = tempCollection;
collection.filterFunction = templateFilterFunction;
collection.refresh();
sort_and_filter(collection);
//In case there are no suggestions, check there is something in the localHistory
if(collection.length==0 && keepLocalHistory)
{
var so:SharedObject = SharedObject.getLocal("AutoCompleteData");
usingLocalHistory = true;
dataProvider = so.data.suggestions;
usingLocalHistory = false;
collection.filterFunction = templateFilterFunction;
collection.refresh();
}
}
private function sort_and_filter(source:Object):Object
{
if (source && source.length > 1) {
trace (source.length);
source.sortOn('type', Array.CASEINSENSITIVE);
var last:String = "";
for each(var entry:Object in source) {
var current:String = entry.type;
if (current != last)
last = current
else
entry.type = "";
last = entry.type;
}
}
return source;
}
You'll notice that the sort_and_filter function is defined, and called on the collection within updateDataProvider. The app now looks like this:
That's it. The sample application now looks like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">
<mx:Script>
<![CDATA[
[Bindable]
private var items:Array = [
{ type:'friends', value:'abc' },
{ type:'friends', value:'xyz' },
{ type:'messages', value:'this is the message' },
{ type:'messages', value:'example for messages' },
{ type:'files', value:'filename1' },
{ type:'files', value:'filename123' },
];
]]>
</mx:Script>
<local:SpotlightField dataProvider="{items}" width="400" />
</mx:Application>
Let me know if you have any further questions. There is still a bit of work to do depending on how you want to display the results, but this should get you 95% of the way there ;)
You may want to try something like this. This is just a sample I whipped up, but the basics are there for you to apply to your solution. What this is doing is creating a custom item render (as you've already done), but the container that it's rendering, it adjusts the data set slightly within set dataProvider so that it sorts and filters.
Obviously, you can expand upon this even further to add common icons, formatted text ... etc. The renderer has an explicit width set for the first "column" text. This is to better align results, but should probably be done while the list is being built (based on the string lengths of the values in the result set). Cheers ;)
Application.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">
<mx:Script>
<![CDATA[
[Bindable]
private var items:Array = [
{ type:'friends', value:'abc' },
{ type:'friends', value:'xyz' },
{ type:'messages', value:'this is the message' },
{ type:'messages', value:'example for messages' },
{ type:'files', value:'filename1' },
{ type:'files', value:'filename123' },
];
]]>
</mx:Script>
<local:SpotlightComboBox
dataProvider="{items}"
width="400" />
</mx:Application>
SpotlightComboBox.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox
xmlns:mx="http://www.adobe.com/2006/mxml"
itemRenderer="SpotlightComboBoxItemRenderer">
<mx:Script>
<![CDATA[
override public function set dataProvider(value:Object):void
{
super.dataProvider = sort_and_filter(value as Array);
}
private function sort_and_filter(source:Array):Array
{
if (source && source.length > 1) {
source.sortOn('type', Array.CASEINSENSITIVE);
var last:String = "";
for each(var entry:Object in source) {
var current:String = entry.type;
if (current != last)
last = current
else
entry.type = "";
last = entry.type;
}
}
return source;
}
]]>
</mx:Script>
</mx:ComboBox>
SpotlightComboBoxItemRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
]]>
</mx:Script>
<mx:HBox width="100%">
<mx:Label width="100" text="{data.type}" />
<mx:Label text="{data.value}" />
</mx:HBox>
</mx:Canvas>

Resources