Event registrer on children rather than parent - actionscript-3

Hopefully a quick question here. I have setup a "LayoutPage" custom class (based on MovieClip) and I am attemptimg to create a "selected" behaviour.
When I assign my "addEventListener(MouseEvent.CLICK,toggleSelection)" from within my custom class, everything works as expected, clicking any object of that class does display the correct behaviour.
Now, I would like to extend the functionality by adding keyboard modifyer to either extend the selection or replace it.
For this, I thought of moving the "addEventListener" out of the class and put it inside the parent instead (my "PageLayout" class where all the "LayoutPage" live). But by doing so, the click event no longer register on the "LayoutPage" class but rather on its individual children (Page icon, Page number text field, Page Highlight shape, etc.)
Can anybody explain why this is happening and how I can circumvent it?
TIA

This should be happening no matter where you put your addEventListener. It is because mouseChildren is switched on by default. It is probably best to turn it off inside your LayoutPage class like so:
myLayoutPage.mouseChildren = false;
The actual issue is that use are probably using currentTarget to reference the item that was clicked on in your event handler method. Take a look at the descriptions for currentTarget and target to get a good idea of how they differ.
A good option would be to add your listener at the PageLayout level, but add it specifically to each LayoutPage child like so:
myLayoutPage.addEventListener(MouseEvent.CLICK, toggleSelection);
This way you can just use target in your handlers. But it would probably be best to still switch mouseChildren to false on each of your LayoutPage instances.

Related

Make resizable methods makes input fields not clickable

I've really strange behavior and I spent a couple of days to try to figure out what is a problem.
MooTools methods makes my input fields not clickable, and I don't know why.
$$('.class1.class2').makeResizable({
});
Above piece of code needs to make all children of div which has class 'class1' & 'class2' to be re-sizable, and that works perfectly but beside that it also makes input fields not clickable.
Does anybody had the similar problem?
Any kind of help will be appreciate.
Thanks
so the problem is that you have no handle passed in. when you fail to do that, the whole element becomes a listener for mousedown and attempts to click into any child element will not bubble correctly, resulting in weird behaviour.
I also found a bug in the logic for adding handlers, which seems to not evaluate handles correctly
https://github.com/mootools/mootools-more/blob/master/Source/Drag/Drag.js#L66 is wrong on many levels - it expects a collection / array of elements but looks in the global document and not child elements - yet it ends up picking element anyway and ignores passed collections like $$('.class1 .resizer')
i did a small change to accept a string for a child selector and added a resize handler.
http://jsfiddle.net/pbu5uzho/
you should submit this bug to https://github.com/mootools/mootools-more/issues though i doubt it will get picked up.
$$('.class1').makeResizable({
handle: '.resizer'
});
the change I did to make this work was:
this.handles = this.element.getElements(this.options.handle);
alternatively, you can use something like InteractJS to handle this.
I'm not 100% sure but can you try this one
I think you are missing (,)
$$('.class1,.class2').makeResizable({
});

Children of Children of MovieClip not showing up when MovieClip is added to stage?

