11. View Parameters

Parameters & Arguments

When it comes to the new view we want to create to allow users to view the details of an existing punch list item, we clearly have to pass some data to the view when we link to it — namely, the specific punch list item that the user wants to view. In contrast, we didn't have to pass any data to our "Add New Item" view when we linked to it, because it simply creates a new punch list item whenever the user opens it. For the purpose of passing data to a view, JourneyApps uses standard concepts similar to other programming environments:

  • A view specifies its Parameters — the data that it requires you to pass to it. A view can have multiple parameters.

  • When you link to a view that expects a parameter, and then pass it a specific object (e.g. a punch list item), that specific object is known as an Argument.

A hypothetical example of this is shown in the diagram below, in the context of some concepts that you are already familiar with, such as Links and Variables:

Looking at the diagram:

  • View B expects two parameters — both of type person.

  • When we link to View B from View A, we pass in two arguments — objects of type person

  • There are two outgoing links from View B — to View C and View D respectively.

  • View C and View D each expect one parameter.

Accessing Parameters from the View

Inside your View XML and JavaScript, parameters are accessed in exactly the same way as variables. In other words, you can bind input components to them and access them from the JavaScript using the view. notation. Once on the specific view they act exactly the same way as view variables.

Linking to a View with an Argument

In OXIDE, open up the Main View of the punch List app again (to do this, make sure you are on the Views Workspace, and then select the main view from the Views Panel on the left). Let's add a "View Selected Item" button before our existing "Add New Item" button, and specify that it will call a JS function named viewItem.

<!-- Components go here: -->
<heading>Welcome to the Punch List App</heading>

<info>A list of all the punches that have not yet been taken care of are shown below</info>

<object-list label="Open Punches" query="open_punches" bind="selected_item" empty-message="There are no open punches at the moment." required="false" />

<button label="View Selected Item" on-press="viewItem" validate="false" style="solid" />
<button label="Add New Item" on-press="goToNew" validate="false" style="solid" />

Now let's define our viewItem() function. We want this function to take the item the user has selected and pass it to the view_item view, which we will create after this step. You may remember we originally defined our <object-list> with a bind attribute and we set that to selected_item to store the object that the user clicks on in the list in the view variable called selected_item. We can now use that variable in our new function.

So, in your main.js, add the viewItem() function as follows (Note: Unlike in the XML, the order in which you specify functions in JS does not matter).

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

This function will take the object that is stored in view.selected_item and pass it to the view_item view. But what if the user hasn't selected an item yet? In that case view.selected_item would be null and we would be passing nothing to our view_item view. We can't have that, so let's add some validations to stop that from happening. We can do this with JS validations, or with simple XML input validations, as we learned in Section 10 - Input Validations. Let's just use simple input validations.

To do this, we will force the user to select an item before they press the button to view the selected item. So, we update the required attribute of our <object-list> to "true" and we also update the validate attribute of our View Selected Item <button> to "true". Like this.

<?xml version="1.0" encoding="UTF-8"?>
<view title="Punch List">
    <!-- Parameters go here: -->

    <!-- Variables go here: -->
    <var name="selected_item" type="item" />
    <var name="open_punches" type="query:item" />

    <!-- Components go here: -->
    <heading>Welcome to the Punch List App</heading>

    <info>A list of all the punches that have not yet been taken care of are shown below</info>

    <object-list label="Open Punches" query="open_punches" bind="selected_item" empty-message="There are no open punches at the moment." required="true" />
    
    <button label="View Selected Item" on-press="viewItem" validate="true" style="solid" />
    <button label="Add New Item" on-press="goToNew" validate="false" style="solid" />
</view>

By only updating the validate attribute of the View Selected Item button, it means that when the users presses the Add New Item button the input validation will not run, and this is correct. We do not need the user to first select an existing item before we allow them to add a new one.

Create the New View and Specify a Parameter

Now create a new view and specify the name/path to be view_item.

Once you hit Continue you will be taken to your new view. Again, let's start by updating the title of the view to something more appropriate, in this case "View Punch Item".

<view title="View Punch Item">

This view needs to accept an item parameter. Under the <!-- Parameters go here: --> section of the View XML, type param and insert the auto-complete suggestion for <param>. Then fill in a name for the parameter and specify the type as item as seen below:

