Create forms that only work when users are online

How to create online-mode extensions for Skedulo Plus.

Overview

Normally, data that users enter into a mobile form is synced asynchronously when the user presses “Save” or “Submit” on the root page and requires that data is fetched before the user can access the page.

Forms that use online-mode fetch functionality update the form data synchronously as the user interacts with it. In online mode, fetching data is executed only when the user opens the form, which means that the data is more current than what you would expect in normal forms.

If online mode is enabled for a form, then the user will be forced to have an internet connection in order to open the form.

Enable online mode in an extension

To enable online mode for a form, do the following steps:

  1. Enable fullOnlineMode in the ui_def file in the root:
  "settings": {
    "fullOnlineMode": true
  }
  1. Enable isRequiredOnline in metadata.json:
  "isRequiredOnline": true

Queries

A “query” is an operation that is defined to make a request directly to the Skedulo server (or externally) when online mode is in use.

Queries can be used to perform two actions:

  • Fetch data to display in the mobile app.

  • Push data to the Skedulo server to process further.

Two types of query can be used to either fetch or push data:

  • Standard queries that follow Skedulo standard definitions and data flow.

  • Custom queries, which use user-defined definitions and a custom endpoint.

Standard and custom queries can vary, with regards to their definition and usage, depending on the operation; even if these operations are a part of the same scenario for fetching or pushing data.

For example, a standard query definition for fetching multiple items for a list is not the same as a standard query definition for fetching a single item for a list.

Data-fetching queries

When a user accesses a page in a form, online mode usually attempts to make API calls to get the necessary data. This is referred to as a “data fetching” operation.

There are two approaches to making a RESTful request to get data: Standard fetching and custom fetching.

Standard fetching queries

A standard fetching query uses the standard data flow provided by the Skedulo MEX service to ease the development process of fetching the data.

Standard fetching queries have the following features:

  • Provides built-in APIs and definitions for fetching data
  • Data is fetched by building a GraphQL call from the endpoint based on the definition of the standard UI Definition provided by the Form developer
  • Form Builder doesn’t have to build anything regarding the server side. The form developer just need to take care about which data they want to get.

Standard fetching queries have the following limitations:

  • Data can only be fetched from the Skedulo database.
  • The data structure is determined by the Skedulo GraphQL database.

Example of a standard fetching query definition

// UI Definition
{
  "type": "standard",
  "object": "ObjectName",
  "fields": ["FieldA", "FieldB", ...],
  "filter": "...." /* Some calls won't have filter option */
}

Based on the values of object and fields, the standard flow will automatically construct the GraphQL format to make a call to Skedulo server to request data.

Custom fetching query

A custom fetching flow allows users to connect to their own endpoint or server with custom logic. Form developers need to build the custom logic for their endpoints and provide the custom API.

To construct a custom fetch call, custom functions must be used to return the required definitions from the custom endpoint.

The name “Custom” does not mean that the form builder can call whenever they want; it means that instead of calling the standard API endpoints, calls can be redirected to custom endpoints while adapting the online mode’s engine flow.

Custom fetching queries have the following advantages:

  • Provides a more flexible method of fetching data.

Custom fetching queries have the following limitations:

  • More difficult to maintain and stabilize.
  • More complex and so more difficult to build.

Example of a custom fetching query definition and function

// UI Definition
{
  "type": "custom",
  "function": "cf.getListHeaderData()"
}
// Custom Function
function getListHeaderData() {
  return {
    getBaseAxiosRequestConfig: () => {
      return {
        baseURL: "http://localhost:3000",
        method: "GET",
        url: "/jobProducts/get-header"
      }
    }
  }
}

Depending on the operation that is using this query, the function getListHeaderData can require more fields, but getBaseAxiosRequestConfig is always required, because we need to know where to call the endpoint. For some complex scenarios, we require more functions to handle the response returned from the server.

Where fetching queries are supported

  • Form Data Expresion Fetching: Form Properties | formDataExpression

  • Page Data Expression Fetching: Page Components | Online mode support (Required full online mode)

  • List Page Fetching: List Page Full Online Mode Source | Full Online Mode

  • Async Validation: Async Expression Validation

  • Data Observer: Page Components | dataObserver

  • Custom Button Async: Button Group Flat Page View Component | Make API Call with custom Behavior

Data-pushing queries

When using a form in the mobile application, it’s common to want to send the data back to the server to make changes or perform operations that only the server can handle. To do that in online mode, these operations have to make data-pushing queries.

Data-pushing queries are usually used in the following scenarios:

  • Insert new data.

  • Update existing data.

  • Remove existing data.

  • Others, such as pushing data for further processing or calculations.

As with data-fetching queries, there are two main types of queries: Standard pushing and custom pushing.

Standard pushing query

Standard pushing queries are in the standard Skedulo data flow for full online mode. Similar to fetching queries, standard pushing queries aim to reduce the effort required to build CRUD operations by providing built-in endpoints.

Standard pushing queries have the following features and advantages:

  • Provide built-in APIs and CRUD operation definitions.

  • Data is updated by building a GraphQL call from the endpoint based on the contents of the standard UI Definition provided by the form developer.

  • The form builder doesn’t have to build anything regarding the server side, only what data they want to update.

Standard pushing queries have the following limitations:

  • Can only update the data from the Skedulo database.

  • Can only update the database on the data structure provided by the Skedulo GraphQL database.

Depending on the operation (UPSERT or DELETE), the standard pushing query can require different definitions for each use.

Custom pushing query

As with the fetching queries, a custom pushing query works like a standard pushing query, but provides a more flexible way to handle the data and which endpoint takes care of the operation.

Form builder can build custom logic for the CRUD endpoints and data is sent via a custom API provided by the developer. To construct custom requests, custom functions must be used to return the required definitions from their custom endpoints.

Custom pushing queries have the following features and advantages:

  • Provides a more flexible method of pushing data.

Custom pushing queries have the following limitations:

  • More difficult to maintain and stabilize.
  • More complex to build.

As with fetching, the name “Custom” does not mean that the form builder can call whenever they want; it means that instead of calling the standard API endpoints, calls can be redirected to custom endpoints while adapting the online mode’s engine flow.

Example of a custom pushing query definition and function for a CRUD operation

The UI definition defines which custom function handles the custom pushing query.

// UI Definition
"query": {
  "type": "custom",
  "function": "cf.saveJobProductItem(pageData)"
},

The custom function does the following:

  • Returns the definition for how to call the custom pushing endpoint via getBaseAxiosRequestConfig.

  • Returns the definition for checking if a call has failed via determineIfError. If it fails, it decides which message is called via getErrorMessage.

// Custom Function
function saveJobProductItem(pageData) {
  return {
    getBaseAxiosRequestConfig: () => {
      return {
        baseURL: "http://localhost:3000",
        method: "POST",
        url: "/jobProducts/save-item",
        data: {...pageData}
      }
    },
    determineIfError: (response) => {
      return !response.data
    },
    getErrorMessage: (response, error) => {
      if (error != null) {
        return {
          title: "From exception",
          description: "Exception: " + error
        }
      }
      if (!response.data) {
        return {
          title: "Return false ==> error",
          description: "data is false"
        }
      }
      return {}
    }
  }
}

As with fetching, some complex operations may require more definition returned from the custom function or the ui definition, so do not rely on this example alone to implement all custom pushing operations.

Where data-pushing queries are supported

  • Flat Page Upsert operation in flat page components
  • Flat Page Delete operation in flat page components