This past weekend, I implemented a significant change to WriteTrack, which drastically improves the navigation within the application. Specifically, I changed from a static navigation menu (which you can see on the left) to a dynamic one (on the right), which adjusts itself based on the active user’s data.
The old navigation system required a user to go to the main Calendar page and then select the correct challenge from a page item which was displayed on the right sidebar of the page if they wanted to change which challenge they were actively working on. This page item, due to screen real estate limitations, only displayed the name of the challenge; there was no indication of which challenges were upcoming, current, or past. And that’s assuming the user figured out that they needed to look on the opposite side of the page in the first place.
The new menu places all of the user’s challenges at the forefront, grouped intelligently into Current, Upcoming, and Past challenges; each group only shows up when there’s something there. (Friends’ challenges are also on the menu now, grouped by the friend’s user names.) So changing the active challenge is much easier and more intuitive.
This is fairly easy to implement, though it does take several steps.
- Create a view which encapsulates the logic for the menu. Necessary columns are a number indicating the nesting level (1 for a top-level entry, 2 for a child, 3 for a second-level child, etc.); the label; the target URL; and a YES/NO flag indicating if the menu entry should be highlighted for the current page. You can also add a Font Awesome icon (which I did for the top-level entries) and attributes for the icon (which I didn’t bother with). I also found it very useful to include several sort columns, at least one per level, so I could ensure that the menu displayed properly.Here’s a snippet from my view:
select 1 lvl, 'Current Challenge(s) ['||( select count(*) from ...)||']' label, 'f?p='||v('APP_ID')||':211:'||v('APP_SESSION') target, case when ':211:' like '%:'||v('APP_PAGE_ID')||':%' then 'YES' else 'NO' end as is_current, 'fa-book' icon, 10 orderby_1, '' orderby_2, 0 orderby_3, '' orderby_4 from dual where exists ( select null from ... ) union all ...
Note that I don’t call prepare_url on the target link; APEX handles that for me. Also, the is_current column could be written in a simpler form, but this style allows me to have more complicated logic if the entry is highlighted for multiple pages, for instance.
- Next, create a dynamic list by going through the wizard from the APEX shared objects page. The query will look something like this:
select lvl, label, target, is_current, icon, '' image_attribute, '' image_alt_attribute from wt_menu order by orderby_1, orderby_2, orderby_3, orderby_4
You could skip the first step and build all of your logic into the list SQL directly, of course, but I find that these queries become very long (multiple UNION ALL statements, as well as nested queries), so the view helps keep things organized.
Finally, go to Shared Components > User Interface Attributes, and edit your default user interface. (You’re likely to only have one interface unless you’ve created a mobile one.) Under the Navigation Menu section, change the Navigation Menu List to the list you created in step 2, hit Apply Changes, and you’re done!
Oh, and incidentally, you may have noticed in my sample query that the label included a count subquery in brackets. There is a feature in the Universal Theme that will take a navigation menu entry like “Current Challenges [14]” and render the number in the bracket as a small box that floats to the right.