Creating a month view calendar in FileMaker Part 3

We're nearing the end of this blog series about creating a one month view calendar in FileMaker, enabling a similar function to the Outlook/iCal calendar app. In part one we created the base for the one month calendar view and in part two we added some new features. In this blog post, we'll improve on our previous work even further in order to create something that's really functional. Consequently, we've got quite a few things to cover, lots of useful features and enhancements, so I recommend that you skim through the post first to get an idea of what's on offer before you jump in.

Creating a month view calendar in FileMaker Part 3 features
1. Improving the portal display date
2. Changing the month and year
3. Jumping to today
4. Showing how many records are hidden in the portal
5. Creating a day view popup
6. A thought on portal scrolling


1. Improving the portal display date

When we view the current month in the calendar, we really want an obvious indicator for where the current date lies in the month. This code was originally defined in the Interface::cDisplayDate date described in the first part of this blog series. I'm not quite happy with the Interface::cDisplayDate calculation so let's change it to this :

Let ( [

PortalDate = Extend ( cDateOfFirstPortal ) + Get ( CalculationRepetitionNumber ) - 1 ;

TodaysDate = Get ( CurrentDate ) ] ;

Case (

PortalDate = TodaysDate ; TextStyleAdd ( "Today - " & Day ( TodaysDate ) & " " & Left ( MonthName ( TodaysDate ) ; 3 ) ; Bold ) ;

Day ( PortalDate ) = 1 ; TextStyleAdd ( Left ( MonthName ( PortalDate ) ; 3 ) & " " & Day ( PortalDate ) ; Bold ) ;

Day ( PortalDate ) ) )

This will give a much clearer visual indicator for today's date / the start of the month and as such, it will also look a lot more like the Outlook/iCal offering.


2. Changing Month and Year

If you've been following this blog series then you might be wondering when I'm going to address the + and - buttons next to the month and year fields. Let's deal with that now. First off you'll need a new script, let's call it Alter Year / Month (). I like to include the double brackets as it's an indicator that the script will be expecting a parameter to be passed to it in order to function correctly.

FileMaker Tip : For best practices you should be recording all sorts of helpful data about a script as part of a general script header. A good starting place is to include the following four comment lines at the very top of each and every script you write - regardless of how many lines it's comprised of.

Created :
Purpose :
Parameters :
Latest Notes :

Saying that, no script should be made up of anything less that half a dozen lines at the very least. You need the four comment lines I've just mentioned, next comes Set Error Capture On and then an Allow User Abort Off step is often (though not always) handy. If you're passing parameters then including a Set Variable step for each one, with meaningful variable names, is very helpful. Finally, I usually have the last step of my scripts set to Exit Script as it acts as buffer before the script finishes thus preserving any error codes.

So you have a new script and you've already followed some of the FileMaker best practices we've discussed. You'll now need an If statement and a series of Set Field steps in order to process the Month and Year buttons.

Set Variable [ $Choice; Value:Get (ScriptParameter) ]

