From APEX 5 onwards the APEX Builder provides an elegant menu showing your account profile with some links/buttons to manage it. Unfortunately, there is no simple way to replicate this functionality with standard APEX using the Universal Theme. In this article we’ll show you how to mimic this menu using our plugins.
Background
With the introduction of FOEX 3.0 we have introduced floating region support. What this allows us to do is associate a region on the page with a button or icon and have it behave like a menu. That way, we can show almost all FOEX region types within a menu, which means that your menu can look as simple or as complex as you want.
Example 1
Example 2
Example 3
This new floating region support is very flexible and simple to setup, allowing you to create some really cool looking menu’s that would otherwise require a fair amount of work using JavaScript.
Design
First we are going to break down the design of the menu into comparable FOEX plugins. In the screenshot below you can see that the overall solution consists of a button, HTML, and toolbar.
For the button requirement we will use the FOEX Button plugin. Similarly for point 3 we will create a toolbar plugin to house the Preferences and Sign Out buttons. For the HTML section we have the choice of four different FOEX plugin region types: we can either use a FOEX PLSQL region, FOEX Static HTML region, FOEX Form region, or last but not least, a FOEX List View.
All four plugins have built-in refresh capability, however, we’ll rule out the FOEX Form plugin because we just have a display requirement in this case. We will also exclude the Static HTML plugin, since we need to show user specific information fetched from a table/view.
For this particular solution I decided to use the List View plugin. The main reason for this choice is that it is a very versatile, yet under-utilised plugin. Essentially, it is a client-side templating solution which will merge an array of JSON records returned from a SQL Query into a client-side HTML template. Additionally, it has the added benefits of lazy rendering and lazy loading for improved performance. We can also set page items with values from the associated JSON record when a list item is selected/clicked. In this case we will only be returning 1 row, so it’s not really a list, but it’s the previously mentioned features of the plugin that we want to take advantage of.
Profile Menu Setup
The page/region structure is as follows:
Our list view plugin has the following SQL Query. Please note that we are using the APEX API apex_util.get_blob_file_src to provide a URL reference to download the image.
APEX has many great APIs that we can take advantage of and save time.
SELECT OID, FIRST_NAME, LAST_NAME, WORKSPACE, ROLE_NAME, BIRTHDAY, CASE WHEN NVL(dbms_lob.getlength(PROFILE_IMAGE),0) = 0 THEN NULL ELSE apex_util.get_blob_file_src('P7111_PROFILE_IMAGE',ROWID) END IMAGE_SRC, EMAIL, JOB_TITLE, PROFILE_IMAGE FROM FX_T_DEMO_USER_PROFILE WHERE OID = :P7110_PROFILE
Our list view has the following Ext JS template, which essentially is an exact copy of the menu HTML markup that is in the APEX Builder.
<div id="accountMenu_menu" class="a-Header-accountDialog" tabindex="-1"> <div class="a-MediaBlock a-Menu-content"> <div class="a-MediaBlock-graphic"> <span class="a-Header-userPhoto a-Header-userPhoto--large"> <img src="{IMAGE_SRC}" height="64" width="64" class="a-Header-photo" alt="Profile image for user {ROLE_NAME}"> </span> <a href="#" class="a-Header-accountDialog-editProfile a-Menu-item a-Menu-label" id="EDIT_PROFILE_LINK">Edit Profile</a> </div> <div class="a-MediaBlock-content"> <div class="a-Menu-label a-Menu-item" tabindex="-1"> <span class="a-Header-dialogText a-Header-dialogName">{FIRST_NAME} {LAST_NAME}</span> <span class="a-Header-dialogText a-Header-dialogUsername">{EMAIL}</span></div> <div class="a-Menu-label a-Menu-item" tabindex="-1"> <span class="a-Header-dialogLabel"> Workspace</span><span class="a-Header-dialogValue">{WORKSPACE}</span></div> <div class="a-Menu-label a-Menu-item" tabindex="-1"> <span class="a-Header-dialogLabel">Role</span><span class="a-Header-dialogValue">{ROLE_NAME}</span></div> </div> </div> </div>
Tip: in Ext JS substitutions are performed using {ATTRIBUTE} syntax. For future list view solutions you can essentially take an existing APEX template and change #ATTRIBUTE# substitutions to {ATTRIBUTE}
To associate our floating region with the button we need to first define a static ID for our button e.g. and then add some additional JSON config to our floating region (which is a FOEX Layout Plugin with vertical stacked regions as the layout type):
Note: when we add the “floating”:true attribute to our region it will be treated the same as a window and it will be separated out of the viewport rendering tree.
Styling
We’ll add some CSS to the page and style the HTML which we borrowed from the APEX Builder:
.a-MediaBlock.a-Menu-content { background: none; border: none; box-shadow: none; } .a-Header-accountDialog .a-MediaBlock-graphic { margin-right: 16px; } .a-MediaBlock-graphic { float: left; margin-right: 8px; } .a-Header-accountDialog .a-Header-userPhoto--large { background-color: #F8F8F8; } .a-Header-userPhoto { box-shadow: 0 0 0 1px #B0B0B0 inset; } .a-Header-userPhoto { display: inline-block; width: 24px; height: 24px; border-radius: 100%; vertical-align: top; overflow: hidden; position: relative; } .a-Header-accountDialog.a-Menu .a-Menu-label { padding: 0; } .a-Header-accountDialog.a-Menu .a-Menu-item { display: inherit; color: inherit; line-height: inherit; float: none; } .a-Header-accountDialog-editProfile.a-Menu-item.a-Menu-label { text-align: center; } .a-Header-accountDialog-editProfile.a-Menu-item.a-Menu-label, .a-Menu-content .a-Header-dialogLink.a-Menu-item .a-Menu-label { display: block; margin-top: 4px; color: #146fb8; } .a-Header-accountDialog-editProfile.a-Menu-item.a-Menu-label, .a-Header-dialogLink.a-Menu-item .a-Menu-label { font-size: 11px; line-height: 16px; padding: 0; border-radius: 2px; transition: none; } .a-Header-accountDialog .a-MediaBlock-content { padding: 4px 0; } .a-Header-userPhoto--large, .a-Header-userPhoto--large .a-Icon, .a-Header-userPhoto--large img { width: 64px; height: 64px; } .a-Header-dialogName { font-weight: 300; font-size: 20px; line-height: 24px; } .a-Header-dialogText { display: block; line-height: 16px; } .a-Header-photoPlaceholder { position: absolute; left: 0; top: 0; right: 0; bottom: 0; border-radius: 100%; box-shadow: 0 0 0 1px rgba(0,0,0,.15)inset; } .a-Header-accountDialog.a-Menu .a-Menu-item { display: inherit; color: inherit; line-height: inherit; float: none; } .a-Header-accountDialog.a-Menu .a-MediaBlock-content .a-Menu-item.a-Menu-label { cursor: default; } .a-Header-dialogUsername { font-size: 11px; font-weight: 400; } .a-Header-dialogLabel, .a-Header-dialogUsername { color: #777; } .a-Header-dialogLabel { margin-top: 16px; line-height: 10px; font-size: 9px; text-transform: uppercase; display: block; } .a-Header-dialogValue { font-size: 12px; line-height: 16px; } .a-Header-dialogName, .a-Header-dialogValue { color: #404040; } .profile-icon { background-color: transparent; background-repeat: no-repeat; background-size: 24px; display: inline-block; height: 24px; width: 24px; vertical-align: baseline; cursor: pointer; border-radius: 100%; margin-right: 5px; } /** * Minor changes to disable list view selection highlighting and setting the line height on * the button to align the button text to the extra profile image which we added */ #P7110_PROFILE_BTN .x-btn-inner { line-height: 24px; } #PR7110_PROFILE li.fx-listview-item:hover { background: none; } #PR7110_PROFILE .fx-listview-item.x-item-selected { background: none; } #PR7110_PROFILE .x-view-item-focused { outline: none !important; }
Next, we’ll include the profile picture within the actual button. We prepend a SPAN tag on our button label with a specific CSS class name to show the profile image. We also need to output this class definition using a PLSQL Page Process (e.g. “After Header”).
The solution presented below was specifically created for our demo which uses a cycle button to change the profile button and menu.
DECLARE l_image_src VARCHAR2(4000); l_css_tab APEX_APPLICATION_GLOBAL.VC_ARR2; l_name_tab APEX_APPLICATION_GLOBAL.VC_ARR2; l_oid_tab APEX_APPLICATION_GLOBAL.VC_ARR2; BEGIN -- -- Bulk Collect our profiles -- SELECT OID , CASE WHEN NVL(dbms_lob.getlength(PROFILE_IMAGE),0) = 0 THEN NULL ELSE '.profile-icon-'||oid||'{ background-image: url('||apex_util.get_blob_file_src('P7111_PROFILE_IMAGE',ROWID)||') !important; }' END PROFILE_IMAGE , LAST_NAME BULK COLLECT INTO l_oid_tab , l_css_tab , l_name_tab FROM FX_T_DEMO_USER_PROFILE; -- sys.htp.p('<style>'); FOR i IN 1.. l_css_tab.count LOOP IF l_css_tab(i) IS NOT NULL THEN sys.htp.p(l_css_tab(i)); END IF; END LOOP; sys.htp.p('</style>'); -- -- sys.htp.p('<script>'); sys.htp.p('var fxUserProfiles = [];'); FOR i IN 1.. l_name_tab.count LOOP sys.htp.p('fxUserProfiles["'||l_oid_tab(i)||'"] = "<span class=\"profile-icon-'||l_oid_tab(i)||' profile-icon\"> </span>'||l_name_tab(i)||'";'); END LOOP; sys.htp.p('</script>'); -- END;
Then end result looks like this:
Demo
We have added the above demo to our documentation application that will be available in the v3.0.1 release of the FOEX Plugin Framework. In the demo we added an extra cycle button to the page and a number of dynamic actions to show you how to make this solution refreshable without reloading the page.
We setup a dynamic action on our cycle button so that when the button changes/cycles you will see the profile button change and then our menu will be lazily loaded (i.e. only when opened). Here you can see it in action:
If you check out the APEX builder you will notice that when you change your profile (e.g. email address) the menu is not updated until you reload the page. Here, at FOEX, we aim to make everything refreshable so you don’t need to perform page reloads.
Summary
In this article I have shown you how to replicate the “APEX User Profile Menu” relatively easily by using a combination of FOEX plugins. There are many other ways to achieve this within FOEX by mixing and matching our plugins. However, we believe that the List View plugin is one that should be used more often due to its versatility.
Do you have a technical question about FOEX or want good tips for improving your application? We’ve launched this series of How To articles to help improve your FOEX applications even more.
Use #askFOEX on Twitter and we’ll get back to you as soon as possible or sign up for a free trial and see why it is a great tool for developing large-scale web applications!
Hi Matt,
I am not getting the profile picture on following this blog. I know that I am missing something related to image source.
How can I come over it?
1. Can you please tell us, what we need write in Dynamic action of P7110_PROFILE page item?
2. Do we need to have FOEX Display Image Plugin in type for P7111_PROFILE_IMAGE? If Yes, in which region? Do we need to create this page item in another page 7111 Since its name starts with P7111?
3. Do we need to write anything on XTemplate?
For apex_util.get_blob_file_src to work you need an APEX file browse item that is within a form which has an associated Automatic Row Processing process.
In our example Page 7111 is a regular APEX page with a regular APEX form created by the builder with “UPDATE” capability. We based the form Primary Key on ROWID and use just the two page items i.e. PK page item and the file browse item based on the BLOB column.
Also P7110_PROFILE is a separate button (actually a FOEX cycle Button) for our demo to show switching the profile, it’s purely for demo purposes and not something we would think belongs in an application. Since the profile is the current user of the application.
You can change the XTemplate according to your own requirements, if you do not change it then it will appear exactly like the demo. We suggest changing it since your application probably does not have workspaces.
Thanks for the Input. It’s working fine.
Thank you very much for your help.