17. Relationships
Punch List App: Next Steps
Let's look at further requirements for our Punch List app:
App Design: Construction Punch List
When more and more punches are captured in the punch list app, it will become problematic to browse all the punches in a single list. We want to allow users to organize punches into categories, and then to filter the lists of punches by category.
Relationships
Therefore, we want to make it possible for categories to be created in our database, and then each punch list item must be assigned to a particular category. In order to implement this functionality, we'll make use of Relationships in our Data Model. Relationships allow us to define how our different object types relate to each other. If we create a new Category object type, we'll say that each category has many punch list items that belong to that category. This is called a one-to-many relationship.
Add a New Object Type
Let's head over to the Data Model workspace and update the schema.xml
to include a new Category model
. This model will only have one field for now, a field that will store the 'name' of the category - we will also use this field as the default display value. Like this.
Add a New Relationship
Next, we'll create the one-to-many relationship between the two object types. This is done by adding a belongs-to
tag to the Item object type, and a has-many
to the Category object type as shown below. Relationship tags should be listed after all the fields in a model but before the <display>
tag. Note that the name=""
property on the has-many
allows you to specify a name for the whole collection of items that belong to a category. Using the pluralized form of the object type (in this case, "items") is a good convention to use for the collection name. On the belongs-to
side you can also specify a name=""
for the relationship, but if you don't the system will default the name to the name of the associated model
- in our case category
.
Your ERD should also visualize these changes, like this.
While we are at it, let's also add a relationship between user and item to signify which user created which punch items. To do this we add another belongs-to
tag on our item
model, this time pointing to the user
model, and we add the has-many
tag to the user
model. For this belongs-to
relationship let's not use the system default name, and instead specify it as name="created_by"
. At this point your schema.xml
file should look like this.
See Changes in Data Browser
If you go to the Data Browser for the "Testing" environment, you'll notice that there is a new Category object type shown on the left, and that clicking on an Item shows a Belongs to Category field and a Belongs to User - created_by field at the bottom (if your Data Browser was already open in a different tab then you will need to first refresh that browser tab before you will see the changes):
Click on the Category tab on the left and let's create a couple of categories:
Set Category on "Add New Item" Screen
Now let's add the category selection to the Add New Item view. Under the "Variables go here" section of the add_new.view.xml
file, add a new variable called all_categories
which will be of type query:category
. Like this.
Then change the init()
function to populate the categories using a Query and also populate the relationship to the user
model. To set the belongs-to
relationship in JS we use a helper method that is created for us on the model in question, this method will use the value of name
that is specified in the in the Data Model in the <belongs-to>
tag. So in our case, we specified the relationship as <belongs-to model="user" name="created_by" />
and so we will use the created_by
method to set the relationship to the user model, like this.
Finally, add a <object-dropdown>
View Component, above the <text-input>
component, allowing the user to select the category. Note that:
We specify
query="all_categories"
so that the list will show all the categories that we've pulled using our Query.We specify
bind="item.category"
so that the category that the user selects will be stored in the category relationship on our item variable.
Test on Mobile Device
At "Add New Item", you should now see a drop-down list to select a category:
View Relationship on App Backend Data Browser
After you've added a new item, if you open up the Data Browser for the "Testing" environment again, you'll see "Belongs to Category" for the item shows the category that you've selected. Go ahead and update the other punch items and make each of them belong-to
a category
as well. Like this:
Display Item Category on "Main" and "View Punch Item"
Let's update the list
component on our Main view to display the category
inside of the <content>
tag, and while we are at it, let's also add the created_at
timestamp in the <footer>
tag. So, in your main.view.xml
, update the list component like this.
If we want to show the category on the View punch Item view, we could adjust our table component there as follows:
Test on Device
Enable Filtering by Category
Lastly, we want the user to be able to browse punch items by category. We will do this in a new view called browse_items
, but first let's add a button on our Main view to allow the user to navigate to the Browse Items view. So, on your main.view.xml
, add a new button to the <button-group>
below the 'Add New Item' button, and hook it up like this:
You will notice we have included the necessary JS navigation
logic directly in the on-press
attribute by using the $:
notation to execute raw JS from our View XML.
Next, let's create a new View with the name browse_items
(remember, you can create views using the command palette, ctrl+shift+p
/ cmd+shift+p
to open the command palette and then start typing create and choose the Create view
action), and then once created update the <view title="Browse Punch Items by Category">
as before.
Now we can add some components to our new view. Firstly, we are going to need to present the user with a list of all categories (we will need a query
for this), let the user select a category (we will need a category
variable for this), and then show the user all the punch items that belong to the selected category (we will need another query
for this). So, in your newly created browse_items.view.xml
specify all these variables, like this.
Now let's add the necessary view components. We want to display all the the categories to the user and then once they select one, show all the related punch items for the selected category. A nice way to do this is to make use of the JourneyApps show-if
and hide-if
logic available to any view component (syntax reference for show-if
and hide-if
available here). We will display an <object-list>
for all the categories but once the user selects one we will hide the <object-list>
and display a <list>
of related items
instead (re-using the list we defined on our main view). So, in your browse_items.view.xml
, add the following code:
Next we need to add a way for the user to clear their selection (we will use a button for that - using show-if
to only display the button if the user has already made a selection). After that we also need to populate the various queries from our JS. Populating the all_categories
variable can be done from the init()
function, but we can only populate filtered_items
once the user makes a selection, and we need to re-populate it every time the user makes a new selection. To do this we will make use of the on-change=""
attribute of our <object-list>
component. (Note, the on-change=""
attribute is available on all input
components, but note that for capture-photo
and scan-barcode
it is referenced as on-capture
and on-scan
instead). So, update your browse_items.view.xml
to the following:
Let's update our browse_items.js
file next to populate our queries and handle the on-change
event, as well as the clearSelection
and selectItem
function calls (let's reuse the selectItem functions from the main view). Like this
Test on Device
Let's test these changes. Your app should now look like this:
Well done, you have effectively completed the Punch List App for the scope we originally envisioned. A user can view open punches, capture new punches, view details for existing punches and mark them as closed. Next up we are going to add a new user role to our app, an App Admin, that should be able to easily manage all the data in the application.
Last updated