How do I make a Flex Component Private?

Over on FlexCoders, Nate asked how he makes a Flex MXML Component private. I'll quote the important part of his question:


I have custom MXML component (ResourcesTree) that has a Tree inside of it. I don't want the Tree to directly be available outside the ResourcesTree Component.

His topic makes things a bit confusing. You make variables or methods private so they can't be used outside of a class. A private class would be one that you can't create an instance of? There would be no purpose in that.

Nate really wants to look into making an internal class. Internal classes can be used only within the package (AKA Directory), but not from outside.

Of course, don't go thinking that internal is not the same as private. People can extend your classes within the same package and use that internal class. I believe that the internal class can even be extended if need be.

If you are distributing a Binary SWC and want to hide the fact that you have a class in there, you can use the ExcludeClass metadata tag. This is used more than you'd think in the Flex Framework code.

Of course none of that will help you if people decompile your SWF.

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Danny Gold's Gravatar I believe what he was asking, which is something I found surprising when I started using Flex, is how you make the variable reference to the subcomponent private, like you can if you wrote the component in AS3. If I have an HBox:

<mx:HBox>
<mx:Lable id="innerLabel" />
<mx:HBox>

Anybody using my HBox component has access to innerLabel because the MXML compiler makes that variable public. If I had created this in AS3 I could have declared innerLabel to be private. Sure, someone could get a reference to it be using getChildAt(0), but at least auto-complete wouldn't expose it.
# Posted By Danny Gold | 7/23/08 10:20 AM
Jeffry Houser's Gravatar Danny,

You could be right. My interpretation of his question was that he had a SWC package with multiple classes, but only wanted to expose one of them.
# Posted By Jeffry Houser | 7/23/08 10:32 AM
Nate Beck's Gravatar Hey guys, actually Danny interpreted it the way I meant. I should have been more clear. I have a custom component that I am using.

[ResourcesTree.mxml]
<mx:Canvas xmlns:mx="..." width="400" height="300">
<mx:Script>
...
</mx:Script>
<mx:WebService details.... />
<mx:Tree id="_tree" change="{dispatchEvent(event)}"/>
</mx:Canvas>

Outside of my Resources tree, I don't want anyone to be able to access my tree component. However it's automatically compiled as public.

Say I want to add an event listener to the tree change event. I want to force people using my component to listen to the ResourcesTree and like Danny said... not the sub-component.

For example:
var myResources:ResourcesTree = new ResourcesTree();
myResources.addEventListener(Event.CHANGE, onResourceChange); // GOOD
myResources._tree.addEventListener(Event.CHANGE, onResourceChange); // BAD!

private function onResourceChange(event:Event):void
{
trace("yay captured");
}
# Posted By Nate Beck | 7/23/08 11:16 AM
Tink's Gravatar Just not possible.

You'll notice they avoid any MXML in the Flex components.

I would suggest logging a feature request, then posting the link back here so we can all stick a vote against it.

an 'accessor' tag would be a fine addition IMO.
# Posted By Tink | 7/23/08 11:30 AM
# Posted By Nate Beck | 7/23/08 11:49 AM
Jeffry Houser's Gravatar Nate,

I do not think it is easy. Once you add a component to the stage, the user can always get at it using the getChild methods. Even if the variable (AKA Component) is private or internal, it is still exposed once added to the stage.

You could override them, to not return your private component; but I find it hard to believe that would be worth the effort. I'm not sure what the implications would be for this on the rest of the framework.
# Posted By Jeffry Houser | 7/23/08 11:49 AM
Nate Beck's Gravatar Hey Jeffry,

I'm not too terribly worried about the getChild methods. Obviously there will almost always be a way to work around this. The people I'm working with have all the source for the classes / components I'm writing.

This for me is more a matter of following good OOP practices. I'm working in a multiple Flex developer environment right now, and we're writing components for all the other devs to use. I'm seeing other devs come in and directly accessing the subcomponents, which ends up causing all sorts of different bugs.

There is always going to be a way for developers to write crappy code, but I don't like being an enabler. :D
# Posted By Nate Beck | 7/23/08 11:56 AM
Danny Gold's Gravatar I don't think they would need to take it that far, but it is nice when someone is dotting down through your component if they don't see every MXML child you added. Like I said before, if you create your component in AS instead of MXML you can declare them private so they aren't quite as easy to get to.

I think adding an accessor tag would help with encapsulation of custom MXML based components. If someone is using a component I write and sees a public property, they're going to assume its safe to use it. I could move things around in a later release and hose anything they've based on my component. If I declare them private then its safe to assume noone is supposed to be monkeying with it, and if they use the getChild to grab it then I'm free to hose them in any way I see fit :-)
# Posted By Danny Gold | 7/23/08 11:58 AM
Tink's Gravatar Not having this deems accessors unimportant which just isn't true.

