Build a Navigation System Part Two - Taking it Further

By Daniel Wood, 6 June 2011

In part one, we built a basic navigation bar made from repeating fields. In this followup article we take the formatting of the navigation bar further by introducing highlights. We also adjust the construction of the navigation, and introduce a custom menu implementation that can be used in conjunction with, or in place of the navigation bar.

Some changes to the construction

In order to make some of the new features of this upgraded navigation bar easier to manage, we are going to make a few minor tweaks to how the navigation bar is constructed. These changes may slightly affect how the navigation bar looks from earlier versions, but these can easily be overcome with field formatting options.

navigationbartwo 1

On first glance it may look very similar to the navigation bar in part one, but there are a couple of changes that are shown better in layout mode.

navigationbartwo 2

Here, the icon repeating fields have been increased in height so that their bottom border touches the top border of the label repeating fields, creating a single block with no gaps in between the icon & the labels.

Another change less noticeable, is that each icon/label combination has been created as a separate series of objects to the other repetitions, better illustrated in the following picture:

navigationbartwo 3

Recall in part one that we specified the icons and labels as single fields that were set to show all repetitions. There are a few reasons for this change which will become clear later.

One final change is that each repetition combination of icon & label are grouped into a single object.

Highlighting the Selected Screen

The navigation bar in part one gave no visual indication of which screen the user was currently viewing. It would be nice to highlight the screen being viewed so the user is not left guessing where they ended up, it also provides some solid feedback that the users click on the navigation bar was successful.

What we are going to do then is to implement some highlight formatting as shown below:

navigationbartwo 4

In the picture above you can see two things happening:

  • Background filled white
  • Text label changed to black & bold

Both of these formatting changes have been done by using conditional formatting.

The decision to use conditional formatting over calculation fields that make use of text formatting functions is a conscious decision. The downside to the conditional formatting is that if you ever want to change the fill color or label changes, then the change has to be applied to all navigation bars (or a single navigation bar that is then replaced on all layouts). This could become a nuisance but we are going on the assumption that once set it won't change. The fact the entire navigation system is based on globals means changes aren't that difficult to make as it is a case of copy/pasting a new navigation bar on all layouts that use it.

The reason why calculation fields that use text formatting functions were not used for the formatting, is because the goal here is to keep the navigation system entirely global. By having it all global based, there is only the need for a single Navigation table occurrence on the graph, and navigation bars can easily be applied to new layouts without additional setup. Global calculation fields are not suitable in this situation as they do not refresh as desired.

The conditional formatting calculation

NOTE: This section is somewhat irrelevant now after a discovery by Peter Bouma after the article was written. Please see the extra section at the bottom of this article before reading this section as it may save you some time, cheers :-)

In order to highlight any particular screen in the navigation bar, we require a calculation that can be evaluated that is generic, but at the same time evaluated differently for each repetition. How can a specific repetition evaluate differently from another repetition you ask? Well the answer lies in using a FileMaker function that will give a different result depending on which repetition evaluated from, and there are two prime candidates:

  • Get ( ActiveRepetitionNumber )
  • Get ( CalculationRepetitionNumber )

Both of these are concerning repeating fields so have potential. Get ( ActiveRepetitionNumber ) however is of no real use because that only evaluates when the user has placed the mouse cursor inside of a repeating field. Because we have disabled browse mode access into our navigation bar, this function will never evaluate.

The other possibility is Get ( CalculationRepetitionNumber ). This function will return a repetitions number when evaluated from a calculation context of that repetition. There is just one problem here, our navigation bar is composed of non-calculation repeating fields. The solution then is to make it based on calculation repeating fields :)

navigationbartwo 5

In the picture above you can see two new fields added to the Navigation table - Labels Display and Icons Display. Both are global calculation fields set to their equivalent non-calculation field.

'Scuse me Egon, you said using global calc's was bad

Now, we mentioned earlier that we chose not to use global calculations to do the formatting, yet here we are using global calculations, what gives? Well in this situation they are fine because they will be used only for the navigation bar, and not formatting. Global calculation fields will re-evaluate when fields they reference are changed, but they will not change however when non-field references in them change, such as the current layout name.

