9. View Stack

To complete our "Add New Item" screen, we want to add a button that saves the item and takes the user back to the main view. Before we do that, a word about the View Stack in JourneyApps:

The View Stack

Imagine that each view on the mobile device is a sheet of paper. For each view that the user opens (by executing a navigate.link() action), a sheet is added on top of the others. Together the sheets are known as the View Stack. Only the top sheet of the stack is ever displayed to the user. Whenever the user goes back (by executing a dismiss or discard action, or by using the built in back button), it would be as if the top sheet is removed and the user sees the sheet that was underneath it.

For instance, if the user has the Main View open and then goes to the Add New Item view in our punch List app, there will be two views on the stack: the Main View at the bottom and Add New Item on top of it.

Dismissing, Discarding & The Back Button

When a user goes back to a previous screen in the View Stack, this is referred to as Dismissing or Discarding the current view and is done programmatically by invoking the dismiss or discard navigation actions. A user can also press the back button (built-in on Android devices, or in the title bar on iOS devices and on Desktop) to go back to the previous view in the stack.

So, what's the difference? The difference is that the dismiss action will automatically save and persist any unsaved changes that have been made to view variables to the database, whereas the discard action and using the back button will discard those same unsaved changes. Note that changes made to JS variables always need to be saved explicitly and will not be included in the automatic save of the dismiss action.

We'll now make use of these concepts in the "Add New Item" view of our punch List app — when the user presses a button to save the new item, we need to go back to the Main View.

Finish Up "Add New Item"

We have added the input-components that will allow our users to capture the information about the new punch list item, but now we need to give them a way to save the new item and go back to the previous view. To do this we will add a button and hook it up with a JS function.

So, in your add_new.view.xml file, underneath the text-input component, add a standard button, give it a label, like "Save Item", and point it to a JS function called saveItem. Like so ...

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

<!-- Components go here: -->
<capture-photo bind="item.photo" required="false" />
<text-input bind="item.comments" required="false" />

<button label="Save Item" on-press="saveItem" validate="false" style="solid" />

Now, in your add_new.js file you need to define the saveItem function. We want this function to save the unsaved changes (save the data that the user has entered) and then take us back to the main view. Broadly speaking you have 2 options.

Option 1 Use a dismiss action which will automatically persist and save the unsaved changes you have made to the view variables on the view in question and then remove the current view from the stack (taking us back to the previous view - the main). In our case, that would save changes you have made to your view.item object. The function will look like this.

function saveItem() {
    dismiss(); // This will save unsaved changed to view variables and remove the current view from the stack
}

Option 2 Explicitly save the unsaved changes and then use a discard action to remove the current view from the stack. In our case, that means we need to save changes to the view.item object. The function will look like this.

function saveItem() {
    view.item.save();
    discard(); // This will will discard unsaved changes and remove the current view from the stack
}

At this point, your code for the Add New Item view should like this.

XML

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

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

    <!-- Components go here: -->
    <capture-photo bind="item.photo" required="false" />
    <text-input bind="item.comments" required="false" />

    <button label="Save Item" on-press="saveItem" validate="false" style="solid" />
</view>

JavaScript (Option 1)

// This function is called when the app navigates to this view (using a link)
function init() {
    // initialize any data here that should be available when the view is shown
    view.item = DB.item.create();
    view.item.status = "Open";
}

// This function is called when the user returns to this view from another view
function resume(from) {
    // from.back       (true/false) if true, the user pressed the "Back" button to return to this view
    // from.dismissed  (true/false) if true, the app dismissed to return to this view
    // from.path       contains the path of the view that the user returned from
    // if any data needs to be refreshed when the user returns to this view, you can do that here:
}

function saveItem() {
    dismiss(); // This will save unsaved changed to view variables and remove the current view from the stack
}

JavaScript (Option 2)

// This function is called when the app navigates to this view (using a link)
function init() {
    // initialize any data here that should be available when the view is shown
    view.item = DB.item.create();
    view.item.status = "Open";
}

// This function is called when the user returns to this view from another view
function resume(from) {
    // from.back       (true/false) if true, the user pressed the "Back" button to return to this view
    // from.dismissed  (true/false) if true, the app dismissed to return to this view
    // from.path       contains the path of the view that the user returned from
    // if any data needs to be refreshed when the user returns to this view, you can do that here:
}

function saveItem() {
    view.item.save();
    discard(); // This will will discard unsaved changes and remove the current view from the stack
}

Test the App on Device

Let's test our app and see that it works as expected.

Firstly, you should see your "Add New Item" button that's been added to the Main View. Clicking on it will take the user to the "Add New Item" screen where you can capture a new punch item.

Note: If your app has not updated on one or more of your devices, ensure you have a network connection and hit the Sync spinner button at the top right corner of the app and wait for the Application updated banner/message to appear on your screen.

Once you've saved the item, you're taken back to the Main View where your new item now appears in the list:

View the Data in the Cloud

Let's go and look at the data we just created in the Cloud. To get there we need to go to our data browser for our app, which can be accessed from the Data Browser shortcut in OXIDE next to our Workspaces Tabs. Once opened, view your Items table and you'll see that your newly added item(s) was synchronized from the device to the cloud, and it happened automatically in the background:

Advanced Navigation

In the last two sections we covered the basics of simple navigation in JourneyApps. It can be summed up by saying you use link actions to navigate forwards to other views, and you use discard or dismiss actions to navigate backwards to previous views.

JourneyApps also supports more advanced methods of navigation and provides you with all the tools you need to actively manage how your users navigate through your application. For more details on simple and advanced navigation as well understanding more about the view stack, it is recommend that you read the View Navigation and View Stack documentation.

Last updated