Role based UI with Flex

This is an example I have in the pipe for a long time but I think it still might be helpful to post it.

I had the use case to build a Flex UI where elements are visible/invisible depending on the user who is logged in. The combination of the properties includeInLayout and visible does the trick.

includeInLayout docs:

“Specifies whether this component is included in the layout of the parent container. If true, the object is included in its parent container’s layout. If false, the object is positioned by its parent container as per its layout rules, but it is ignored for the purpose of computing the position of the next child.”

So when for instance a Button has includeInLayout and visible set to false the control is hidden and does not effect the layout and is not accessible. Now how can we bind this to the roles of a user who is logged into the application?

I thought of this:

<Button label="delete" includeInLayout="{user.hasRole(UserRole.DELETE)}" visible="{user.hasRole(UserRole.DELETE)}" />

The User class:

package
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
 
 
	public class User extends EventDispatcher
	{
 
		private static const ROLES_CHANGED:String = "rolesChanged";
 
		[Bindable]
		public var username:String;
 
		public var password:String;
 
		private var _roles:Array;
 
		public function get roles():Array
		{
			return _roles;
		}
		public function set roles(a:Array):void
		{
			_roles = a;
			dispatchEvent(new Event(ROLES_CHANGED));
		}
 
		public function User(username:String = "", password:String = "")
		{
			this.username = username;
			this.password = password;
		}
 
		[Bindable(event=ROLES_CHANGED)]
		public function hasRole(userRole:UserRole):Boolean
		{
			if(roles != null)
			{
				for each(var role:UserRole in roles)
				{
					if(role.equals(userRole))
					{
						return true;
					}
				}
				return false;
			}
			return false;
		}
 
	}
}

The key is the hasRole method which is bindable and can be used for MXML bindings to the includeInLayout and visible property. All bindings will refresh every time the roles setter is called as the ROLES_CHANGED event is dispatched within. And this event is the custom binding event for the hasRole method.

The UserRole class:

package
{
	public class UserRole
	{
 
		public static const DO_A:UserRole = new UserRole("DO_A");
		public static const DO_B:UserRole = new UserRole("DO_B");
		public static const DO_C:UserRole = new UserRole("DO_C");
		public static const VIEW_A:UserRole = new UserRole("VIEW_A");
		public static const VIEW_B:UserRole = new UserRole("VIEW_B");
		public static const VIEW_C:UserRole = new UserRole("VIEW_C");
 
		private var name:String;
 
		public function UserRole(name:String)
		{
			this.name = name;
		}
 
		public function equals(userRole:UserRole):Boolean
		{
			if(userRole != null)
			{
				return this.name == userRole.name;
			}
			return false;
		}
 
	}
}

The UserRole class specifies all available Roles as constants so they can be passed as parameters to the hasRole method of the User class.

I build a little example application which you can try here and view the source here.

11 comments to Role based UI with Flex

  • stef

    thank you, wonderful and concise example. SB

  • Chris H

    yep, thanks. will come in handy soon…

  • Benoit Jadinon

    nice. I just needed something like this. gotta love rss. thx

  • would this mean, that some users have components or whole modules in their memory, which they will never be able to use? I’d rather have an argument, that lets components not even be created, if a certain argument is false.

  • I’d go with Sven. I’d rather create ui components at runtime using actionscript rather than crank up unused memory space. If your components are independent enough, there shouldn’t be much complexity involved.

  • First thanks for the nice comments.
    To Sven and Hyder: Yes this would mean that there is an extra unsused memory when you bind to includeInLayout and visible but I also show in my example application how you you deal with container an that childs are only added/instantiated if they are really used. Nevertheless I think this extra memory is such a small part of the total memory usage that it has no weight. The benefit of the binding approach is that you have really small and very readable markup to provide this functionality. If you implement this with ActionScript code you will have more bugs and refactoring will also be more complicated so I think it’s worth the extra 100KB memory usage I think.

  • Johan

    Thanks for a nice example. Much appreciated.

    FYI – the dotted background on your blog makes it hard to read the AS (code) text which is quite a small font.

  • Thanks Johan, I know that the code is not so readable. I will change the CSS when I have time.

  • Craig

    Hi great example.

    What would be the best approach to use this within a menu?

    Thanks

  • Craig, I think this can not be done with markup. You could provide multiple dataProvider for the different user roles.

  • Martin

    Hi Sönke,

    Thank you for sharing this great wundefull solution!
    Greetings from Germany!

    Martin Zach