navigationbartwo 6

Here is the new navigation bar above, based on the global calculation fields. Note the label definition is not visible because the label text is white by default.

Now that the navigation bar is based upon global calculations, the Get ( CalculationRepetitionNumber ) field can be used in the conditional formatting. Here is the conditional formatting calculation we can apply across all repetitions:

Get ( LayoutName ) = Navigation::Layout Names[Get ( CalculationRepetitionNumber ) ]

It is simply comparing the current layout name, to the layout name contained in the Layout Names field repetition that corresponds to the current repetition being evaluated. For example, the 5th repetition in the nav bar will compare the current layout name, to that in the 5th repetition of the Layout Names field. If it is a match, the conditional formatting will evaluate to true.

Changes to make applying conditional formatting easier

Recall earlier the changes made to the navigation bar construction. These were done for various reasons, but one is to make the conditional formatting of the nav bar simpler.

navigationbartwo 7

The grouping of the label and icon repetition means that we can apply a single conditional formatting property across the single object that takes care of both the highlight and the text formatting, no need for a separate condition for the label and the highlight.

navigationbartwo 8

This single conditional formatting condition can be applied across the entire navigation bar in a single hit, because it is generic across all repetitions. The text formatting of bold & text color will have no affect on the icon, and the fill color will be applied to both icon and label which is what we want.

Note that in order for the highlight fill to work correctly, your icons should be transparent png's or gifs.

A custom function for conditional formatting

While not strictly necessary, we have used a custom function in the example file to contain the conditional formatting calculation. This is a nice illustration of how custom functions can actually reference fields - so long as those fields are able to be evaluated from the context of where the custom function is evaluated from.

navigationbartwo 9

navigationbartwo 10

Clickable area in the Navigation Bar

Now that the text label and icon are touching borders, and they are grouped, we can just make the clickable button the grouped object. This removes the need for a separate button overlay which was used in part one. The reason it was used there was because our icon and label were not aligned and the same size as the clickable area. Because of this change, we can remove the button overlays, reducing the complexity of the navigation bar.

navigationbartwo 11

Building Navigation into a Custom Menu

With the navigation system completely global and already built, building it as a custom menu is a piece of cake.

To do this, we use a technique demonstrated in a previous article called Hide Custom Menu Elements Dynamically.

The technique consists of creating menu items in a new menu. The name of each item is set using a calculation to a specific repetition of the labels repeating field. Because this is global based, it should work across all layouts where the menu item is used.

When building a custom menu, there is no ability to soft-code item names making use of the menu items position in the menu. For this reason, each menu item's name is set from an explicit repetition of the Labels field. Because we may not know exactly how many repetitions of the navigation bar a solution may use, we accommodate for this by adding as many menu items as possible. Menu items will not display if their name evaluates to blank. This is the technique outlined in the article above, and for this reason we can be sure that the menu will only display items for just those that are in the navigation bar.

navigationbartwo 12

The picture above illustrates how the custom menu is built, and the fact that unused repetitions contain no name, and so will not be displayed in FileMaker 11 (in FileMaker 10 they display as blank, but have no action).

The menu item name is set via the Labels repetition, and the action attached is a script that is passed a corresponding repetition number.

navigationbartwo 13

We have gone from using a single script step for the navigation, to putting that inside a script. The reason for this is one of future-proofing. If we ever wish to do post-navigation stuff, this lets us add that in later without having to redo the navigation bar or custom menu.

navigationbartwo 14

The above shows the custom menu in action.

If you had a solution with lots of screens, you could choose to do away with the visual navigation bar entirely, and simply use the custom menu aspect for navigation.

Final Thoughts

With a few tweaks and additions, we have made the navigation bar more responsive visually, by having it give feedback on which screen is selected. We also extended it's use by building a custom menu to supplement it. All the while the navigation system has been kept global and generic so that it can easily be applied to layouts with zero modifications required.

Extra: Global Calcs not required via Peter Bouma