<?xml version="1.0" encoding="UTF-8"?>
<view title="View Punch Item">
    <!-- Parameters go here: -->
    <param name="item" type="item" />

    <!-- Variables go here: -->

    <!-- Components go here: -->

</view>

Add Some Components

Now let's add some view components to display the details of our punch item. A new component that we will be using here is the info-table (which allows displaying a 2-column table and is perfect for displaying data from the database). We will also be using the display-photo component to display the photo that we captured. Finally, we need a button that will take us back to the main view.

<?xml version="1.0" encoding="UTF-8"?>
<view title="View Punch Item">
    <!-- Parameters go here: -->
    <param name="item" type="item" />

    <!-- Variables go here: -->

    <!-- Components go here: -->
    <info-table>
        <row label="Item Comments" bind="item.comments" />
        <row label="Item Status" bind="item.status" />
    </info-table>

    <display-photo bind="item.photo" />
    
    <button label="Go back" on-press="dismiss" validate="false" style="solid" />
</view>

A couple of things to note.

  • Firstly, our button is hooked up to a JS function called dismiss. This function is a built-in function and does not have to be redefined. This means you can use it, like this, directly in your XML and it will execute the dismiss navigation action - saving all unsaved changes to view variables and then removing the current view from the stack

  • Secondly, inside the <info-table> component we have nested <row> sub-components. You may have noticed that similarly to when we had input components, the row display sub-component has a bind attribute which we used to bind directly to view variable's fields. This is very useful for quickly and easily displaying data that is stored in any view variable. However, you can also display information dynamically using XML string interpolation inside any XML component that knows how to display text values, for example a <heading> component.

So let's do that now. Let's add a <heading> component and make it display the contents of the comments field of our item variable. Still in the View XML in the view_item.view.xml file, add the following above the <info-table>.

<heading>{item.comments}</heading>

Note that item.comments is wrapped in curly braces. Remember Display Format for default display values from the "The Data Model" section of the tutorial? Displaying the value of a variable or parameter within the View XML uses the same syntax in JourneyApps. In fact, almost anywhere where you are using text in your View XML you can render the text dynamically using XML string interpolation, using values stored in variables or even the returned results of JS functions. So let's try that now. Let's add another row to our <info-table>, and in this one we are going to display the returned results of a new JS function called showTime().

Executing JS in the View

So, still in the View XML in the view_item.view.xml file, update your <info-table> to include the following new row.

<row label="Current Time" value="{$:showTime()}" />

Note that this time we replaced the bind attribute with a value attribute. bind is used to display the contents of variables directly, value is used to display text, both static and dynamic. We also used a new syntax notation inside the curly braces, and that is the $: notation. The $: notation inside a pair of curly braces {} tells the XML that you will be executing JS code inside those {}'s. You can execute raw JS code or call a function that you have defined elsewhere. In our case we are calling a function called showTime - which we still need to define. (Note: If you execute raw JS code you need to remember to escape any XML characters, for example > --> &gt;, <= --> &lte;, && --> &amp;&amp;, etc.)

Your View XML should now look like this.

<?xml version="1.0" encoding="UTF-8"?>
<view title="View Punch Item">
    <!-- Parameters go here: -->
    <param name="item" type="item" />

    <!-- Variables go here: -->

    <!-- Components go here: -->
    <heading>{item.comments}</heading>
    <info-table>
        <row label="Item Comments" bind="item.comments" />
        <row label="Item Status" bind="item.status" />
        <row label="Current Time" value="{$:showTime()}" />
    </info-table>

    <display-photo bind="item.photo" />
    
    <button label="Go back" on-press="dismiss" validate="false" style="solid" />
</view>

Next, let's create the corresponding JS function and then we will review what we have just done. So, in your View JS in the view_item.js file, add the following new showTime() function.

function showTime() {
    var now = new Date(); // standard JS function to get the current date and time
    return now.toLocaleString(); // changes the DateTime object into a string according to local conventions
}

Note, the reason we used the toLocaleString() method before returning the value is because our XML is expecting text and so we need to convert the result we want to return into a string first before we return it.

At this point, the code in your view_item view should look like this:

Test on Mobile Device

Let's test it out! Your app should now look like this:

Last updated