This problem seems very simple to me, but I've been unable to fix it, or find an answer anywhere.
This is in a class constructor for a class called block, block_maker is the object that called the constructor, an instance of level.
this.bitmap = new Bitmap(this.bitmap_data);
this.addChild(this.bitmap);
this.block_maker.stage_foreground.addChild(this);
In level, stage_foreground is added to the stage, but nothing appears. trace(stage_foreground.numChildren); shows the correct count of children, and var temp = (this.stage_foreground.getChildAt(0)); trace(temp.numChildren); correctly but the children OF the children don't actually show up, the stage just stays blank.
When I change the above code to
this.bitmap = new Bitmap(this.bitmap_data);
this.block_maker.stage_foreground.addChild(this.bitmap);
the blocks appear on the stage, as children of level_instance.stage_foreground, but with this method, the bitmaps aren't appropriately positioned, as they have no position data. I can simply give this.bitmap x and y positions, and it works, but I am curious as to why it won't work when just adding the bitmap as a child to the block and then adding that as a child to stage_foreground.
I've tried replacing this.bitmap with a number of other object classes, such as a temporary MovieClip I made, or a Shape, but nothing shows up, so I know it has nothing to do with it being a Bitmap.
As you stated
This is in a class constructor for a class called block, block_maker
is the object that called the constructor, an instance of level.
this.bitmap = new Bitmap(this.bitmap_data);
this.addChild(this.bitmap);
this.block_maker.stage_foreground.addChild(this);
The level class needs to to extend a display object for it to show up.
In other words
"this"
has to be a display object or extend it in some form.
The reason this doesn't work.
this.block_maker.stage_foreground.addChild(this);
and this does
this.block_maker.stage_foreground.addChild(this.bitmap);
Is because "this" is not a display object but "this.bitmap" is.
The DisplayObject class is the base class for all objects that can be placed on the display list.
First of all, even though it's not neccesary, I'd suggest to make a classname start with a capital letter, and vars always start with a lower-case letter. It's a common 'rule' in AS3 that's mainly to avoid confusion.
The problem most likely lies within you use of this; what you're doing is adding this into this. It seems to me it's not a proper way of coding.
Also, since all of the other attempts didn't work; have you tried to make the var you want ot add a public static var?

AS3 Custom contextMenu to children

I have create a custom contextMenu using AS3 and can apply that to the stage. Any movie clip I place onto the stage does not inherit the contextMenu from the stage, i.e. they display the default contextMenu.
How do I apply my custom contextMenu to every child in my application?
[edit]
This is a simplified version of what I have in my main.as file:
var my_menu:ContextMenu = new ContextMenu();
my_menu.hideBuiltInItems();
var my_copyright = new ContextMenuItem("Copyright - 2012");
my_copyright.enabled = false;
my_copyright.separatorBefore = true;
my_menu.customItems.push(my_copyright);
stage.contextMenu = my_menu;
If I right-click on the stage then I get the copyright. If I add a movieclip (or anything else) to the stage then right-click on that, then I get the default context-menu.
[edit]
I have found the problem, and fixed it. I was adding a background image using stage.addChildAt(mc, 0);. For some reason this removes the context menu. Placing the child at 1 fixes this and allows everything to inherit the contextMenu.
Before: http://richard.parnaby-king.co.uk/examples/stackoverflow/stackoverflow.swf
After: http://richard.parnaby-king.co.uk/examples/stackoverflow/stackoverflow-after.swf
I am changing the purpose of the bounty - can someone explain WHY this happens!?
Ok, so after a bit of testing this is what I have. I can't say it's that definitively, as flash doesn't give the events for right-click, so it's only a guess, but it seems to hold up.
On a side note, you can't add a context menu to the stage, it won't allow it, so the lowest item you can add it to is the document class
When you right-click on a DisplayObject, it'll look for a ContextMenu on that object. It it doesn't find one, it'll continue on up the hierarchy for that object looking for one, stopping when it finds one. Something like this:
stage
- document (has context menu1)
- parent (has context menu2)
- child
- parent2
In this example, if you right click on child, there's no menu, so it looks to parent. Here it finds context menu2 so it shows that. However if you right-click on parent2, there's no menu, so it looks to document and here it finds context menu1.
There seems to be a bit of a hack though when you right-click somewhere else on the stage (i.e. somewhere with no graphics). In this case, as the stage can't have a ContextMenu (or at least you can't set one), it seems to decide to use the context menu of the child at depth 0 (normally the document class).
When you added your background image at depth 0, you were bumping up your document class to depth 1. Your hierarchy now looks something like this:
stage
- bg
- document (has context menu1)
- parent (has context menu2)
- child
- parent2
I'm assuming you're adding your context menu to the document class (in this example context menu1), so unless your document class has some graphics in it, your event would search up to the stage, find no context menu, then try to look for the context menu of child 0 - in this case bg which doesn't have one.
You can test this by drawing something in the graphics object of your document class (or clicking on one of the nested elements). If you right click on the graphics, you'll see your custom menu, even though bg is at depth 0. Alternatively, you can add another menu to bg to see what I mean.
The answer to your why really is subjective to what else you add into the stage & their order.
I could quote 2 points from the adobe live docs relating to the same :
An index of 0 represents the back (bottom) of the display list for
this DisplayObjectContainer object.
If you specify a currently occupied index position, the child object
that exists at that position and all higher positions are moved up one
position in the child list.
I think if you properly analyse all that is added onto the stage, you yourself might get the answer.
try changing stage.contextMenu = my_menu; to just contextMenu = my_menu;

