Do you know how to make a horizontal portal in the first place?
Does the data in your one row portals need to exactly match up with other data such as an assignment name? (and which you won't want to have to enter more than once for any given assignment.)
In short, tell me more about the overall set up of your database...
Hi Phil. Thanks for your reply. I don't know anything about horizontal portals. I'd like to match up data with assignment names. If like to enter data only once as I want it to be really user friendly.
My colleagues and I use a roll book for recording attendance and marks. There is a list of names on the left. Along the top there is a list of dates. This method is cumbersome. But it has advantages. I can see the results that each child gets on a particular date. I can compare her results to previous dates and to her peers. I would like to be able to do the same by using a horizontal portal. This would allow me to compare students to each other and to their previous performances. I would also like to be able to sort these students and results into top performers on given dates (vertically), or most recent tests (horizontally). I hope this is a bit clearer.
The simplest horizontal portal is simply a row of almost identical one row portals. The first portal specify's an initial row 1, the next is set for initial row 2 , the third specifies initial row 3.
But with this approach, you can't enter data into column 3 until you have first created records in columns 1 and 2 and this can sometimes be a bit of a problem.
An alternative method is to set up portal filters that use data from either a related table or global fields to filter for a specific date or assignment. This requires a bit of scripting to create a new record in the portal when you click on it, but allows you to associate attendance to a specific date or a homework score to a specific assignment. It also allows you to update your layout by updating the data in the filter fields to show a different sub set of all your related data on the screen.
Thanks Phil. The second option you mentioned, using portal filters, sounds more dynamic. Would you mind advising me on how I might set something like that up?
Horizontal portals and such a row of filtered portals are basically one way to set up a "cross tab" report or data entry layout where data from different records are arranged in different columns.
Let's use an attendance example and I think you can extend that to assignments by replacing a date with an assignment ID in the filter field:
The basic data model on which to build the layout:
Students----<attendance>----SchoolCalendar (schoolCalendar is optional)
Students::__pkStudentID = Attendance::_fkStudentID
SchoolCalendar::Date = Attendance::Date
Define one more field, Absent as a text field.
With a typical, Simple Simon layout, you would put a portal to attendance on the students layout and select a date in Attendance::Date whenever you mark a student absent.
But the typical paper student grade book has one row for each student's name with columns for each date in the school year. That's a very space efficient way to go and we can reproduce that classic layout design with a row of filtered portals.
First, define a date field with global storage, and I'm going to do something radical, make it a repeating field, gDates, with the same number of repetitions as you plan on having attendance columns on your layout. Gasp, yep ye olde repeating field, but it's making sense to me to use it here.
Now, go to your Students layout, set it up for List View, place the name field(s) on the left and then use the portal tool to add one portal to the body next to the name column. Make it a portal to attendance, but give it this portal filter: Globals::gDates = Attendance::Date. Make this a one row portal (initial row 1) and put Absent as the sole field in the portal. Resize your portal to fit and you have one column added to your layout. You can then duplicate this portal as many times as you need and just change the portal filter expression to refer to Globals::gDates, Globals::gDates, Etc.
You can place your global repeating field in the header and you can add a school date each day manually in the repetitions of that field or you might use a script to load this field from the dates in SchoolCalendar. (There are also ways to access the dates in SchoolCalendar directly for the portal filters instead of using the global field, but I think the performance hit in getting your screen to update will be to much...)
Now there simply comes a need for being able to actually add new records in the attendance with the correct date entered automatically. We could use a script that swaps layouts, but let's add a relationship so that we don't have to and so that we can use the same button tap to clear a mistakenly recorded absence as we do to record it in the first place.
Add another table occurrence and a global field to create this relationship:
Students::__pkStudentID = Attendance|Select::_fkStudentID AND
Students::gDate = Attendance|Select::Date
Enable "allow creation... for Attendance|Select.
For simplicity and testing purposes, put a small button just below the first portal in the body layout part. We'll move it after we have things debugged and working right.
Set it to pass the column number (1) as a script parameter to this script:
If [ Not IsEmpty ( Globals::gDates [Get ( ScriptParameter ) ]
Set Field [Students::gDate ; Globals::gDates[Get ( ScriptParameter ) ] ]
Commit records ---> may not need this step
If [ Isempty ( Attendance|Select::Absent ) //Mark student absent ]
Set Field [ Attendance|Select::Absent ; "X" ]
Set Field [Attendance|Select::Absent ; "" ]
#test your script with and without these next two steps to see if you need them to get screen to refresh...
Once you have this script and button working, you can make the button invisible and place it on top of the portal, but this get's tricky. You don't want the portal to "own" the button or the button will not be present and clickable until there is a record in the portal. You can make the button slightly larger than the portal or you can use the Inspector's alignment tools to align the button object on top of the portal. But if the button is the same size or smaller than the portal row, dragging the button on top of the portal will result in the portal "owning" the button.
That works for simple "toggle" data entries where you have only two possible values. To enter more values in the field or a numerical score such as the student's grade on a test or assignment, you could pop up either a custom dialog or a modal window for entering the score or your script can just create the record and then use go to field or go to object to put the cursor into the field so that you can select from a value list or type in a score.
Thanks Phil. I'll try that out as soon as I get a chance. I've been busy entering Xmas Exam results. Groups of students have been coming up and asking me for their results on the corridor. It was really getting cumbersome getting multiple results with my current set up making paper look like the ideal record storage system.
This is for Phil-
Thank you for the response. Very helpful. You had given me advice on a similar problem before, and it's all be so informative.
My next question is: when I go to set all this up, I'm getting all of the students. But I would like it to break down the attendance for each group of kids. (So like, 1st hour, 2nd hour, etc but in my case it's more like Tuesday group, Thursday group, etc.) Would there be a way to create a similar set up but in a tab? So one tab has the overall group information, one is the class roster, and in the other tab you have attendance for those related students.
I was also thinking I could set up a button that would just take you to the right layout to enter in attendance, but then how would you make sure only the students for that hour/group were populated on the layout?
Thanks for your help again.
@NonProfit Education User,
I suggest starting your own thread. The first part of answering your question will be to determine your current data model to both make sure that it is workable for what you want and if it is, exactly how to use it to get the needed results. Please start that new thread and in it, repeat this question but provide a description of the tables and relationships you have set up for your system.
Thanks! I will start a new thread for those questions. But, first, I have a question about the method you set up above. I have it up and working (thanks for a GREAT walk through) but it shows ALL of my students at the same time right now. What is best practice for having it only show students in 1st hour, and then only show students in 2nd hour, etc?
Thank you! I have this set up to this point. Now I was wondering if could explain how a script would fill in the repeating global dates field that you described above as well.
"You can place your global repeating field in the header and you can add a school date each day manually in the repetitions of that field or you might use a script to load this field from the dates in SchoolCalendar."
I have multiple different groups of students, but each group has a different set of dates that they are attending sessions (aka classes). So rather than one "SchoolCalendar" I have multiple SessionDates.
Right now, to take attendance, the teacher clicks on a button that takes her from the roster of students, to the attendance layout. She can select the group for which she is taking attendance by drop down. It then runs a script to show only students in that class (THANK YOU for that bit of help too). Then there are horizontal portals for each day that she sees the student (up to sixteen days) so they can mark absent. (Still trying to figure out the toggle you are describing, but I'll come back to that later). This is all working per your advice above.
There is a repeating global field in the header showing all the repetitions. I want to automatically pull the dates for the current group and put in the repeating fields.I tried to do a "Set Field" script telling it that Globals:gDate = Session|Attendance::Session Date; but it didn't do anything. I noted the "repeating" edit box at the bottom of one dialog, and sure this comes in to play here, but no idea how to use.
Thanks again for your help!
So rather than one "SchoolCalendar" I have multiple SessionDates.
But a SchoolCalendar file can have all session dates for all sessions in it. And this can actually be displayed as dates on a traditional monthly calendar if you want.
The general outline of this method is to have your script use a relationship or scripted find to access the group of records for a specific class (session) sorted in ascending order. The script then isolates the "next group" of dates from this set and copies them back into the repetitions of your global date field. Let's say that you have only 5 columns of attendance data on your layout just to keep it simple. A global field or Global Variable would be used to track which 5 date group is currently shown on your layout. If there's a 1 in the field, you have the first 5, a 2 tells the script that the next 5 are showing...
For my example, I'll use a global variable named $$Group.
Then your script might follow this outline to get the dates for the "next 5 dates":
Set Variable [$$Group ; value: $$Group + 1 ]
##Perform a Find or use Go To Related Records to pull up the date records in SchoolCalendar for the specified Session
Sort Records [Restore ; no dialog ] // sort by date in ascending order
Go to Record/Request/Page [$$Group * 5 - 4 ; no dialog ] //use the record number by calculation option
Set Variable [$K ; $K + 1 ]
Exit Loop If [$K > 5 ]
Set Field [ Globals::Dates[$K] ; SchoolCalendar::Date ]
Go to Record/Request/Page [Next ; exit after last ]
You would put $K in the repetition box in the first Set field parameter.
Note: With FIleMaker 13, there's a new summary field that could extract this data from a found set without needing a loop.
My horizontal portal is filtered like this.
PatternCount ( Comment portal::timestamp ; Personnel Records::gDate ) ≥ 1
I enter the date Im looking for into the global field. But it doesn't find all of the dates that match that field. I have the field that I'm looking the match for auto entering timestamps which include the time of the day.
Why is it not working?