This doesn't only apply to items added to a displayList either. You can create more than just DisplayObjects with MXML, and these should have the ability to be truly private.
# Posted By Tink | 7/23/08 12:05 PM
Jeffry Houser's Gravatar Nate,

I think the best way to address that from a code stand point is to switch to ActionScript classes, and make the appropriate internals private variables.

There may also be a business way to address it, but creating guidelines for your team on component building / reuse; or a more documented / better documented API.

Danny / Think,

I am not understanding what an assessor tag is, or what problem is solves in this case.
# Posted By Jeffry Houser | 7/23/08 2:20 PM
Nate Beck's Gravatar Adding an accessor tag simply means that the generated code will inherit whatever is put into that attribute.

Right now when MXML is generated into Actionscript, a <mx:Tree> component's class is marked as public. It'd be nice be able to <mx:Tree accessor="private">, so when this block of MXML is generated into AS, it will use private instead of public.

How hard that would be to implement into the entire framework I'm not sure of.

I understand that writing these new components in AS is the way to go to get what I want. However it then defeats the purpose of why I'm using Flex in the first place, simplicity & consistency.
# Posted By Nate Beck | 7/23/08 2:52 PM
Jeffry Houser's Gravatar Nate,

Much thanks! I understand what you mean by accessor now. I wonder the best way to approach it from a code perspective. You don't really want accessor as a property on the component, but more like a compiler directive somehow.

In many cases, I think that the Flex Framework offers great time savings over 'generic' ActionScript 3, but I'm not sure that MXML offers significant time savings over AS3 w/ the Flex Framework.
# Posted By Jeffry Houser | 7/23/08 4:11 PM
Sid Maskit's Gravatar It looks as though this blog post documents a way to achieve this using a metadata tag: http://blog.ashier.com/2008/03/25/hiding-propertie...
# Posted By Sid Maskit | 7/23/08 6:41 PM
Nate Beck's Gravatar I checked out that article with high hopes that it would work... it doesn't. Unless I'm doing something wrong:

[ExcludeTesting.mxml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="absolute" xmlns:local="*" creationComplete="init();">
   <mx:Script>
      <![CDATA[
         import mx.controls.Button;
         
         private function init():void
         {
            var mybtn:Button = myComp.btn;
            mybtn.label = "Wootage";
         }
      ]]>
   </mx:Script>
   <local:MyComponent id="myComp" />
</mx:Application>

[MyComponent.mxml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"; width="400" height="300">
   <mx:Metadata>
      [Exclude(name="btn", kind="property")]
   </mx:Metadata>
   <mx:Button x="167.5" y="146" label="Click Me" id="btn" />
</mx:Canvas>

It still allows me to access the component, change properties on the component etc. So unfortunately this doesn't solve the dilemma :(
# Posted By Nate Beck | 7/23/08 7:05 PM
Jeffry Houser's Gravatar Sid,

Exclude will just remove the property from the Flex Builder code completion feature. Users can still manually type in the property name to drill down to it.

I thought it was used primarily to hide parent properties within the subclass. For example a VBox excludes the direction property of the Box component.

Nate,

I've never seen the property used in MXML. When you compile your code, there is a compiler flag to save the ActionScript. You might be able to look at the generated ActionScript to see where that metadata ends up.

You could also try something like this [written in the browser and not tested]:

[MyComponent.mxml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml";; width="400" height="300">
<mx:Script>
<![CDATA[
import mx.controls.Button;
private var btn : Button = new Button();
   override protected function createChildren():void{
      super.createChildren();
btn.x = 167.5
btn.y = 146
btn.label = "Click Me"
addChild(btn);
}
]]>
</mx:Script>
</mx:Canvas>
# Posted By Jeffry Houser | 7/23/08 8:47 PM
Sid Maskit's Gravatar I'm in the same boat as the rest of you. I read the blog post, thought it sounded great, and posted about it here. Then I tested it (which I guess the original author didn't do), found it didn't work, and came back to post a correction. Sorry about the misinformation. BTW I've also commented at the site I quoted so hopefully others won't repeat my mistake.
# Posted By Sid Maskit | 7/24/08 1:22 AM
Nate Beck's Gravatar Hey Jeff,

That's all and good with simple components like a button. But it gets a bit harder when I want to do things like constraint based layout. When working with a Tree in actionscript I can't easily set the width and height to "100%" like I can with MXML. Which makes constraint based layout a much harder thing to achieve.

It's the small things like that, that make me want accessors in MXML.
# Posted By Nate Beck | 7/24/08 11:37 AM
Jeffry Houser's Gravatar Nate,

Look into percentWidth and percentHeight.
# Posted By Jeffry Houser | 7/24/08 12:13 PM
Nate Beck's Gravatar Hey looky there. Cool.
# Posted By Nate Beck | 7/24/08 12:24 PM
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.