One of the coolest new features in Flash Player 7 is the support for context menus. With most of the buzz centered around the new and improved version of ActionScript, this little nugget could easily slip through the cracks. However, the user experience that it brings to RIA's is too important not to elaborate on.
As a Windows user, I'm used to right-clicking on everything. It's great to see this functionality finally available to Flash developers as well. Now the RIA experience can more closely mimic that of the desktop environment.
For example, I just built an application centered around the data grid. Users familiar with a similar desktop application had the opportunity to right-click on a row and select properties, or delete the row entirely. I was able to mimic this functionality in Flash almost exactly.. but I ran into two limitations of context menus.
- Context menus cannot be specified for clips not directly on the stage. This is kind of a bummer as you can't specify a context menu for a nested MovieClip.
- Context menus cannot have "Delete" as a menu item. You can add "Delete" as an item, however, it won't display in the menu. I thought this was a little strange and that maybe it was related to delete being a reserved word. After some testing ("class", "interface", etc), it looks like the other reserved words can be used just fine as menu items. Interesting... I changed "Delete" to "Delete Item" and the code worked fine. EDIT: Thanks to Erik Bianchi for pointing out that delete is a built in item, and you can't duplicate built-in items.
In Windows, when you right click on a row in a grid, that row becomes the selected row. In Flash, this wasn't the case. I had to use a little bit of coding magic to get roughly the same effect. Here goes!
// on stage: info_dg - datagrid, status_txt - dynamic text
// create a context menu
var cm:ContextMenu = new ContextMenu();
cm.hideBuiltInItems();
// add "delete item" to the menu - "delete" won't work as a label
cm.customItems.push(new ContextMenuItem("Delete Item", onDeleteSelected));
// called when "Delete Item" is selected in the data grid
function onDeleteSelected() {
// trick the datagrid into thinking the mouse was released so that
// moving the mouse doesn't scroll the grid
info_dg.onMouseUp();
// display a message
status_txt.text = "You chose to delete:" + info_dg.selectedItem.item;
}
// called before the context menu is first displayed
cm.onSelect = function(info_dg) {
// select the "lastOver" row when we right-click, but only
// if it is not already selected
if (info_dg.selectedIndex - info_dg.vPosition != info_dg.lastOver) {
info_dg.onRowPress(info_dg.lastOver);
}
}
// called when a row is rolled over
itemRollOver = change = function(eventObj) {
// get the index of rolled over row, and adjust for scroll position
// if the datagrid was scrolled vertically. store it in a "lastOver"
// variable
// change uses selectedIndex, itemRollOver uses index
var tmpIndex;
if (eventObj.type == "change") {
tmpIndex = eventObj.target.selectedIndex;
} else {
tmpIndex = eventObj.index;
}
eventObj.target.lastOver = tmpIndex - eventObj.target.vPosition;
}
// update the lastOver row when the selected row changes or when
// a row is rolled over
info_dg.addEventListener("change", this);
info_dg.addEventListener("itemRollOver", this);
// add some data
office_items = ["Stapler", "Rubber Band", "Thumb Tack", "Notebook", "Pen", "Pencil", "Phone"];
my_dp = new Array();
for (var i = 0; i < office_items.length; i++) {
my_dp.push({item:office_items[i]});
}
info_dg.dataProvider = my_dp;
// set up the context menu
info_dg["menu"] = cm;
The final product looks like this:
Sorry I can't offer a .fla for this one - the Data Grid is for Flash Professional only, and I don't have the ability to distribute it.
Enjoy!

You can distribute the FLA, as the SWC is protected inside; you just can't distribute the DataGrid.as file and all that it imports.
Hey Darron,
ContextMenuItem: "Items that are identical to any built-in menu item, or to another custom item, are ignored, whether the matching item is visible or not"
You can see delete if you select text and right-click. =)
I ran into this issue a while back when I wanted to use my own cut method. Hopefully in the next version items will not use their labels to identify themselves.
@Jesse - Because the DataGrid is Flash Pro only, I don't think I can distribute it. Does anyone know for sure?
@Erik - Well I'll be a son of a ... thanks for pointing that out. At least I know why it doesn't work now.
Now let's see if Macromedia fixes it for the next version. :-)
Context menus will be really cool when we can hide Parameters... and About Flash Player...
contextmenu's don't work in flash form apps?
how about an example that shows a context menu that works on a datagrid that's buried within an accordian that's buried within a movieclip.
i don't think it's possible, but then again i didn't think you could assign a context menu to a datagrid until i found this website.
:)
Sorry frank, that's not possible. Context menus can only be associated with clips that are direct children of _root (i.e. on the stage).
You can try some trickery by setting a context menu for _root, and then figuring out where the mouse coords are. If the mouse coords fall within the bounds of your data grid, then you can show the menu for the grid, but it's a workaround at best.
okay, what about placing a button behind the datagrid. would that be enough to trick flash into displaying the context menus with clips that are not direct children of _root?
p.s. don't you think it's a bit of an oversight on MM part to limit the context menus in such a fashion?
I could get a button on _root to trigger the context menu of the datagrid ok, but I couldn't get it working with the button "under" the grid visually (so you wouldn't see it). The problem is because the grid subscribes to mouse events to update the selected item, and as such, since it appears "above" the button visually, the button below it doesn't get the click.
Yes, I think it's an oversight that you can't assign a context menu to a nested movieclip. Hopefully it's been addressed in the next release.
interesting...i am having the same conversation on chattyfig and eric thibualt posted the following:
==============================================
The only way I made it work on a project with tree and datagrid components inside movieclip was to place a button under each component (with no cursor to it) like so:
_root.mc_activites.mc_datagrid and inside
- datagrid with contextual menu applied
- button with no cursor (under datagrid)
With that solution, the contexctual menu worked OK (the same with tree component)
==============================================
I'm going to have to try it and see if i can get some sort of workaround going.
basically what I need to do is allow the user to rightclick on cell within a datagrid and have specific functions available. unfortunately this request was asked for so late in the project that it would cost too much to re-do the entire project just to comply with MM context menu requirements.
any suggestions?
is there a way i can disable or trap for the right mouseclick and then display my own custom rolled contextual menu without MM's context menu being displayed?
I have a tree within a accordion and would like to have the capability to add and delete a node depending on what level you select and such with a context menu. Example:
Accordion1
-Tree root
-tree node
-tree node
Accordion2
-Tree root
-tree node
-tree node
Accordion3
-Tree root
-tree node
-tree node
I would love anyone that could figure this out and help me with it. Email me at cpigg@nitrosecurity.com.
Appreciate it!
hi daron,
I have used ur code on a project im working on . Its a playlist and when i click on a cell, i guess the onRowPress event causes the datagrid to glitch. when i hover over the bottom or top of the DG. The DG scrolls up or down. Have you had this problem. Can it be solved?
"i guess the onRowPress event causes the datagrid to glitch. when i hover over the bottom or top of the DG. The DG scrolls up or down. Have you had this problem. Can it be solved?"
Tambi, just came looking with a similar issue. I think I've worked around it by setting the selectedIndex of the datagrid rather than calling onRowPress.
Darron, thanks!
A.