View Navigation

Definitions

The following terms are used throughout this page and are defined as:

Action

A navigational function that will navigate the user from the current view to another.

Actions include:

  • link

  • dismiss (and discard - a special case)

  • replace

  • clear

Navigational actions are namespaced to navigate.<action>().

Version compatibility

  • The navigate namespace and its primary navigation actions were introduced in version 4.50 of the JourneyApps Container.

  • navigate.getDeeplink was introduced in version 4.89.0 of the JourneyApps Runtime. See more details about deep linking to a view here.

Transitioning from one view to another, modifying the view stack. Forward navigation adds a view to the view stack. Backward navigation navigates back to a view that is already on the view stack, while removing all views in between.

Top level view

A view that is not dependent on other views, i.e. it can be navigated to from anywhere in the app, and is typically used as the starting point of a workflow.

View stack

A virtual representation of the navigation history, with the current view at the top of the stack.

Accessed in JS using journey.viewStack. Please refer to the viewStack reference for more details.

View path

A unique path representing a view (which you specify when you create a view) used to navigate to the particular view.

Accessed from JS using view.path.

The view path is especially useful for functions in SharedJS or if you are logging usage of the app to an analytics service.

View parameters

Some views may expect data to be passed when navigating to them. These can be objects or other data types and are are specified in a view’s XML. Any view variable or JS variable may be passed as parameters (referred to as params).

For example, the view new_user requires two parameters (group and name) to passed to it:

<view title="New User">
   <param name="group" type="group"/>
   <param name="name" type="text"/>
   ...
</view>

Using object parameters simplify apps where there are multiple steps that work with the same object. For example, if the group object above is used or modified in multiple successive steps as part of a linear flow, you should specify it as a parameter for those views.

An example of a valid link to reach this view would be navigate.link('new_user', view.group, view.user_name), refer to Linking to a view for more detail.

View parameter attributes

required

Version compatibility

The required attribute was introduced in version 4.89.0 of the JourneyApps Runtime.

  • Optional

  • Type: boolean

  • Default: true

main.view.xml
<param name="job" type="job" required="false"/>

Specify whether a view parameter requires a value or not. If this attribute is set to false, the parameter does not require a value when navigating to the view (in-app or when using deep links). Important: this is only the case when there are no subsequent parameters in the link. For this reason, it is recommended to list required parameters first in a view, and optional parameters last.

Example

Given the following view:

job_details
<param name="job" type="job" required="true" />
<param name="site" type="site" required="true" />
<param name="current_date" type="date" required="false" />

The following links are valid:

main.ts
navigate.link('job_details', job, site);
navigate.link('job_details', job, site, new Date);

If the order of the view parameters were as follows:

job_details
<param name="job" type="job" required="true" />
<param name="current_date" type="date" required="false" />
<param name="site" type="site" required="true" />

Links need to include null for empty optional view parameters:

main.ts
navigate.link('job_details', job, null, site);
navigate.link('job_details', job, new Date, site);

transform-value

Version compatibility

The transform-value attribute was introduced in version 4.89.0 of the JourneyApps Runtime.

This attribute takes a function and passes an $event object.

The $event object has the following structure:

"$event": {
    value: DB.object | string | null,
    param: {
        name: string // -> 'current_job'
        type: string // -> 'job'
        required: boolean // -> true
    }
}

Example:

main.view.xml
<param name="job" type="job" transform-value="$:loadJob($event)" />
<param name="compeletion_date" type="date" transform-value="$:getDate($event)" />
main.js
function loadJob(event) {
    // event.value => ''
    var job = DB.job.first(event.value);    
    return job;
}

function getDate(event) {
    // event.value => '1681822674806' | '1991/01/01' | null
    return new Date(event.value);
}
  • This function takes some input and outputs a value based on that input. It is not like any other JS/TS function; for example, navigate does not work within transform-value. Its sole purpose is to return a value to a view parameter.

  • This function is useful for setting a parameter where the event object needs to be transformed or retrieved from the DB from an ID. It is also useful to provide a fallback value (e.g. when a parameter is null).

  • The function always runs before init() . This ensures that anything that depends on the view parameter in init() can seamlessly execute.

  • It is executed every time before the view is added onto viewStack including:

    Note: The function does not execute when resume the flow happens (since in this case the view is already on the viewStack).

  • When an exception gets thrown in this function, the view cannot successfully load and the user will be taken to the main view.

Example use case

Here is an example use case to aid in explaining view navigation.

The above diagram represents the navigational flow of a fictitious app.

It consists of a Login page, from which the user navigates to individual landing views, according to some criteria (typically based on a role).

From a landing page, the user can navigate to any of the top level views and back, in any order. This is done using the replace action, only replacing the current view and not adding to the view stack. See Replacing a view.

When the user starts a linear flow from Top level 1, link is used. Navigating between steps adds to the view stack and allows the user to navigate forward and backward. (See Linking to a view and Dismissing a view).

When the user performs non-linear tasks, link from Top level 2 to Task 1 is used. Thereafter replace is used, allowing the user to jump between different tasks in the process. See Replacing a view.

The diagram also illustrates how clear is used, allowing the user to ‘log out’ and navigate to the login screen, clearing the views on the stack. See Clear and navigate.

Linking to a view

The link action performs forward navigation (→) and is typically used with linear workflows.

For example: A → B → C will result in a view stack of [A, B, C] with C being the active view.

Syntax

navigate.link(path, param1, param2, ...) — link to the specified view path and pass params.

Examples:

Using navigate.link in xml:

<view title="Main Menu">
    <button label="New User" on-press="$:navigate.link('new_user')" />
