FileMaker Weetbicks

Build a Navigation System Part Two - Taking it Further

June 6, 2011 By Daniel

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.

The new navigation bar

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.

resizing of the new navigation bar

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:

splitting repetitions of the nav bar

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:

Navigation with highlighting of selected screen.

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 :)

A couple new global calculation fields.

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.

The new navigation bar based on global calcs.

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.

Grouping of repetitions.

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.

Conditional formatting.

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.

Putting it in a custom function.
the revised conditional formatting.

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.

Clickable area of the navigation bar.

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.

Building a menu.

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.

Using a script for Navigation

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.

Custom Menu in Action

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.

Comments

Paul Spafford

07 June, 2011

Hey Daniel. Very nice and very thorough -- as always!

Tom Droz

07 June, 2011

Any good source for the nice icons you used?

Daniel Wood

Daniel Wood

07 June, 2011

Hi Tom, I can't remember specifically where I got those icons from, but I quite often use IconsPedia.com for icons, or the icons that come with FM Theme Studio, cheers.

Peter Bouma

07 June, 2011

Hi Daniel,

As always, your solutions are intelligent and efficient, and your article was informative and fun to read. Thanks again! I think that in this case, the solution could be even more basic. As I experimented somewhat with your example file, I found that you don't need the extra global calculation fields as intermediaries at all. When I change the fields in your Nav bar to the original globals (Icons and Labels), it still works, without even changing you CF. Apparently, the function Get( CalculationRepetitionNumber ) not only applies to calculations inside fields, but also to calculations on layout objects. The formatting condition is enough of a calculation in its own right to know about the CalculationRepetitionNumber of the object it's attached to. In your example, it's not even necessary to do a screen refresh, since the layout change already takes care of that. Without the layout change you might need to add a Refresh Window. (played with in FMA11/OSX)

Good luck, Peter Bouma, Amsterdam, Netherlands

Daniel Wood

Daniel Wood

07 June, 2011

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

Stephen

08 June, 2011

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 ▼ 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

Stephen

08 June, 2011

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

Stephen

08 June, 2011

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

Bob Stuart

09 July, 2011

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.

Trevor Hatchett

24 July, 2011

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

Michiel

04 August, 2011

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) ;-).

Colin

23 August, 2011

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.

Daniel Wood

Daniel Wood

23 August, 2011

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 August, 2011

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

Daniel Wood

23 August, 2011

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 August, 2011

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

Daniel Wood

23 August, 2011

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 August, 2011

Great Thanks.

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

Regards
Colin

Colin

24 August, 2011

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

Michiel

24 August, 2011

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 August, 2011

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

Daniel Shanahan

07 September, 2011

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.

Daniel Wood

Daniel Wood

07 September, 2011

Hi Daniel, thanks for the cool tip.

Michiel

08 September, 2011

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

colin

11 October, 2011

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

Daniel Wood

Daniel Wood

11 October, 2011

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 October, 2011

Ideal thanks for that will look into your suggestions.

Best of luck with the semi's (NZ)

Colin

Something to say?

Question: The current version number of FileMaker Pro is

Some HTML is OK

  • <b>bold</b>
  • <i>italic</i>
  • <blockquote>
    blockquote
    </blockquote>
  • <pre>
    preformatted code
    </pre>