As always the readers of these articles come up with some great suggestions and contributions after the article is written and this case, Peter Bouma from Amsterdam, has discovered that in fact the need for global calculations that contain the icons and the labels is not necessary for using the Get ( CalculationRepetitionNumber ) function as I had assumed.

He has found that this function still evaluates correctly even from the context of a layout-based calculation such as the conditional formatting calculation. Even though the original labels and icons repeating fields were not calculations, the function still is able to obtain the relevant repetition via the conditional formatting calculation set on each repetition.

End result is the solution can be made simpler than I originally presented, you can do away with the Icons Display and Labels display calc fields entirely and just keep the Icons and Labels global fields for your nav bar, awesome!

Example File

Please find attached an example file. This file was used for all the screenshots in this article, and is provided to help you fully understand what is going on in this article, and to let you experiment in FileMaker with this solution.

Download Example File

Example File Extra from Stephen Dolenski

Stephen Dolenski of Ocean West Consulting, Inc. has provided an awesome adaptation of the original example file for this article. In Stephen's adaptation, he has added functionality to allow the navigation bar to toggle between each screens various list & form views, as well as a dashboard view, very cool, and I encourage you to check it out also.

Download Stephen's Modified Example File

Something to say? Post a comment...

Comments

  • corn walker 25/07/2015 4:28am (4 years ago)

    Very nice, this is very similar to what we do. I had been thinking about changing to button bars in FMP14 and it was in reading your post on FMP14 navigation that led me here.

    By the way, the dates of the comments here seem a little peculiar. Did Colin really post from the future or have I been in a coma for a year and today is actually 23 July 2016 instead of 23 July 2015 as my computer insists it is?

  • Colin 11/10/2011 11:12pm (8 years ago)

    Ideal thanks for that will look into your suggestions.

    Best of luck with the semi's (NZ)

    Colin

  • Daniel Wood 11/10/2011 9:44pm (8 years ago)

    Hi Colin. The first thing you could try is changing the graphic display option on the icon repeating fields to "reduce image to fit", and if you put into the icon fields images that are small enough then they should end up centered in the field not touching the edges.

    Failing that the alternative is to introduce a little bit of separation between the label fields and the icon fields. You can do this by increasing the height of the label field (and decreasing the height of the icon field). Set the label fields to be text aligned vertically and because of the taller height, the label text should separate further from the icon. Another alternative is to simply make the icon fields a reduced height so as it is not directly touching the label fields.

  • colin 11/10/2011 8:44pm (8 years ago)

    Hi Daniel

    Is there any way in which you can adjust the distance between the icons and the text. My icons seem to be only a couple of pixels away from the top of my text label and it makes it look very bunched up.

    regards
    Colin

  • Michiel 08/09/2011 2:05am (8 years ago)

    Colin, tab design sample at www.arubaserver.com (tab_sample.zip)

  • Daniel Wood 07/09/2011 10:09am (8 years ago)

    Hi Daniel, thanks for the cool tip.

  • Daniel Shanahan 07/09/2011 12:27am (8 years ago)

    For text only navigation you could simplify it even more. Have a repeating field that can be entered in Browse mode only. Attach a script trigger OnObjectEnter and run the following script:

    #
    Set Variable [$nav; Value:Get ( ActiveFieldContents )]
    Go to Field []
    Go to Layout [$nav]
    #


    This, of course, requires that the layout is the same name as the text in the repeating field. Using the script trigger removes the need for individual buttons masking each field repetition; very portable.

  • Colin 24/08/2011 3:10am (8 years ago)

    Hi Michiel,

    Dear me do you people never sleep...it's 03.10 in the morning there!!

    No I confess never tried the tab sample listed...where is that?

    I have used the alternative Example and can change everything there and happy with the way it works,. However, my issues getting out of the example.fp7 into mine...

    Regards
    Colin

  • Michiel 24/08/2011 2:55am (8 years ago)

    Better use the database listed here as the start-point of your project, rather than copy-pasting the elements into your own. Did you try the tab sample I listed? This would give unlimited layouts within a given 'selected' tab/button...

  • Colin 24/08/2011 2:43am (8 years ago)

    HHi Daniel,

    I have followed your guidance as per our discussion on the blog and have come up against a couple of issues.

    Having imported the Tables and the scripts, looked into setting the icon, labels and layout names into the repeating fields. However, when i look at navigation table, in find, browse mode i cannot see where I add this data as they appears to be nothing. So I go into layout mode and can see the table structure but they have no labels assigned to them.

    It looks very different form when I go into layout mode on the example file. Maybe it is just my ignorance and being a relative newbie to FM. I am confident at hooking my layouts to the specific buttons and changing the colours etc, but alas I'm still struggling with how I import it into my db.

    I tried to send you an email to the address on your site in the about section but the email address assigned to your name was bounced by your servers as non-existent.

    Is there another way i can get my db to you?


    Appreciating your help in this.

    Colin

  • Colin 23/08/2011 8:12pm (8 years ago)

    Great Thanks.

    I will run through that and see what mess I get into...:)

    Regards
    Colin

  • Daniel Wood 23/08/2011 8:01pm (8 years ago)

    Hi Colin, work never stops ;)

    If following the example file, you can do the following in order:

    1. Import Navigation Table
    2. Import "Navigation Script"
    3. Set icons, labels and layout names into repeating fields in Navigation table
    4. You're all set, paste the nav bar onto your layouts

    One thing to note, the navigation fields are globals, so this means if you are implementing it in a solution that is hosted with FileMaker Server, you will have to set these fields while the file is offline, otherwise the values you put into the globals won't remain if you set them while it is hosted.

  • Colin 23/08/2011 7:35pm (8 years ago)

    Hi Daniel,

    Thanks for getting back to me...again and so quickly...really must be near home time there as it's 08:30 in the UK...anyhow I'm waffling.

    Yep discovered that you can use the "Setup Screen" to define and personalise the look. So if I just import the tables, add those to the top of my "app" then place the scripts behind then that should do...

    I'm bound to come back to you..but hey, it's all a learning process that i'm enjoying with the help of talented chaps like yourself.

    Regards
    Colin

  • Daniel Wood 23/08/2011 6:40pm (8 years ago)

    Hi Colin, in my example file the layouts that the Navigation bar makes use of are whatever you define them to be. You don't need to recreate any of the layouts in the solution (and you can't import layouts). In my example file on the main screen, go to the "Access Navigation Setup" link. Here you'll see three repeating fields, one for icons, one for labels and one for the layout names. It is in these fields that you define your own icons, labels, and the names of the layouts you want each of the navigation buttons to go to.

    Stephens example is very similar. In his example file, also go to the navigation setup screen accessible via the link from the home screen. Here you will see he has added a few more repeating fields for the layout names for list & table views of layouts.

    to implement the navigation bar (either one of them) in your solution, you need the repeating fields, any associated navigation scripts, but most importantly you need to actually put some values into these repeating fields such as the layout names, labels etc. These don't get copied across if you are copy/pasting elements from the example file into your own solution.

    Hope this helps

  • Colin 23/08/2011 6:32pm (8 years ago)

    Hi Daniel,

    Thanks for getting back to me. I suppose I should have been more clear.
    When I import it into my DB, I am missing all of the layouts and the text isn't below the button image . In stephens example he has layouts for each button, so I assume I would need to recreate those if they don't get imported.

    Regards
    Colin

  • Daniel Wood 23/08/2011 9:36am (8 years ago)

    Hi Colin,
    All I have really is the example file that is included in this article along with Stephens, and the articles themselves to explain. There is a part-one for this article which is linked at the top of this article, that also helps explain how to implement it. If you need more specific help you can e-mail me.

  • Colin 23/08/2011 9:13am (8 years ago)

    Hi Daniel

    I am impressed with the navigation bar and am looking to use within my app.

    Do you have a step by step guide about how to apply the example or Stephen Dolenski's example to an existing app.

    I am fairly new to FM 11 and can see what your doing but can't quite get my head around on how to apply it to my header.

    Some simple instructions would be great.

    Kind regards
    colin.

  • Michiel 04/08/2011 7:26am (8 years ago)

    I adapted the version into an IE9 style tab navigation... Also tweeked the 'NavBarSelected' function so that it keeps highlighting the tab on layouts that fall thereunder. Now when you have a list view AND a data entry layout only one is highlighted. Stephen's sample works, but with more than 2 layouts falling under one tab/button it doesn't. My sample is dynamical, so every layout that you want to fall under a tab, the tab always remains high lighted. Unlimited layouts if you need to, without extra lines of code... Just duplicate a layout and change the last 4 characters of its name. No extra field needed either in the 'Navigation' table.

    UI - Person DATA
    UI - Person LIST
    UI - Person DETL
    UI - Person 1234
    UI - Person ABCD


    With all the above layouts the 'Person' tab is kept highlighted without the need of extra fields or code...

    Sample at www.arubaserver.com (tab_sample.zip)
    Comments/Suggestions/Updates/Bugs welcome (for sample purpose, only the first 5 tabs in the sample have layouts, so take it easy on that one) ;-).

  • Trevor Hatchett 24/07/2011 2:43am (8 years ago)

    Hi Daniel

    Congratulations on an elegant and easy to use technique.

    I've been using a very similar conditional formatting trick for controlling the appearance of tab panels, which I use extensively.

    It's surprising what you can do with ordinary FileMaker objects to make layouts look clean and simple, and less like an intimidating database. I particularly like to use repeating fields on tab panels which I allow to expand as the user adjusts the size of the window.

    I have a small demo file should you be interested.

    Best wishes

    Trev

  • Bob Stuart 09/07/2011 5:41pm (8 years ago)

    Hi Stephen,

    That looks nice. I think it would look even better if, on the form view, you move the buttons to the right by 3 px and run a 1 px black line vertically 2 px out from the left. Then the objects don't appear to 'jump' when changing from Form to List view.

    Regards,

    Bob.

  • Stephen 08/06/2011 11:09am (8 years ago)

    Visual Aid: http://screencast.com/t/jUtw240K2sGP

  • Stephen 08/06/2011 11:04am (8 years ago)

    the blog didn't preserve the characters they are Disclosure Triangles: Char ( 9660 ) and Char ( 9658 )

  • Stephen 08/06/2011 11:03am (8 years ago)

    Excellent article. If solution is a hosted solution a startup routine could take a one record preference table and populate the globals, OR a server side script could be ran (nightly on schedule) to make sure that globals are reset for all users not requiring the script to set the globals on startup.

    -

    My goal I have is to repurpose the Label to indicate a toggle of List/Form view by using a triangle ► or &#9660 set by a custom function...

    TextFont ( Choose ( value ; Char ( 9660 ); Char ( 9658 ) ) ; If ( Get( SystemPlatform ) = -2 ; "Arial" ; "Apple Symbol Regular" ) )

    So for example:

    When on Notes in List view

    ▼ Notes

    when in detail view

    ► Notes

    So I added a Label State field and that is used with the Display Field.

    Part of the Navigation script would test to see if I am already on Notes and toggle to the corresponding layout, not switching the current layouts view state. And also set the state to reflect the view.

    I typically have a controller script that branches to perform module based routines.

    Adding another field for the List View Layouts Names - unless your naming is consistent and always append "List" then it could be done via the script.

    -

    One may mention that what is the default operation do you always land on LIST or DETAIL, i guess that depends on the solution. And the target module.

    Perhaps some form of logic matrix could be made to assist in abstracting that from the script.

    IE: if I am on a customer and go to invoice should it show ALL invoices / related invoices, or the most current related invoice detail.

    Some cases you just need to navigate the layout because the found set and sort is already established and sometimes you need to perform a FIND and cleanup.

    Cheers

    Stephen

  • Denis Jutras 07/06/2011 1:42pm (8 years ago)

    very funny, Merci beaucoup

  • Daniel Wood 07/06/2011 9:12am (8 years ago)

    Hi Peter, wow that is a cool find thank's for sharing that, I'll have to try it out right now, but that definitely makes it easier. I always thought that function required a calculation, but very cool to know it can work on layout object level calculations too!

    I have updated the article by adding a section at the end outlining your findings :-)

    Cheers
    Daniel

RSS feed for comments on this page | RSS feed for all comments