Flex4 Right Click Spark List using ContextMenu() - apache-flex

I would like to add custom right clicks to a number of spark list controls.
I have tried the following as an item renderer. (as per the flex 4 cook book).
Full Render code here http://pastebin.com/Kx8tJ1cY
When I right click on the Spark List I simply get the Adobe Default Context menu.
This is the same default behaviour I had before I added any code to this.
Could anyone tell me how to add right clicks to List Items in Flex 4.
Please and Thank you.

I found the problem/solution. You cant use context menus if there are Vboxes or Tab Navigators. Which is insane because it means I cant do relative layout properly or decent variable width design.
Quoted from: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/ui/ContextMenu.html
For example, if a DataGrid control is a child of a TabNavigator or VBox container, the DataGrid control cannot have its own context menu.

Christopher Huyler posted something similar (source code available here). From the article:
Start out by grabbing the Javascript code from Google's code repository.
Step 1 – Setup custom context menu code
Create a new Flex project in Flex Builder. Copy rightclick.js and swfobject.js into the html-template folder of your project. From here, I had to make several changes…
I modified the RightClick.init() function to accept an object and container value as input. This allows me to pass in the name of the application as the object instead of having it be called the same thing every time.
I included rightclick.js and swfobject.js in the header of index.template.html.
I added a new div to the body called “flashcontent”.
I added an onload handler to the body tag to initialize RightClick
I replaced AC_FL_RunContent(…) with new SWFObject(…) making sure to maintain all template variables.
After making these changes, I verified that no right-click context menu appears in my application.
Step 2 – Listen for the rightClick event
Next I added a few lines to the main mxml file of my application to listen for the ExternalInterface event that will be dispatched when I right-click my appliction.
private function handleCreationComplete():void
{
ExternalInterface.addCallback("rightClick", handleRightClick);
}
private function handleRightClick():void
{
Alert.show("Right Click Success!");
}
Step 3 – Dispatch an event to the correct object
Getting the event to the main application is easy, but we actually want the appropriate child object to be notified when the right-click event occurs. Since I am not using any double-click events in my application I decided I would treat every right-click event like a double-click event. Users without a two button mouse (aka Mac users) can simply double-click to get the same menu while users with a two button mouse just have to right-click. Here is how I make sure the event is dispatched to the appropriate object.
private function handleRightClick():void
{
var objects:Array = systemManager.getObjectsUnderPoint(
new Point(mouseX,mouseY));
if (objects.length>0)
{
var object:Object = objects[objects.length-1];
var relatedObject:InteractiveObject;
if (object is InteractiveObject)
relatedObject = object as InteractiveObject;
else if (object.parent && object.parent is InteractiveObject)
relatedObject = object.parent;
var event:MouseEvent = new MouseEvent(
MouseEvent.DOUBLE_CLICK,true,false,mouseX,mouseY,
relatedObject);
object.dispatchEvent(event);
}
}
I hope this helps!

Related

Dialog not displaying propagated model data

In my UI5 application, I have an i18n.properties file with keys and values:
#XMSG:
qty=Quantity
And I'm using this property value in a dialog box as title
onUpdateDialog: function() {
var that = this;
var dialog = new Dialog({
title: "{i18n>qty}",
// ...,
});
dialog.open();
},
But when I run my application, the dialog box title is not getting displayed:
When I use text values from i18n property file somewhere else it's getting displayed.
ManagedObjects, that are created by the application code imperatively outside of the framework-managed features (Such creating an instance of sap.m.Dialog in a Controller code without using the API loadFragment), have to be added to the model delegation chain manually in order to make use of the propagated models.
In order to do so, add the created instance to the parent's <dependents> aggregation. E.g.:
this.getView().addDependent(myDialog); // myDialog is now aware of the "i18n" model
From API Reference:
Special aggregation dependents is connected to the lifecycle management and databinding, but not rendered automatically and can be used for popups or other dependent controls or elements. This allows the definition of popup controls in declarative views and enables propagation of model and context information to them.
In order to use texts in the controller you need to fetch the text first, like so:
this.getOwnerComponent().getModel("i18n").getResourceBundle().getText("qty")
this will be the dialog inside the dialog, so declare a that before the dialog and change this to that..
var that = this;
that.getOwnerComponent().getModel("i18n").getResourceBundle().getText("qty")
Hope this solves your issue..
At the point of opening the Dialog, it doesn't know the i18n model. You need to provide the model to the dialog by calling dialog.setModel(this.getModel('i18n'), 'i18n') before opening the dialog.