Show itemRenderer in specific DataGrid rows... others empty

I have a DataGrid populated via an Array. The last column in the DataGrid uses an ItemRenderer (Button). I want to show the Button in certain rows but not in others (leave those empty). I've looked everywhere for an example or even a clue how to do this (tried labelFunction on DG, etc.) but can't find anything about it. Any help would be appreciated. Thanks!
Okay... with (lots of) help, figured it out.
First off, I'm not sure why the itemRenderer requires a container but it does. The array must also be checked from the itemRenderer and not from the main application... again, I don't know why since the debugger shows it going through the exact same loop/events, etc.).
If interested here's the relevant parts of the code:
Main App:---
{col1:'', col2:'', col3:'', col4:'', col5:'', col6:'', col7: '', col8:'', col9:'', col10:'', col11:'yo'}];
public function initData():void
{ xferSchedule.dataProvider = schedArray; }
]]>
an item renderer does not have to be a container, it has to implement IDataRenderer (a Button does not). One could extend Button and implement this interface to get a simple button renderer. If you want it to display conditionally, you will accomplish this by handling those conditions within the renderer based on the data.
Now this might get slightly complex. I would recommend you to define you an XML instead of Array of Objects. If the node has the type property button, then it would create button at that cell whose value type is button.
How to create a button dynamically inside a grid which is yet again dynamic?
This might end into the whole component being dynamic.

What's the best way to hide a tab in a TabNavigator?

I'd like to conditionally hide a tab in a TabNavigator. It seems that setting visible doesn't work properly (presumably because this is how the TabNavigator hides the tabs that aren't currently selected).
What's the right way to do this?
You can do this by making use of TabNavigator's getTabAt() method which returns the Button that makes up the visual tab. You can then set that Button's visible property. It's a little tricky to get this setup with a bindings, but it's doable.
You could also consider just disabling the tab instead, which you can do by setting enabled on the corresponding TabNavigator child (for which visible didn't work).
What do you mean by hide? If you actually mean remove, then just take your array that's bound to the data in the TabNavigator, and remove the applicable element from it.
If you want to just have them removed temporarily, create a component of your own that encapsulates the TabNavigator and has an array of removed tabs and an array of actual tabs. Then handle this as you see fit.
You might want to check out the flexlib project. They have a component called SuperTabNavigator that adds a lot of functionality to the base Flex TabNavigator, including hiding tabs (I think).
If you do have to create your own component, though, it's a bit more tricky. The thing to know is that "tabs" are actually specially styled buttons, contained within a TabBar component (the TabBar is then contained within the TabNavigator). What you'll have to do then, is subclass TabNavigator and have some property on your views (i.e. the canvases, etc. that are added to the TabNavigator) that is bound to the visible and includeInLayout properties of the TabBar buttons.
In essence, what you'll have is something like:
BindingUtils.bindProperty( tabButton, "visible", view, "someProperty" );
BindingUtils.bindProperty( tabButton, "includeInLayout", view, "someProperty" );
I don't know about TabNavigator, but in other containers, you can set the includeInLayout property to false and it will be ignored. You probably still need to combine it with visible.
var secondTab = tabNavigator.removeChildAt(0);