15. Lists

List vs Object-List

Taking a look at the list of punches on our Main View: Currently, in order to view a punch item, the user has to select the item from the list and then scroll down to press "View Selected Item". If the list of punches gets quite long, this will require excessive scrolling and thus make for a poor user experience. It would also be nice to see a thumbnail preview of the photo in the list of punch items. Our existing <object-list> component cannot do this, but JourneyApps has another component used to display lists of static items or database objects, that supports photo thumbnails, and that component is called the List component. In the List component you can call a JavaScript function (potentially trigger a link to a subsequent view or even delete the clicked object), whenever the user "clicks"/touches a list item.

Remove Some Old Components

Before we implement a clickable list on our Main View, first of all, let's remove some things from our View XML that we'll no longer need:

  • The selected_item variable (and any references to it from both the xml and the js)

  • The existing <object-list> component.

  • The "View Selected Item" and "Delete Selected Item" buttons in the <button-group>.

Add the List Component

Now let's add the <list> component in the place of the <object-list> we just removed (in between the info and button-group components). Start typing 'list' and insert the auto-complete suggestion for <list>. Like so

For our list we want to populate the list items dynamically using our open_punches variable, but as previously stated it is also possible to hard-code static list items inside the list component. To populate the list items from a query we need to specify a query="" attribute on the first list-item. Like this.

<list empty-message="Your items will appear here">
    <list-item query="open_punches">
        <header></header>
        <content></content>
        <footer></footer>
        <accent label="" color="info" />
    </list-item>
</list>

Now let's add the comments of each punch item to the <header> tag of our list items, add the status to the <accent label="" and add the photo thumbnail, but leave the other tags empty for now. Like this.

<list empty-message="Your items will appear here">
    <list-item query="open_punches">
        <header>{comments}</header>
        <content></content>
        <footer></footer>
        <accent label="{status}" color="info" />
        <asset src="{photo}" />
    </list-item>
</list>

Finally, let's make the list 'clickable' by specifying an on-press <action> which will call a new JS function, selectItem. This time things will be slightly different though, as we will want to pass the object that the user clicks on to the JS function - we have access to this selected object in a special variable called $selection, so note the syntax below. (For a full syntax reference on the list component please read the reference documentation available here)

<list empty-message="Your items will appear here">
    <list-item query="open_punches">
        <header>{comments}</header>
        <content></content>
        <footer></footer>
        <accent label="{status}" color="info" />
        <asset src="{photo}" />
        <action on-press="$:selectItem($selection)" />
    </list-item>
</list>

Now we just need to create our new selectItem JS function. We want this function to replace the 2 buttons we had previously, one for viewing the details of the punch item and one for deleting the item. So, after the user clicks on any item we want to present them with 2 options, 'View Item Details' or 'Delete Selected Item'. If the user chooses to view item details, we will navigate them to the view_item view, and if the user chooses to delete the item, we will get their confirmation and then delete the item (luckily we already defined 2 JS functions that can help with this so we will definitely reuse them - with a bit of refactoring). To present a user with options to choose from from JS we either use the Option List or the Action Sheet component. Let's start with optionList, but the syntax is essentially identical for both so feel free to experiment and replace optionList with actionSheet whilst keeping the rest of the code exactly the same. So let's create the new JS function and update the 2 existing ones to work with our new setup, like this.

function selectItem(selectedItem) {
    var userOptions = ["View Item Details", "Delete Selected Item"];
    var userSelection = optionList(userOptions);
    // var userSelection = actionSheet(userOptions); // Alternative
    if (userSelection === 0) { // user selected 'View Item Details'
        viewItem(selectedItem);
    } else if (userSelection === 1) { // user selected 'Delete Selected Item'
        deleteItem(selectedItem);
    } else { // user cancelled or clicked away
        return; // exit the function pro-actively
    }
}

function viewItem(item) {
    navigate.link('view_item', item);
}

function deleteItem(item) {
    if (confirmDialog("Delete Item?", "Are you sure?", "YES", "NO")) {
        item.destroy();
    }
}

Test on Device

Phew, we made some major changes to our main view, let's go check it out. It should now look like this.

Next up we are going to augment the data we are capturing for every punch with GPS coordinates, system timestamps and relationships.

Last updated