Flex - How to get the parent of a custom grid column filter editor and open a pop up window?

I am trying to figure out how to open a pop up window in my Air application, in a secondary Window, instead of the main application window.
I am using the ReusableFX components, which include a custom DataGrid with filtering and other capabilities. The filtering feature displays a pop up window via PopUpManager when you click on the top of a column in the grid.
PopUpManager.addPopUp(this, FlexGlobals.topLevelApplication as DisplayObject);
The problem is that the pop up window opens in the main application - I am assuming because of the 'topLevelApplication' reference.
So, I need a way to open this window in the current Air "s:Window".
I am assuming I need a way to walk up : this.parent.parent or this.owner.owner - though I have tried that and it did not seem to work (it said null reference).
OR, is there a way to get the current top most window / component (NOT the main application / window)?
Update:
I decided to create a new project for the component, and add in the Air libraries. Now I am able to access the "NativeApplication.nativeApplication.activeWindow" call. That gives me the correct Air window. However, it does not seem to be working:
PopUpManager.addPopUp(this, NativeApplication.nativeApplication.activeWindow as DisplayObject);
My popup does not appear. I am assuming because "activeWindow" is not actually a DisplayObject? (so how do I get the DisplayObject if that's the case?)
Update:
Could it be that I am a victim of this adobe bug? (found here originally)
Well, I came up with some changes that seem to work, though there is probably a much cleaner way to do this - I was just not able to figure a way to get a reference to the current air application window except this way (this is using the ReuableFX custom flex component by the way):
First, in my custom DataGridColumn component, I added a public property
public var pApp:Object;
Next, I modified the DropDownFilterHeaderRenderer (extends HBox , implements IListItemRenderer), showFilterDropDown method and right before it calls dropDown.startEdit(column); , added:
column.pApp = parentApplication;
Finally, I modified DropDownFilterEditor (which extends FilterEditorBase), the method startEdit(column:MDataGridColumn) (the previous PopUpManager was calling FlexGlobals.topLevelApplication, which is not the correct window when opening a s:Window in an Air native application:
var editorInstance:Object = _editor.parent;
var columnInstance:Object = editorInstance.column;
var parAppInstance:Object = columnInstance.pApp;
PopUpManager.addPopUp(this, parAppInstance as DisplayObject);

Adobe Flex PopUpManager -- multiple instances of a TitleWindow opened

Setup: My Flex application is one consisting of several "subapps". Basically, the main application area is an ApplicationControlBar with buttons for each of the subapps. The rest of the area is a canvas where the subapps are displayed. Only one subapp is visible at a time. When switching between subapps, we do a canvas.removeAllChildren(), then canvas.addChild(subAppSwitchedTo). It's essentially a manual implementation of a ViewStack (the pros and cons of which are not the topic of this, so refrain from commenting on this).
Problem: In one of my subapps (let's say subapp "A"), I have a search function where results are displayed in a TitleWindow that gets popped up. Workflow is like enter search criteria, click search button, TitleWindow pops up with results (multiple selection datagrid), choose desired result(s), click OK, popup goes away (PopUpManager.removePopUp), and continue working. This all works fine. The problem is if I switch to a different subapp (say "B" -- where A gets removeAllChildren()'d and B gets added), then switch back to A and search again, when the results TitleWindow pops open, there will be TWO stacked on top of each other. If I continue to navigate away and back to A, every time I search, there will be an additional popup in the "stack" of popups (one for each time A gets addChild()'d).
Has anyone else experienced this? I'm not sure what to do about it and it's causing a serious usability bug in my application. Does this ring any bells to anyone? It's like I somehow need to flush the PopUpManager or something (even though I'm correctly calling removePopUp() to remove the TitleWindow). Please help!
EDIT
Flex SDK = 4.5.1
// Subapp "A"
if (!certificateSearchTitleWindow)
{
certificateSearchTitleWindow = new CertificateSearchTitleWindow;
certificateSearchTitleWindow.addEventListener("searchAccept", searchOKPopupHandler);
certificateSearchTitleWindow.addEventListener("searchCancel", searchClosePopupHandler);
}
PopUpManager.addPopUp(certificateSearchTitleWindow, this, true);
My guess is that the popup is removed from the main display list when you remove its parent (this in the PopUpManager.addPopup() method), but not from its parent display list. Why don't you listen, in your subapps, to the Event.REMOVED event, and then remove your popup ? That would be :
private var pp:CertificateSearchTitleWindow;
private function onCreationComplete():void
{
addEventListener(Event.REMOVED, onRemovede);
}
private function addPopUp():void
{
if (!pp) {
pp = new CertificateSearchTitleWindow();
PopUpManager.addPopUp(pp, this, true);
}
}
private function onRemoved(event:Event):void
{
if (pp) {
PopupManager.removePopUp(pp);
pp = null;
}
}
Thank you to those who gave suggestions. It turned out I was re-registering an eventListener over and over.
I am using a singleton to act as "shared memory" between the subapps. I was setting singleton.addEventListener(someType, listener) in subapp A's creationComplete callback. So everytime I navigated back to A, the creationComplete was running and re-adding this listener. After the search, the listener method (that opened the popup) was being called multiple times, i.e., as many times as the event had been added.
xref: http://forums.adobe.com/message/3941163

returnedObject property

I'm programming in Flex Builder Burrito for an mobile application.
I'm trying to get a variable from navigator.PopView()
and i found the following site: adobe View and ViewNavigator
On that page is written that you can get to an returnedObject:
The ViewNavigator will save this object internally, and the new view can access it from with the navigator.returnedObject property.
The problem is when I want to acces the returnedObject flash builder doesn't seem to find that even the package isn't found.
I've found my problem on an other site.
There it's plain simple explained.
Do the override public function createReturnObject():Object.
On the page where it needs to be send back.
Then on the popped view, you can acces it by returnedObject.
On same page next lines are
The property is a ViewReturnObject
which contains the object that was
returned
and the context in which the removed view was pushed (See Setting
the View Context).
ViewNavigator.poppedViewReturnedObject
is guaranteed to be set by the time
the new view
receives the add event and will be destroyed after the view receives its
viewActivate
event.
and also a NOTE
Note, the return object is only stored when a view is popped of
the navigation stack
or replaced through the use of the pop and replace navigation
operations (e.g.,
replaceView, popView, etc...). It will be cleared after the new view
receives its
ViewNavigatorEvent.VIEW_ACTIVATE event.
I think should try function to get popuped view poppedViewReturnedObject of ViewNavigator
Its description is also on same page
public function get poppedViewReturnedObject():ViewReturnObject
Hopes that help

Flex and fake Mxml initialisation without actually showing the component, (more insise)

I have a TitleWindow mxml class wich has several components, and listeners.
On its creationComplete and init state i add some listeners which listen for events on its gui.
This TitleWindow is only shown when the user click on a "button", i made TitleWindow a singleton with the following code:
public static function getInstance():MyWindow
{
if ( MyWindow.singleton )
{
return MyWindow.singleton;
}
else{
MyWindow.singleton = new MyWindow();
return MyWindow.singleton;
}
}
I needed a singleton because the user will call this window several times as much as he wants and i only need one.
The problem is the following on some special external events i need to "modify" some listeners (remove listeners and add new ones) on a button from MyWindow, before it was even shown once.
I still have MyWindow.getInstance() in memory when my application starts up.
However adding /removing listeners does not seem to have any effect if he actual rendering of the components did not happen, event when using the following code on app startup.
myWindow= MyWindow.getInstance();
myWindow.initialize();
Not suprisingly if i "show" ('render') the myWindow at least once then the events modifications on the myWindow instance works perfectly.
How can i fake the complete initialisation of this component without showing it on startup ?
Thanks !
Which sort of a container holds your button? If you are using a Multiple View Container you can try setting the creationPolicy to all. Single View Containers create all their children in one go and you shouldn't face this problem.
From Flex 3.0 docs I could retrieve this:
The default creation policy for all containers, except the Application container, is the policy of the parent container. The default policy for the Application container is auto.
This looks like the cause for all your troubles.
Update: I did not mention this earlier, since I thought this was to be expected :) Setting the creationPolicy to all makes your application load more slowly. So, read up on Ordered Creation -- this technique helps you to choose if the controls are displayed all in one go (which is the default behavior, after all of the controls have been created) or step-by-step, as and when they are created.

Resources