Pesto Garden, Inc. Bathroom QA Application
Ok, lets get started building a fun application. Let’s say you were hired by Pesto Garden, one of the many Italian restaurant chains in the US. Your boss, Mr. Pasta Lasagna, just read a news story about how the new White House administration thinks that technology can improve the healthcare industry via e-records and other neato things that high tech gadgets and computers can do. Mr. Lasagna thinks that if it can work in healthcare, why not in restaurants? So he tells you that you need to build a system to collect bathroom cleanliness data electronically so that he can quickly tell which of his restaurants are providing a clean bathroom experience to its customers.
So your new assignment is to develop a quality control program that helps improve the restaurant’s bathrooms. You decide that collecting this information in offline mode is the way to go because not all of Pesto Garden restaurants have internet access. Besides, not having to rely on Pesto Garden’s crappy and unreliable internet service, even when it is available, won’t slow you down on your job.
Before you build your application, you first have to think about what sort of data you will be collecting and how to store it. Think of it in terms of one-to-many relationships. Each restaurant is a fixed location. You will store information about each restaurant like its address, city, state, its capacity, when was it opened for the first time, etc. Each restaurant most likely will have more than one bathroom, so you need to create a table to store bathroom information such as the the bathroom number, whether its a men’s bathroom, women’s bathroom, or unisex bathroom, the number of toilets, number of stalls, urinals, sinks, etc. You then need to assume that your QA program will require that someone from your department will be visiting each restaurant more than once, maybe once every three months. So the inspection information would be stored in a many table and would contain things like the inspection date, the inspector name, what the bathroom conditions were like, etc. Another table you probably want to build would be an Inspector table. Here you would store information about the inspector conducting the inspection…his name, contact info, and so forth.
STEP 1 – TABLES AND FIELDS
So lets launch Adesso and build four tables: 1) Restaurants; 2) Bathrooms; 3) Inspections; and 4) Inspectors. We will build the easiest one first. Restaurants. Once you create your application and the Restaurant table, you will be presented with the following screen, which is where you create fields that become part of that table.
I am going to create a bunch of fields that should go in the Restaurant table. Most will be plain text fields, some will be listboxes so that you can enter State in there, and some will be numerical type of fields. A screenshot of the ‘state’ listbox is presented below.
For the ‘State’ field we are simply adding static text to the listbox for each state in the US. I also added a photo field…to store a photo of the facility itself, maybe the entrance of the restaurant. To create a binary field and assign it a display type of image, see the screenshot below.
Notice that you can set the binary image to download always, on request, on a condition, or not sync at all. These options are there because remember that we are dealing with an offline database system that runs on small devices. You have to be careful when designing your application as to what the target device(s) are going to be. If you choose ‘on request’, the image will be uploaded to the server once the user syncs, but when someone else syncs to the database, only the header information will download from the server, sort of like email headers. If that particular user wants to download the image, then he will have the option of marking the binary file for download upon next sync.
Ok, we have completed building the Restaurant table, your table editor should look like the screen below.
OOPS! I just realized that we haven’t even discussed the idea behind ensuring a unique identifier in each table. Notice in the above image, there’s a field called restaurant_name. We can assume that this field is the one that would contain a unique value for each restaurant. That means that the user cannot enter “Pesto Garden” into each record. If he does, then how would one know Pesto Garden #10 from Pesto Garden #251 in the database? One way to tackle this is to use a unique names or a unique restaurant ID number that was assigned by Pesto Garden in their accounting system. However, this company is still in the dark ages and doesn’t do that, so we have to figure out how to assign a unique value to each record on our own. One way to do this is to create a “restaurant_no” text field and give it an expression of RECORDID(). This function uses a hexadecimal function to assign a unique value to the field. Remember that this is an offline system, so there’s no way to autoincrement the value without potentially causing conflicts with other users. So let’s go ahead and add a new field called restaurant_id_no and give it the RECORDID() function as an expression.
Now that we have a unique identifier in this table, we will go ahead and create the bathroom table. I will create fields for bathroom type (mens, womens, or unisex), # of toilets, # of urinals, trash receptacles, etc. Don’t forget to also include a unique identifier for this table too. My table looks like this:
Note that there is a restaurant_id_no field in the related bathroom table. In order to connect the Restaurant table to the Bathroom table, all you need to do is create one single field in the Bathroom table that will act as the “connector” field to connect the two related tables. I usually name the fields exactly the same in all the tables to make it easy to know that it is a “relationship” field. Remember my prfevious blog post when I talked about relationships: always think one to many. In this case, one restaurant can have many bathrooms. More about relationships later in this blog post.
Our most important table for this application, the inspection table, is next. This is the table that will store inspection information, which would include things like “are the toilets working, is the bathroom a filthy mess, do the stall doors close properly, is there obscene graffiti on the walls, etc. Once built, your inspection table should look something like this:
Our final table is the inspector table. I included inspector name, city, state, cell phone, and email address in this table. Once this table is built, I can go back to the Inspection table and use it as a lookup from the inspector field. The lookup screen is accessed by double-clicking on the Inspection.inspector field and then clicking on the Settings button to the right of the display control type. Once there, click on the Query radio button, select the Inspectors table from the lookup table dropdown menu, and then select the field you want to connect to. Your screen will look like this:
Notice that I have included both a comments and a recommendations field. If you want to include an autowriter widget next to the field on the form, so that the user can simply select commonly-occurring things from a checkbox list, then all you need to do is click on the settings button next to the display type drowdown, select autowriter, and then click on the edit button. Here you will have the ability to enter all the values you want to display from the autowriter widget. See screenshot below:
STEP 2 – RELATIONSHIPS
The very next step in building your bathroom QA application is to connect the tables to each other. Remember to ALWAYS think one to many. In our case here, each restaurant can have many bathrooms, and each bathroom can have many inspections. By logical deduction, then each restaurant can also have many inspections. And each inspector can also conduct many inspections. If you understand this one concept, then you have what it takes to build a database application in Adesso.
Building a Relationship Between Restaurant and Bathroom
In the Adesso Designer, click on the Relationships icon on the left pane, and then click on the ‘New” button on the bottom of the right pane. You will be presented with the following window:
There are two types of relationships in Adesso: a one-to-many (O2M) and a one-to-one (O2O) relationship. A O2M relationship is exactly what we described above, where, for example, one restaurant can have many bathrooms, and one bathroom can have many inspections. In Adesso, a O2O relationship is exactly the opposite. This concept may be difficult to understand, so for purposes of building good Adesso applications, all you really need to know about relationships is this: if you build a O2M relationship between two tables in Adesso, you need to build a O2O relationship in the exact opposite direction between those same two tables. The reason for this is for allowing the many, or child, record to be able to display fields from the parent onto its form and its views. More on this later.
The easiest way to start is to first build a O2M relationship, then build the opposite O2O. Although you can use any naming convention you like, its good practice to follow something like this: Table1 > Table2. That way you know which tables are related, and in which direction. Notice that the icons are slightly different for the two available relationship types. In or case here, name the relationship Restaurant > Bathroom and click ok. Your screen will look like this:
Notice that there is a Master table and a Detail table. This is the same thing as a one table and a many table. The Master table = the one table, and the Detail table is the many table. this is also referred as a Parent to Child relationship. Parent = Master = One. Child = Detail = many.
Now you can see why it is important to include a field in the many table that is the labeled the same in the one table…it makes it easier to connect them to build the relationship correctly. You will also notice that there are three field dropdowns for each table. This feature allows you to create uniqueness within the many table by narrowing down the list of records in the many table that will match up. The more fields you use, the fewer records will match. However, it is not absolutely necessary to use this if you are creating uniqueness in your application in another way, such as using the RECORDID() function. In such a case, all you need to do is connect the tables by selecting the same field that is present in both tables.
Enforce Referential Integrity – Very Powerful, and Very Dangerous
Notice that there is a checkbox called “Enforce Referential Integrity”. If this checkbox is checked, then this means that essentially you don’t want to have any orphan records. Think of it this way: if you delete a record from the one, or parent table, then all the related records from the many, or child, table will be deleted. If you think of this in terms of humans, if you kill off a parent, then the database will kill off all of that parent’s children automatically. By default you should NOT have this checkbox checked unless you know what you are doing. The reason for this is that once records are deleted, they are hard to recover, if at all. If you make a mistake, and accidentally delete a parent record, then all the detail records are gone, period. Sayonara. I would prefer to have a bunch of orphan records around and then manually delete them later if they are not needed, than to programmatically have a system that deletes them for me. Err on the side of caution, in my opinion. ‘Nuff said about this.
Ok, once you create a O2M relationship, you need to create an exact opposite O2O relationship for the same tables. Click on New, type in Bathroom > Restaurant, and click on the One to One icon. Your screen will look like this:
Note that an O2O relationship contains a display view dropdown. From here you would select the view that you want to display when a user clicks on a related field widget (more on this later). Since we haven’t built any views yet, you can leave this dropdown alone and come back to it once you build some views.
Now you will need to build O2M relationships between Restaurant > Inspection; Bathroom > Inspection, and Inspector > Inspection. Then you will need to build O2O relationships in the exact opposite direction for these table pairs. Your Bathroom > Inspection relationship should look something like this:
And your Inspector > Inspection relationship should look something like this:
Your main relationships designer screen should look like the following:
STEP 3 – FORMS
Now that you have connected the tables, we need to build forms for each table. In Adesso, you can create an unlimited number of forms per table, and link different forms to different filtered views programmatically by using different events or conditions. This gives you the ability to use the same table to store data, but navigate a user to a completely different form depending on where he is or what he is looking at in the database. Very powerful. For purposes of this simple application, we will focus on building only one form for each table.
The Form Wizard
Adesso contains a form wizard that will automatically create an input form for you based on the fields in your table. I encourage you to use it and then change the form manually once it has done its thing.
To create a form, click on the Forms icon on the left pane of the Application Designer screen, then click on ‘New’ on the bottom of the right pane. Before entering a name for the form, click on the Data Source dropdown and select a table. In this case, select the Restaurant table. Notice that Adesso will automatically name the form the same as the table name. You can change the name manually, but for now, leave it as is.
Note that there are 3 form types: Data form, Home form, and Startup form. Almost all your forms will be of type Data form. The Home form is a special form that allows you to build dashboard-style screens for both PC and PPC. The Startup form is essentially a simple splash screen that displays at launch only. It is typically used to display author information, version numbers, logos, etc. For our bathroom qa app, we will stick to data forms only.
Once you click ok, the wizard will pop up a window asking if you would like Adesso to create the form based on your field definitions. Click yes. The initial form will look something like this:
In Adesso, you can place a maximum of two fields on a row. While this is a limitation, keep in mind that the forms need to be readable on PPCs, hence the limitation. Despite this limitation, you can still build very powerful and aesthetically pleasing forms in Adesso that provide a lot of flexibility. I will show you how.
On the form in the example above, notice that there are labels on the left, and fields on the right. They are separated from each other by a large vertical line. This is a slider. If you move the slider from left to right, you will give the labels more space while shrinking the space available for the fields. These screen constraints are set so that the application designer can effectively build an app that can be viewed on a PPC. If your target devices are PCs (and not PPCs), its ok. Users can stretch the forms however they want in runtime.
On the top of the form you have two menus: Tools and View. Most functionality is available from the Tools menu: validation conditions, form style, form properties, and tabs. See screenshot below:
The validation conditions menu function allows you to set an unlimited number of validations that are checked when the user tries to save the record. If a condition is not met, a popup is displayed with the error condition that the app designer enters for display. All functions that are available within Adesso are also available in the validation conditions section of the form.
The form style menu allows you to select a predefined style or create your own custom style.
The form properties menu allows you to set the default size of the window on a PC, the total height of the form (maximum = 100 rows), select a background image, and basic form background colors.
The tabs menu is where you create tabs for the form, and in what order they will appear on the form from left to right. You can also hide tabs if you want to force the app user to navigate to tabs using button controls, for example.
Form Designer Controls & Tips
* To drop a field into a row, simply click on a blank row and a popup will appear where you can then select a field from that table or its related one tables, where you have created O2O relationships.
* To move a field from one row to another, click and hold onto the field, drag with your mouse until the field is in the row you want, and let go of your mouse button.
* To add a new blank row to a form, right-click where you want to add the row, and a popup menu will appear with Insert Row, Delete Row and Cancel options.
* To strip a label from a row, click on the label, and select remove label.
* To remove both a field and its label, click on the field, and select remove field. The label will be deleted along with the field.
* To add a static label, click on an empty field and select static label from the popup. Then format it using the format tools available from the label designer.
* To add a parent field, click on an empty field and select the parent table, then the field in that table.
* To add a O2M grid, click on an empty field and select the relationship you want.
I went ahead and formatted the Restaurant table somewhat. Screenshot is provided below.
We will go over some of the form items now:
* When you create tabs, a section at the top of the form is then split by a horizontal line. this horizontal line signifies that everything above that line will display on each form, while everything below the line will display only on the respective form. To move the line up and down, simply drag it up or down. Please note that in order to move the line, the form has to be large enough in height (Tools>Format>Form Properties) and/or have enough blank spaces.
* The header area contains its own vertical slider that acts independently of the vertical slider in the section that is specific to the tab you are editing.
* Static text and fields can be formatted to spread across the full row, and can also be changed to be more than one row in height.
* Notice that the photo field is several rows high and covers full row.
* you can add buttons to perform specific tasks. Notice the Acquire GPS Reading button.
* Fields can be formatted to be in read-only mode, so that a user cannot enter anything in the field.
* Tabs can be rearranged to be in a different order from Tools>Format>Tabs menu.
When you click into a blank field, your screen will look something like this:
If you right-click into a blank field, the popup will instead look like this:
If you select a button control to place in a blank field, the button designer will look like this:
Notice that with buttons, you can do all sorts of stuff. In our case, we want to read the GPS on the PPC, so we select an action of Read GPS.
Now take a look at the second tab I created for the Restaurant form.
The control I placed below the static text is a O2M control which displays the related many records. To load this control onto the form, simply click into a blank row, and select ‘Restaurant > Bathroom’ from the popup menu. O2M grid controls are labeled with the same names that you created them in on the Relationships designer. Once you drop a O2M grid control onto the form, you can then click on them to change its design. Screenshot of this is displayed below:
Of key importance is the display view. We haven’t created any views yet, but you will want to later go back into this control and select one from the dropdown menu. This allows you to fully control what displays in that grid view from within that form. Very powerful feature.
Once you have created all your forms, you can then proceed to creating your views.
STEP 4 – VIEWS
Building views is relatively straightforward. To get started, click on the views icon on the left pane of the Application Designer. Click on the ‘new’ button on the bottom of the right pane to create a new view. The following screen will display:
enter a name and a data source. The data source is simply the table. Same thing. A note on views:
* Views are merely sorting and grouping views of the records stored in the table
* You can create an infinite number of views and display them in whatever order you want
* You can hide views if you don’t want them to display on the main Adesso screen
* You can add filters to views to display only records that meet specific critiera
* You can navigate to specific input forms from a view
* Views can take whatever name you assign it…I like to name a view by the sort order…for example, if the view sorts and groups the records by rtheir date, then I would label the view by Date
When you create a view, you will be presented with the following screen:
I pushed several fields into the right hand side of the screen, then made sure the field labels/headers made sense and were justified correctly. Then I clicked on the sort tab and told it to sort by restaurant_name field. Screenshots of these tabs are listed below:
STEP 5 – TESTING YOUR APPLICATION
Once you create a few views for each table, you are ready to test your application. The following is a screenshot of the restaurant table and form while entering our first restaurant record:
Once we enter a restaurant record, then we can enter a bathroom that is inside the restaurant. To do that, navigate to the bathroom tab on the same form and click on the button.
Bathroom records created from this form will associate with its parent and show up in the O2M grid box in the screenshot above. the following screenshot is the view you will see when entering a new bathroom record. Note that I have used two different types of input widgets for numerical values: a spinner, denoted with two arrows < > . Click on the right arrow to increase the number, and click on the left arrow to decrease the number. The other type of widget available for numbers is a numerical keypad, as illustrated below:
After taking the screenshot, I notieced a mistake on the display type for the yes/no fields on this form. I changed the yes/no field sfrom display type of text to checkbox. Screenshot is displayed below:
Once you enter a record for restaurant and a record for bathroom, you are ready to test the inspection table. To test, click on the Inspections tab and click the button to enter a new inspection record.
You will notice that the Inspector field doesn’t have any values in it. This doesn’t mean that that field is messed up…it is because we haven’t actually created any records for the Inspector table. We can add records for that table later. Now let’s click on the Notes tab:
Notice that there’s an autowriter widget to the right of the comments field. It is populated with the autowriter items we created when designing the Inspection table and fields. you can check boxes off in the autowriter, and then edit them within the comments field later. Fully editable comments. The photo field allows you to select a photo from your hard drive, and it also can drive an integrated camera on a PPC device directly. The sketch field is simply a doodle field. The audiro field allows you to record an audio clip as long as your device has a microphone.