</view>

Notice the use of $:, this will evaluate the function in the view context.

Using navigate.link with params in JS

function editUser(currentUser){
    navigate.link('edit_user', currentUser);
}

Deprecation warning

The link() function might be deprecated in the near future.

link.view_path() — link to the specified view path link.view_path.with.slash(params) — link to a view path containing / (the slashes are replaced with a .)

Using link in JS:

function createUser() {
    // Include other logic here
    link.new_user();
}

Dismissing a view

The dismiss action performs backward navigation (←).

Calling dismiss on a view (e.g. on a button press) will save and close that view and navigate to the previous view on the stack. Given a view stack of [A, B, C] dismiss ← will result in a view stack of [A, B].

To close the view without saving variables and view state, chain discard.

Closing multiple views, for instance to return to a top level view, use the dismiss action specifying a view path, navigate.dismiss('view_path').

Syntax

navigate.dismiss() — dismiss the active view

navigate.dismiss(path) — dismiss to the specified view path

navigate.discard().dismiss(path) — dismiss to the specified view path without saving

Note: dismiss and discard does not take view parameters.

Examples:

Using navigate.dismiss to a view path in xml:

<button on-press="$:navigate.dismiss('main')" label="Main Menu" />

This will automatically save all objects defined in the view.

Using navigate.discard().dismiss in xml:

<button on-press="$:navigate.discard().dismiss('main')" label="Main Menu" />

dismiss()

Deprecation warning

The dismiss() function might be deprecated in the near future.

dismiss()— dismiss the active view

discard() — dismiss the active view without saving

discard.view_path() — dismiss to the specified view path without saving

Examples:

Using dismiss() in xml:

<button on-press="dismiss()" label="Save" />

This will automatically save all objects defined in the view.

Using discard() in xml:

<button on-press="discard()" label="Cancel" />

Replacing a view

Instead of adding a view to the view stack, the replace action (denoted by ⇌) replaces the current view and navigates to a new view.

For example: A → B ⇌ C will result in [A, C] on the view stack. A → B ⇌ C ⇌ D ⇌ B will result in [A, B] on the view stack.

The replace view action is typically used for non-linear workflows, but is also a powerful tool to build apps that consists of various top level views.

replace calls the target view’s init() function, instead of the resume() callback when navigating to it. You can read more about the resume callback in a section below.

Syntax

navigate.replace(path, param1, param2, ...) — replace with the specified view path passing params.

navigate.discard().replace(path, param1, param2, ...) — discard unsaved changes and replace with the specified view path, passing params.

Examples:

Using navigate.replace in xml:

<button on-press="$:navigate.replace('tasks/task_1')" label="Complete Task" />

Using navigate.replace in JS:

function toMyDashboard() {
    // Other logic here
    navigate.replace('dashboards/tech');
}

Using navigate.replace with params:

<button on-press="$:navigate.replace('tasks/task_2', view.results)" label="Complete Task" />

The replace action reduces the need to manage the view stack manually and makes for clearer navigation within your app.

Clear and navigate

The clear navigation action (denoted by ⇒) will remove all views currently on the view stack and navigate to the target view.

For example:

  • Normal linking A → B → C → D will have [A, B, C, D] on the view stack Performing ⇒ E will result in a view stack of [E]

  • Also when ⇒’ing to a view already on the stack, e.g. A → B → C → D ⇒ B will result in [B]

The clear action is typically used when navigating away from a point in the app, where the navigation history is not needed anymore, for instance when a user logs out.

Syntax

navigate.clear(path, param1, param2, ...) — clear and navigate to the specified view path, passing params.

navigate.discard().clear('view_path', param1, param2, ...) — discard unsaved changes, clear and navigate to the specified view path, passing params.

Examples:

Using navigate.clear in xml:

<list>
    <list-item on-press="$:navigate.clear('login')" header="Log out" icon="ion-home"/>
</list>

The clear action will save view state by default, but can be chained to discard() navigate without saving. Using navigate.clear in JS, without saving view state:

function cancelTasks(){
    // other logic here
    navigate.discard().clear('tech_landing');
}

Using navigate.clear with params in xml:

<button on-press="$:navigate.clear('dashboard', query_range_str, query_range_end)" label="Dashboard" />

Please see the following section for deep linking to a view when opening a container:

resume Callback

A resume function may be defined on a view, which is called whenever the user returns to the view from a different view, either via a dismiss function or via the back button.

The resume function receives a single "from" parameter, with the following properties:

  • path: the path of view that the user returned from

  • dismissed: true if the dismiss() function or a dismiss link was used to return

  • back: true if the user used the back button to return

An example:

function resume(from) {
    if(from.dismissed && from.path == 'user/new') {
        dialog("New User", "A new user has been created");
    }
}

Resume functions may also chain further links. However, it is recommended to use a dismiss link instead.

Overriding the built-in back button

By default, the built-in back button has the same behavior as the discard() function.

This can be changed by specifying an on-back handler on the view. If the function triggers navigation or returns false, the default back behavior is suppressed. Otherwise, the default discard() is performed after the handler has completed.

Examples

<!-- Example 1: Save data when back is pressed. -->
<view title="Example" on-back="$:navigate.dismiss()">
    <!-- ... -->
</view>
<!-- Example 2: Confirm when going back. -->
<view title="Example" on-back="$:confirmBack()">
    <!-- ... -->
</view>
function confirmBack() {
    var confirmed = confirmDialog('Back', 'You will lose unsaved changes. Are you sure?', 'Yes', 'No').

    return confirmed;
}

Last updated