If [ $Choice = "-Month" ]


  If [ Interface::gSelectedMonth = 1 ]

    #If changing to before January, decrease year as well.

       Set Field [ Interface::gSelectedYear; Interface::gSelectedYear - 1 ]

    End If

    Set Field [ Interface::gSelectedMonth; If ( Interface::gSelectedMonth = 1 ; 12 ; Interface::gSelectedMonth - 1 )

Else If [ $Choice = "+Month" ]


    If [ Interface::gSelectedMonth = 12 ]

        #If changing to after December, increase year as well.

        Set Field [ Interface::gSelectedYear; Interface::gSelectedYear + 1 ]

    End If

    Set Field [ Interface::gSelectedMonth; If ( Interface::gSelectedMonth ≥ 12 ; 1 ; Interface::gSelectedMonth + 1 )

Else If [ $Choice = "-Year" ]


  Set Field [ Interface::gSelectedYear; Interface::gSelectedYear - 1 ]

Else If [ $Choice = "+Year" ]


  Set Field [ Interface::gSelectedYear; Interface::gSelectedYear + 1 ]

Else If [ $Choice = "Today" ]


  Set Field [ Interface::gSelectedYear; Year ( Get (CurrentDate) ) ]

  Set Field [ Interface::gSelectedMonth; Month ( Get (CurrentDate) ) ]

End If

At the end of the script, make sure that you call the PortalRefresh script described in part one of this series. Without it, the month / year changes you made won't be fully realised in the portal. Whilst we're at it, I have changed how the PortalRefresh script runs so unless you have already reviewed these alterations, it would be a good idea to see how I've sped the portal refresh up by checking out the first part of the blog.

Make sure that the + and - buttons that surround the month and year fields have correctly assigned parameters as shown in the script (eg to increase the Year, make sure that the button is calling the script and passing +Year as a parameter).

With this script we're able to adjust the month and year by clicking on the + and - buttons but better than that, if you click on the - month button and the month is set to January, then the month will become December and the year will be decreased by 1 as well.


3. Jumping to Today

From the earlier "2. Changing Month and Year" section, we created a script that allowed us to change the month and year being shown in the FileMaker One Month view calendar. How about jumping to the current date? Well if you haven't noticed, we've already written the required script steps into the Alter Year / Month () script. All you need to do is put a "Today" button on the layout, assign it to the script and pass Today as the script parameter.


4. Showing how many records are hidden in the portal

One of the big limitations of the current calendar view is that the calendar day portals only show four records - what can we do to about the records past that initial four? We could increase the number of visible rows but that won't always work or we could enable portal scrolling but it's very very ugly and we're trying to create something that's pleasing to the eye as well as being entirely functional.

A neat solution is suggested by iCal which shows "x more…" at the bottom of a day box (where x is the number of hidden records). So how do we arrive at this functionality? The field that stores the "x more…" calculation can't be stored in the portal for obvious reasons so once again we'll be needing a repeating field where each repetition will calculate how many days are hidden for each portal. Unfortunately this is not entirely straightforward because each event is actually comprised of many dates : a start date, an end date and every date in between and we'll need to total them. Locating these dates is pretty easy with portal filtering but how about in a calculation field? We need our calculation field to determine how each repetition corresponds to the date on the month calendar and then count how many times that date is recorded in the Events table.

4a. Create a repeating calculation field, with 42 repetitions, in the Interface table called cHowManyHiddenItems (make that you don't store the text result). Here's the code you'll need for it.

Let ( [
Dater = Date ( Month ( Extend ( cDateOfFirstPortal ) ) ; Day ( Extend ( cDateOfFirstPortal ) ) ; Year ( Extend ( cDateOfFirstPortal ) ) ) + Get ( CalculationRepetitionNumber ) - 1 ; 
DaterList = List ( Extend ( Interface to Events::cListOfDates ) ) ] ;
If ( PatternCount ( DaterList ; Dater ) < 5 ; "" ; PatternCount ( DaterList ; Dater ) - 4 & " more…" ) )

This takes a specific date from the one month view, compares it with all of the cListOfDates and works out how many times it pops up - that's the figure that we're interested in. Remember that our portals only show four rows so if you need your portals to show something else, you'll need to adjust the IF statement in the cHowManyHiddenItems field.

4b. This last step is unfortunately a little tedious and it's the problem you face whenever you're dealing with this number of repetitions. Perhaps I should have started with a one week view instead and advised how to extrapolate from it to a full month… In any case, you're going to need to move all of your portals and resize the boxes that surround them so that you can include space for the cHowManyHiddenItems field. Here's a screenshot showing what I mean.


I've made the box that surrounds the portal an extra 15 pixels high (150 by 100 pixels) to accommodate the new field. Add the cHowManyHiddenItems field so that it sits beneath the portal but within the box that surrounds the portal. Here's a screenshot.


You'll need to do this for each portal, a pest I know but it's well worth it.


5. Creating a day view popup

I'm not going to break down how to create a day view popup but I will give you a good idea of how to do it yourself.

5a. You'll need to create a script and pass the day portal number as a parameter (so you'll need to add a button to each of the Summary fields held in the portal and assign a parameter of 1 to the first, 2 to the second and so on, right up to 42).

5b. Create a global date field in the Interface table and store the date of the portal the user clicked into - this can be accomplished by using the date of the first portal and the script parameter.

5c. Create a global numeric field to store the number of the portal clicked into (ie the script parameter).

5d. Create a layout based on the Interface table and put a portal, based on the Interface to Events table, on it. The portal will need a filter that shows all of the Event days that fall between a start and end date equal to the first portal date (from the one month calendar view) plus the passed parameter described above in 5c).

5e. The script should open a new window based on this new layout.

That's pretty much it aside from some minor adjustment with the dates and which fields to show on the layout. Make sure that if you allow adding records to this new portal that when the popup is closed, the refresh portal script is run otherwise your changes won't appear in the one month view.


6. A thought on portal scrolling

As you are aware there is no portal scrolling in the FileMaker one month view calendar. Instead when a day portal contains more than four records we get the natty little blurb stating "x more…" which helps to alleviate the need for scrolling. However you may want to consider including a facility whereby the four records displayed in a portal can be cycled through, perhaps by clicking on the "x more…" blurb or maybe via a button that cycles through all of the day portals.

I haven't included this option here as I don't feel that it adds enough to what is already a neat and worthy solution, however should you be interested, here's how I would do it.

1. Grab the IDs of the first four records that would be shown in the portal and store in a global field.

2. Change the portal filter to only show those records that have IDs that match those stored in the global field. This wouldn't change the "x more…" blurb as it's part of a different calculation.

3. A script is run via a button click from the "x more…" blurb or a global button (as described above) that changes the global field to the next four IDs.

4. Once you get to the end of the ID list, it resets (or something similar).

This would allow for some simple control of scrolling through a day's events without the need for scroll bars. You need to use portal filtering here (or a similar approach) as you can't use a Go To Portal Row script step since the portal row selection process happily carries on past the number of visible portal rows (ie portal rows don't slide up and down, the selector simply scrolls out of view).


Closing Notes

I have tested this with a networked database that holds a thousand or so Event records and I believe that the performance is acceptable. However, if you're thinking of running this in a more 'extreme' environment then you might want to consider the following ideas for speeding things up.

Opt 1. Move from 1 single Interface to Events relationship to 42 separate relationships. This is the old way of doing things whereby rather than using portal filtering (which has only been available recently in FileMaker), create a relationship for each day in the one month calendar. To do this you'll need 42 global fields in the Interface table with each one holding the relevant date and then you'll need to use this as a match criteria with the Events table and the field you use to store the list of start to finish Event dates. This has some serious setup overheads as you'll need 42 fields, relationships, portals, portal fields, portal sorts and so on. Yes that was the old way of doing things and recommending reverting to it may seem to invalidate some of this blog series but FileMaker is quicker resolving relationships than portal filters so changing to a relationship model can have a positive effect on the refresh speed.

Opt 2. Change calculation fields. Where possible, rather than have un-stored calculations, update the fields in your PortalRefresh script. No doubt this will slow the refresh Portal script down but may improve overall performance.

Opt 3. Don't use conditional formatting. Consider using container fields and filling them with a colour that is specified when the Event type is altered. The advantage here is that you can change the colours used to represent this or that Event type globally (perhaps via an admin view) rather than having to change dozens of conditional formatting statements which, even with block selections can be a pest.

Opt 4. Change how the PortalRefresh script works. I've changed this in the Blog Part One so it's worth a look.


I hope that I've gone some way to improving how FileMaker deals with dates and one month calendars and hope that you've learned something interesting along the way. I may well come back to this blog series at some point and include further detail but for now I feel that I've done what I set out to do. If you notice anything wrong with this blog, think that you can do it better or just want to discuss it, then please get in touch.

Blog entry is closed for new comments.