# Welcome to Jigx Documentation

Jigx simplifies mobile app development from start to finish in three steps. You can build native iOS and Android apps with familiar frameworks and tools like JavaScript, SQL, YAML, and Visual Studio Code.

<a href="/pages/lzV841bKSnDTEWQBMTnS" class="button primary">Getting Started</a>

<figure><img src="/files/u82E7mGOIyGoCRhmHy4X" alt=""><figcaption></figcaption></figure>

***

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><a href="/pages/an2Soz29ANYcdjo8iz0R">Install</a></td><td>Install the Jigx Builder extension in Microsoft Visual Studio and create your Jigx's solutions.</td><td></td></tr><tr><td><a href="/pages/yzR4vzaAGg3gJAAAzrEl">Build</a></td><td>Start creating your mobile apps, use intellisense prompts and code completion to speed up development.</td><td></td></tr><tr><td><a href="/pages/MbccaAZUfezKGZhyJFq5">Data</a></td><td>Integrate with with your business's datasources, REST, Salesforce and more, or use Jigx's built in real-time datastore.</td><td></td></tr><tr><td><a href="/pages/PdzRDgoDHiUxpes8rSPZ">UI</a></td><td>Choose from a range of available components, add actions and integrate these with your data to create powerful apps.</td><td></td></tr><tr><td><a href="/pages/8mniE5eGc1RZfT1Z3PI1">Logic</a></td><td>Structure and manipulate data before binding the data to the UI using JSONata expressions, or use states to manage inputs at runtime.</td><td></td></tr><tr><td><a href="/pages/LrDzQIvcdLA1lqTH7yRY">Manage</a></td><td>Manage your organization details, users, and solutions, send push notifications, and configure authorization and authentication.</td><td></td></tr></tbody></table>

***

***


# Getting started

Jigx account creation, Install the Jigx builder and steps by step tutorial

**📌 How to build mobile apps to enhance your organization's work experience.**

### Prerequisites

Before you can start building your first Jigx solution, you require the following prerequisites.

* [Creating an account](/getting-started/creating-an-account). You need a Jigx account with at least creator rights within an organization to publish and modify a solution.
* [Microsoft Visual Studio Code](https://code.visualstudio.com/) installed on your computer. This is required for the Jigx Builder which is a Microsoft Visual Studio Code extension.
* [Install the Jigx Builder](/getting-started/install-the-jigx-builder) extension in Microsoft Visual Studio Code.

### Let's get you building solutions *fast*.

* [Use templates](/getting-started/use-templates-to-create-apps)
* [Create from scratch](/getting-started/create-an-app-from-scratch)
* [Use pre-built solutions](/getting-started/use-pre-built-solutions)

### Want to know more?

* Get an overview of the [Jigx platform](/understanding-the-basics/architecture)
* Understand [Jigx Concepts](/understanding-the-basics/jigx-concepts)
* Create with [Jigx Builder](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/jigx-builder-code-editor.md)
* Explore [examples](https://docs.jigx.com/examples)
* [Managing](/administration/management-overview) apps, users, roles, and organizations


# Creating an account

To build and use Jigx solutions you require a Jigx account. You can create an account by registering on the <https://www.jigx.com/> Jigx website or via an invitation from your organization. Follow the steps below to create an account.

## Register

Register at [manage.jigx.com/register](http://manage.jigx.com/register) to create an account.

### Sign up

1. Add your full name, surname, and work email address, and click the **signup** button.

{% hint style="info" %}
Registering with a non-work email e.g. Gmail does not check for existing organizations or allow other people to find your organization during registration. To join or share your organization you need to invite people from Jigx Management.
{% endhint %}

<figure><img src="/files/Jv80t5SA8xbZnMRcQqwT" alt="Registration screen" width="375"><figcaption><p>Registration screen</p></figcaption></figure>

### Verify your email

1. Enter the **Pin code** received in the email into the Pin screen.
2. Create a **password** following the Jigx password requirements (as displayed on the screen) and click **Continue**.

<figure><img src="/files/cypduhacmoYQLRTCVrln" alt="Registration Pin code" width="262"><figcaption><p>Registration Pin code</p></figcaption></figure>

### Join or create an organization

1. Next any organizations linked to your email domain will be displayed and you can click the **Join** button or **Request to join** button next to your organization name.
2. Alternatively, you can choose to create a new organization by clicking the link, providing a name, and deciding who can see or join your organization based on the email domain.
3. Next Jigx Management opens on the **Quick Start** screen. Now you are ready to start building, using, and administering Jigx solutions.

<figure><img src="/files/BtXbYakfa3qtBi7TwMlD" alt="Create an organization" width="375"><figcaption><p>Create an organization</p></figcaption></figure>

## Invitation

Your organization's Jigx administrator sends an onboarding email invitation to your inbox. This invitation includes instructions on how to download your Jigx app.

<figure><img src="/files/58zSX4LSzMpWTag84HLg" alt="Jigx invitation email" width="375"><figcaption><p>Jigx invitation email</p></figcaption></figure>

The Jigx app is available on your iOS and Android apps and works on any device.

* Download the Jigx iOS app from [App Store](https://apps.apple.com/sg/app/jigx/id1495596537)
* Download the Jigx Android app from [Google Play Store](https://play.google.com/store/apps/details?id=com.jigx.android\&pli=1)

### Getting started

Once you have downloaded the app, tap on the Jigx icon. Now tap the **Get Started** button and fill in your email address

<figure><img src="/files/5GpwihBDfaF0e1Rqtydv" alt="Welcome and sign in" width="375"><figcaption><p>Welcome and sign in</p></figcaption></figure>

### 2-Step Verification

Once you tap the **Continue** button an email with your 6-digit long pin code is sent to your inbox.

<figure><img src="/files/YxSRbdZYxPR1R6lUlPWJ" alt="Jigx app verification email" width="375"><figcaption><p>Jigx app verification email</p></figcaption></figure>

Enter the One-Time Password (OTP) received in the email into the 2-Step verification screen. After entering your OTP code the password setup screen opens. Create a password following the Jigx password requirements (as displayed on the screen).

{% columns %}
{% column %}

<figure><img src="/files/jRThB9dwge2DED6QT1Xa" alt="2-Step verification screen" width="188"><figcaption><p>2-Step verification screen</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/VzRQlGVD6HkBphjcNoEh" alt="New Password screen" width="188"><figcaption><p>New Password screen</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### Home Hub

Once your new password is set, the [Home Hub](/building-apps-with-jigx/ui/home-hub) screen displays.

* When there are no solutions assigned to your account the home hub is empty. Assign solutions on the [Jigx Management](https://manage.jigx.com/) website
* If you have solutions assigned to your Jigx account, you will see the assigned solution on the Home Hub.


# Install the Jigx Builder

With Jigx, you build native mobile solutions in [Microsoft Visual Studio Code](https://code.visualstudio.com/), a development environment installed on many platforms, including Windows and Mac. Jigx extends VS Code with the Jigx Builder, an extension that allows you to build rapidly, test, and publish Jigx mobile apps.

## Installing Microsoft Visual Studio Code and the Jigx Builder extension

Start by downloading and installing VS Code on your development machine. The Jigx Builder extension is in the Microsoft [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=Jigx.jigx-builder). Click on the VS Code extension icon in the left navigation bar and search for Jigx Builder. Go ahead and install it.

{% columns %}
{% column width="41.66666666666667%" %}
The Jigx Builder now appears under your list of installed extensions and is automatically added to the side pane and is identifiable by its unique icon.
{% endcolumn %}

{% column width="58.33333333333333%" %}

<figure><img src="/files/vJ6XbhOcM2Edu25vF4Mq" alt="Jigx Builder installed"><figcaption><p>Jigx Builder installed</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

Build Jigx projects by using the Jigx Builder extension and use YAML, SQL, JSON, and JSONata.

The Jigx Builder YAML editor includes code completion by simultaneously pressing the control and spacebar **(ctrl+space)** keys. Only valid options in the current cursor context display in the code popup.


# Use templates to create apps

### What you will create

Create a travel app using one of the provided templates. The template inserts the required YAML in the correct format. Use the template as a base on which to build when creating a jig. If the template by default provides the functionality you need, publish your Jigx project to use the jig on your mobile device. \
**Build time:** 5 mins

<figure><img src="/files/o5mLv9rMNkXuhIanIohG" alt="" width="375"><figcaption></figcaption></figure>

{% hint style="info" %}
Before you start building your first solution, ensure you have created a [Jigx's account](/getting-started/creating-an-account) and [Install the Jigx Builder](/getting-started/install-the-jigx-builder).&#x20;
{% endhint %}

#### Step 1: Create a new solution in Jigx Builder

1. Open VS Code, and click on the Jigx Builder **icon** in the left navigation bar. Select the **Create New Jigx Solution** button.
2. Type **World Travel** in the Solution title field and press enter. This name displays at the top of your solution on the Home Hub in the Jigx App.
3. The *Solution name* field automatically pre-populates with the solution's system name world-travel. Press **Enter.**
4. For this solution select the **business** category.
5. Select a local folder where the project files are saved too. Your Jigx default solution files open in the VS Code editor with the .jigx extensions ready for editing.

{% columns %}
{% column %}

<figure><img src="/files/9kTJgmU6h35jtaxH4lqs" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/mZsnRERvxWkxB9fjpSYh" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Step 2: Choose a template

<figure><img src="/files/YfVWgAm541WrQNJ5G3IV" alt=""><figcaption></figcaption></figure>

1. In Explorer expand the **jigs** folder and click on `myfirstjig.jigx` file. The Jigx auto-complete popup displays.
2. Click on **use template** to open the list of templates.
3. Under **Default** hover-over \*\*Default jig 6 \*\*and click the blue insert button.
4. The jigx file is populated with the YAML for the template.
5. Change the title to ***Thailand*** as the `title` for your jig.
6. The `myfirstjig.jigx` file is already referenced in the `index.jigx` file which is the home screen file (Home Hub).

{% columns %}
{% column %}

<figure><img src="/files/vbkUenYPT5cmAMgje42D" alt="" width="375"><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/ifkuGFjnuc8VY7GUpdgu" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Step 3: Publish the solution

{% columns %}
{% column %}

1. In VS Code click on the Jigx Builder **icon** in the left navigation bar.
2. In the Jigx Explorer hover over the **world-travel** node till you see the **publish** **icon (rocket)**. Click on the icon to start the publishing process.
3. Enter your Jigx username and press **Enter**.
4. Enter your Jigx password and press **Enter**. The publishing process starts and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/HlhgfpWtzqEDOEiGGopi" alt="Publish Jigx project"><figcaption><p>Publish Jigx project</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Step 4: Open the app on your mobile device

{% columns %}
{% column %}

1. On your mobile device **tap** the Jigx app icon.
2. Sign into the app with your [Jigx account](/getting-started/creating-an-account) details.
3. The app opens the [Home Hub](/building-apps-with-jigx/ui/home-hub) screen displaying the **World Travel** solution.
4. Tap on the icon to display the **Thailand** destination screen.&#x20;

{% endcolumn %}

{% column %}

<figure><img src="/files/o5mLv9rMNkXuhIanIohG" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="success" %}
Yes it is that simple to build apps in Jigx. Explore further by either editing the YAML in `myfirstjig.jigx`; or adding additional files under the jig folder, add another template, reference the file in `index.jigx` and publish the solution.&#x20;
{% endhint %}

### What's next?

Why not build your own app? See how to [plan your app](/getting-started/planning-your-app), then learn how to [create an app from scratch](/getting-started/create-an-app-from-scratch) or explore the various available UI elements in Jigx by adding the **Jigx-samples** [prebuilt solution](/getting-started/use-pre-built-solutions) to your organization and viewing the solution in the Jigx App.


# Create an app from scratch

### What you will learn

In this quick guide, you will learn the basics of Jigx and how easy it is to create mobile apps. Basic Jigx concepts are introduced, such as collecting information, working with data in SQLite, navigating between screens, and passing parameters.

### What you will create

{% columns %}
{% column %}

<figure><img src="/files/rXGOrJI40eY8noEN43u4" alt="Hello Jigx Solution" width="188"><figcaption><p>Hello Jigx Solution</p></figcaption></figure>
{% endcolumn %}

{% column %}
The solution is named **Hello-Jigx** and consists of a map showing a location, a calendar with events, a form to capture and view data, and a list showing the captured data. The table below guides you through building each element of the solution.
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}

1. Before you start building your first solution ensure you have created a [Creating an account](/getting-started/creating-an-account) and [Install the Jigx Builder](/getting-started/install-the-jigx-builder). Get an overview of the [Jigx platform](/understanding-the-basics/architecture) and an understanding of the [Jigx Concepts](/understanding-the-basics/jigx-concepts).
2. We recommend you build out all the solution steps below, as each solution step builds on the previous step until you have a functioning mobile app.
   {% endhint %}

### Solution Steps

There are several [types](/building-apps-with-jigx/ui/jigs-_screens_#jig-types) of jigs you can build. They are default, document, calendar, composite, and list. Below are step-by-step guides that use these jig types. Each solution step builds on the previous step until you have a functioning mobile app. Each solution provides an overview, explaining the Jigx's concepts introduced in the step, and code samples with comments.

[Step 1: Create the Hello Jigx solution project](/getting-started/create-an-app-from-scratch/create-the-hello-jigx-solution-project) Start by creating the Hello Jigx project in VS Code \
**Build time**: 2 min

[Step 2: Create the Map](/getting-started/create-an-app-from-scratch/create-the-map-1) Build a map jig that displays a specific location on a map, with an icon for the jig. \
**Build time**: 10 min

[Step 3: Create the Calendar](/getting-started/create-an-app-from-scratch/create-the-calendar) Next, add a calendar jig that displays a week with the events, meetings, and relevant details. \
**Build time**: 10 mins

[Step 4: Create Data - forms & lists](/getting-started/create-an-app-from-scratch/create-data-form-_-list) Build a jig to add a new customer by capturing the customer's details using a form. Then add a jig to list all the customers created using the form. Add the ability to view, and edit these customer records. \
**Build time**: 20 mins

[Step 5: Combine the solution's elements](/getting-started/create-an-app-from-scratch/combine-the-solution_s-elements) Now you have built a solution that shows a location on a map, a calendar with detailed entries, and a new customer form and list in a single solution. Let us expand the solution further by joining the new customer form and list into one jig, then add a jig header to the new customer jig. \
**Build time**: 15 mins

[Step 6: Customize the Hello-Jigx solution](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution) Extend your solution with styling changes and additional functionality. Replace the map icon with a location widget in the map.jigx file, and replace the people icon with the image widget in the composite.jigx file. Change the calendar icon and add a badge to display the number of events for the week. \
**Build time**: 10 mins

### What's next?

Why not build your own app? See how to [plan your app](/getting-started/planning-your-app), then learn how to [Use templates to create apps](/getting-started/use-templates-to-create-apps) or explore the various available UI elements in Jigx by adding the **Jigx-samples** [prebuilt solution](/getting-started/use-pre-built-solutions) to your organization and viewing the solution in the Jigx App.


# Create the Hello Jigx Solution project

Every solution you build is contained in a Jigx project. You can name your solution, select from a predefined list of categories and determine where the solution files will be located, which could be locally, or you can connect VS Code to a GitHub repository. Your project is preloaded with the required Jigx files ready for you to configure.

{% hint style="success" %}
We recommend you build out all the solution steps for the [Create an app from scratch](/getting-started/create-an-app-from-scratch), as each solution step builds on the previous step until you have a functioning mobile app.
{% endhint %}

{% columns %}
{% column %}

## Steps

1. Open VS Code, and click on the Jigx Builder **icon** in the left navigation bar. Select the **Create New Jigx Solution** button.
2. Type **Hello-Jigx** in the Solution title field and press enter. This name displays at the top of your solution on the Home Hub in the Jigx App.
3. The Solution name field pre-populates with the solution's system name. Jigx derives the system name from the solution title you provided in the previous step. You can provide a different solution name if you want. Take note of the following naming restrictions:
   1. Cannot start with a number.
   2. No spaces are allowed. Hyphens replace spaces.
   3. Must be in lowercase.
4. Select a relevant category where you want the solution saved. The category you select displays at the top of your solution in the [Home Hub](/building-apps-with-jigx/ui/home-hub). For this solution select the **business** category. Select a local folder where the project files are saved too. Your Jigx default solution files open in the VS Code editor with the .jigx extensions ready for editing.
   {% endcolumn %}

{% column %}

<figure><img src="/files/LpM5oPbsgn09b0ok6Jxc" alt="Jigx project in VS code"><figcaption><p>Jigx project in VS code</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

## Steps

1. Open VS Code, and click on the Jigx Builder **icon** in the left navigation bar. Select the **Create New Jigx Solution** button.
2. Type **Hello-Jigx** in the Solution title field and press enter. This name displays at the top of your solution on the Home Hub in the Jigx App.
3. The Solution name field prepopulates with the solution's system name. Jigx derives the system name from the solution title you provided in the previous step. You can provide a different solution name if you want. Take note of the following naming restrictions:
   1. Cannot start with a number.
   2. No spaces are allowed. Hyphens replace spaces.
   3. Must be in lowercase.
4. Select a relevant category where you want the solution saved. The category you select displays at the top of your solution in the [Home Hub](/building-apps-with-jigx/ui/home-hub). For this solution select the **business** category. Select a local folder where the project files are saved too. Your Jigx default solution files open in the VS Code editor with the .jigx extensions ready for editing.
   {% endcolumn %}

{% column %}

<figure><img src="/files/Q6XGSaW4bwRbMC7wjBKL" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

## See Also

* [Jigx overview](/understanding-the-basics/architecture)
* [Jigx Concepts](/understanding-the-basics/jigx-concepts)


# Create the Map

Learn how to build your first jig by using this simple step-by-step guide that displays a marker on a map. The solution uses the [jig.default](https://docs.jigx.com/examples/jigdefault) type with an icon and a [static data](https://docs.jigx.com/examples/static) source. At the end of this step-by-step, you will have built a solution that can display a location marker on a map as shown. See [Jigx Concepts](/understanding-the-basics/jigx-concepts) to learn what jigs and widgets are.

{% hint style="success" %}
We recommend you build out all the solution steps for the [Create an app from scratch](docId:8SeLgEopqiL70vPoV72WY), as each solution step builds on the previous step until you have a functioning mobile app.
{% endhint %}

{% columns %}
{% column %}

## Steps

1. [Create the Hello Jigx project](/getting-started/create-an-app-from-scratch/create-the-hello-jigx-solution-project) in the Jigx Builder.
2. [Add the jig.default](/getting-started/create-an-app-from-scratch/create-the-map-1/adding-the-map-jig) with an icon, and static data source.
3. [Publish the project](/getting-started/create-an-app-from-scratch/create-the-map-1/publish-the-project).
4. [Open the Jigx mobile app](/getting-started/create-an-app-from-scratch/create-the-map-1/run-the-solution-in-the-app), click on the location jig, and view the map.
   {% endcolumn %}

{% column %}

<figure><img src="/files/qzGEwPq97cokOxIunEQ1" alt="" width="375"><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

## GitHub samples

You can download the [Hello Jigx solution project](https://github.com/jigx-com/jigx-samples/tree/main/quickstart/hello-jigx-solution) on GitHub or build it yourself by following the detailed steps in this section.

## See Also

* [Jigx Architecture](/understanding-the-basics/architecture)
* [Jigx Concepts](/understanding-the-basics/jigx-concepts)


# Adding the Map Jig

## Overview

In this section, there are two files to edit, namely, `index.jigx` and `myfirstjig.jigx`. In the `index.jigx` file, you configure the bottom navigation tab to display the `myfirstjig.jigx` on the Jigx mobile app [Home Hub](/building-apps-with-jigx/ui/home-hub) screen. In the myfirstjig jigx file, you will specify the default [type](/getting-started/create-an-app-from-scratch/create-the-map-1/adding-the-map-jig) of jig, assign an icon for the jig, and provide a [static datasource](/getting-started/create-an-app-from-scratch/create-the-map-1/adding-the-map-jig) that provides the location on the map.

{% hint style="success" %}
See [Jigx Concepts](/understanding-the-basics/jigx-concepts) to learn what jigs are.
{% endhint %}

### Steps

{% hint style="info" %}
The Jigx Builder YAML editor includes **code completion by simultaneously pressing the control and spacebar (ctrl+space)** buttons. Only valid options in the current cursor context are displayed in the code popup.
{% endhint %}

#### Edit the index.jigx file

1. Click on the `index.jigx` file. This file is the menu structure of the app. In the `index.jigx` file you configure the navigation menu that displays at the bottom of the Jigx mobile app [Home Hub](/building-apps-with-jigx/ui/home-hub) screen.
2. **Save** the project.
3. Your index.jigx file should resemble the code below.&#x20;

{% code title="index.jigx" %}

```yaml
# The system name that uniquely identifies the solution
name: hello-jigx
# The friendly name of the solution
title: Hello-Jigx
# The built-in category selected for this solution
category: business
# The top-level navigation elements for jigs, displayed at the bottom of the app
tabs:
  home:
    label: home
    jigId: myfirstjig
    icon: home-apps-logo
```

{% endcode %}

#### Add the map to the jig

1. In Explorer expand the **jigs** folder and right-click on `myfirstjig.jigx` file and rename the file to map.jigx. Click to open the file, the Jigx auto-complete popup listing the five jig types displays. For this solution, we will be using the **default** jig to create the UI for displaying data. Click on **Default** to open the skeleton YAML created by the Jigx Builder.
2. Add ***Location with address*** as the `title` for your jig. The title appears under the widget on the Home Hub. Add a description for the jig, such as map with a marker.
3. On the line under `type:`, type `icon:`. To select an icon from the predefined list start typing the first two letters of the name of the icon, in this case *lo,* the list of icons starts to populate as you type. Select `location` from the list. This icon displays on the widget on the Home Hub.
4. Delete the `header`, and `onFocus` section, you will add a header later in the [Combine the solution's elements](/getting-started/create-an-app-from-scratch/combine-the-solution_s-elements) section.
5. The map jig needs a `datasource:` defined that provides the location details. You will use a [static datasource](/getting-started/create-an-app-from-scratch/create-the-map-1/adding-the-map-jig) in this step. The static dataset is created directly inside the jig file of the Jigx solution, and there is no need to specify any database connections or set up any tables. The amount of records that can be created for the static data is unlimited and is used to bind data to the UI components.
6. Replace `mydata:` with `address:` press **ctrl+space (Intellisense)** and select `Static Datasource`.
7. Define the location details for the street, city and country under the `data:`tag. You can remove `id:1`. Add your own location or use the following as an example: 768 5th Ave, New York, US.
8. The controls displayed on the jig are defined under the `children:` node on a default jig. The output control is placed on the location component to display a map/location inside the jig. Under the `children:` node press **(ctrl+space)** and select **Location** from the list.
9. For the output control to display the map with the location you will use the address from the datasource using an [expression](/building-apps-with-jigx/logic/expressions) to return the street, city and country to the location component. Next to `options:` press **(ctrl+space)** and select **address** from the list. To add the expression next to the `address:` line press **(ctrl+space)** and select **=@ctx** from the list. The root element of expressions in .jigx files always starts with "@ctx" vs. "$." in JSONata Exerciser (e.g. @ctx.data vs. $.data). Add the following to your expression: `address: =@ctx.datasources.address.street & ',' & @ctx.datasources.address.city & ',' & @ctx.datasources.address.country`
10. To ensure that the location marker can be seen on the map add a `zoomLevel: 9` under the address line.
11. **Save** the project.
12. Your map.jigx file should resemble the code below.

{% code title="map.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Location with address
description: map with a marker
# The jig type used to display data
type: jig.default
icon: location

# The type of datasource used to return data in the jig
datasources:
  address: 
  # The static dataset is created directly inside the jig file
    type: datasource.static
    options:
      data:
        - street: 768 5th Ave
          city: New York
          country: US
# The control used by the jig to display a location          
children:
# The component location is an interactive map displaying the location using the address
  - type: component.location
    options:
      viewPoint:
        address: =@ctx.datasources.address.street & ',' & @ctx.datasources.address.city & ',' & @ctx.datasources.address.country
        zoomLevel: 9
```

{% endcode %}

#### Update the jigId in the index.jigx file

1. Click on the `index.jigx`.
2. Change the `JigId` from myfirstjig to map.
3. Your index.jigx file should resemble to the code below.

{% code title="index.jigx" %}

```yaml
# The system name that uniquely identifies the solution
name: hello-jigx-solution
# The friendly name of the solution
title: Hello-Jigx Solution
# The built-in category selected for this solution
category: business
#The tab that act as top-level navigation elements for jigs
tabs:
  home:
    jigId: map   
    icon: location
```

{% endcode %}

### See Also

* [Jigx overview](/understanding-the-basics/architecture)
* [Jigx Concepts](/understanding-the-basics/jigx-concepts)


# Publish the project

## Overview

With the Hello Jigx project created, and the jig added you are ready to publish your solution to the Jigx Cloud.

{% columns %}
{% column %}

### Steps

1. In VS Code click on the **Jigx Builder** icon in the left navigation bar.
2. In the Jigx Explorer hover over the hello-jigx node till you see the **publish** **icon (rocket)**. Click on the icon to start the publishing process.
3. Enter your Jigx username and press **Enter**.
4. Enter your Jigx password and press **Enter**. The publishing process starts and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/T3aAlo2gFPHWZYhutaQw" alt="Publish Jigx project"><figcaption><p>Publish Jigx project</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
When you build and publish a solution you automatically become the owner of the solution. Access to the solution is managed by [Permissions](/administration/solutions/permissions) assigned in [Jigx Management](/administration/management-overview). Here you give users access to the solution, define their role in the solution scope and assign `Solution Group` membership for the visibility of widgets.
{% endhint %}

### See Also

* [Jigx overview](/understanding-the-basics/architecture)
* [Jigx Concepts](/understanding-the-basics/jigx-concepts)


# Run the solution in the app

With the Hello Jigx solution published to the Cloud, you are ready to use the solution in the Jigx mobile app.

{% columns %}
{% column %}

## Steps

1. On your mobile device **tap** the Jigx app icon.
2. Sign into the app with your [Jigx account](/getting-started/creating-an-account) details.
3. The app opens the [Home Hub](/building-apps-with-jigx/ui/home-hub) screen displaying the Hello Jigx solution, with the map widget and location icon.
4. Tap on the icon to display the location on the map.&#x20;

{% endcolumn %}

{% column %}

<figure><img src="/files/qzGEwPq97cokOxIunEQ1" alt="Map jig on Home Hub"><figcaption><p>Map jig on Home Hub</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
As you build and publish more solutions to your Jigx mobile app, you can toggle between the solutions by clicking on the home icon, and selecting the solution you want to use. The number badge on the home icon shows how many solutions are available to you.
{% endhint %}

**Congratulations** you have built, published, and used the Hello Jigx solution. Why not try building the next step in the [Build your first Jigx solution](/getting-started/create-an-app-from-scratch/create-the-calendar).

## See Also

* [Jigx overview](/understanding-the-basics/architecture)
* [Jigx Concepts](/understanding-the-basics/jigx-concepts)


# Create the Calendar

## Overview

Learn how to add a second jig to your Hello Jigx project using the ***jig.calendar*** type with an icon and a [static data source](https://docs.jigx.com/examples/static). At the end of this step-by-step, you have added a calendar jig to the [Home Hub](/building-apps-with-jigx/ui/home-hub) that can display a week, the events, meetings, and the relevant details for each, as shown below.

{% hint style="success" %}
We recommend you build out all the solution steps for the [Create an app from scratch](/getting-started/create-an-app-from-scratch/create-the-calendar), as each solution step builds on the previous step until you have a functioning mobile app.
{% endhint %}

{% columns %}
{% column %}

### Steps

1. Open the Hello-Jigx solution in the Jigx Builder in VS Code.
2. [Add the calendar jig and datasource](/getting-started/create-an-app-from-scratch/create-the-calendar/add-the-calendar-jig-and-datasource) with an icon, and static data source.
3. [Publish your project](/getting-started/create-an-app-from-scratch/create-data-form-_-list/publish-your-project).
4. [Run the updated solution](/getting-started/create-an-app-from-scratch/create-the-calendar/run-the-updated-solution) in the Jigx mobile app, click the calendar icon, and view the week's meetings and events.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/NQAZZD7pKeV18UL54YZn" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### GitHub Sample

You can download the [Hello Jigx solution project](https://github.com/jigx-com/jigx-samples/tree/main/quickstart/hello-jigx-solution) on GitHub or build it yourself by following the detailed steps in this section.


# Add the calendar jig and datasource

## Overview

In this section, you will learn how to add a second jig file to the Hello Jigx project and add the calendar jig next to the map jig on the [home hub](/building-apps-with-jigx/ui/home-hub). You create a data source file in the datasource folder containing the calendar details that provide the data for the week, events, meeting subjects, dates, and times.

{% hint style="success" %}
See [Jigx Concepts](/understanding-the-basics/jigx-concepts) to learn what jigs, widgets, and the Home Hub are.
{% endhint %}

### Steps

#### Add the calendar-data.jigx data source file

1. You first need to add data that the calendar jig can read from. For this step, you create a `Static Datasource` in the datasource folder of the project, which is automatically synced to the Jigx Cloud. Likewise, data updated on the Jigx Cloud automatically syncs to the device. **Right-click** on the `datasources` node in Explorer and select **New file**.
2. Name the file **calendar-data**. Jigx automatically adds the **.jigx** extension to your file. The Jigx auto-complete popup displays the data source options. Select **Static datasource** from the list.
3. Under the data node, you need to provide the details for the events in the calendar. The following fields are available for use with each event entry, you can add your own event entries or use the code example below.

{% code title="datasource" %}

```yaml
type: datasource.static
options:
  data:
    - id: 1
      eventEnd: 2 
      eventStart: 1 
      location: Redmond, WA 
      people:
        - avatarUrl: https://randomuser.me/api/portraits/men/1.jpg   
          fullName: Tim Cook 
      tags:
        - color: color2 
          title: Negotiation 
      title: Negotiation with Company A
```

{% endcode %}

4\. Once you have added the fields your calendar-data.jigx file should resemble the code below.

{% code title="calendar-data.jigx" %}

```yaml
# A global static datasource that allows easy access and reusability to the data across various jigs and components
type: datasource.static
options:
  data:
    - id: 1
      eventEnd: 2 
      eventStart: 1 
      location: Redmond, WA 
      people:
        - avatarUrl: https://randomuser.me/api/portraits/men/1.jpg   
          fullName: Tim Cook 
      tags:
        - color: color2 
          title: Negotiation 
      title: Negotiation with Company A
    - id: 2
      eventEnd: 4
      eventStart: 2  
      location: Palo Alto, CA
      people:
        - avatarUrl: https://randomuser.me/api/portraits/men/49.jpg
          fullName: Michael Tate
      tags:
        - color: color5
          title: Qualification
      title: Demo for Company B
    - id: 3
      eventEnd: 25
      eventStart: 24
      location: Menlo Park, CA
      people:
        - avatarUrl: https://randomuser.me/api/portraits/men/90.jpg
          fullName: Michael Tong
      tags:
        - color: color6
          title: Verbal
      title: Sign contract  
```

{% endcode %}

#### Add a calendar jig file

1. Open the Hello-Jigx solution in the Jigx Builder in VS Code, **right-click** on the jigs node in Explorer, and select **New file**.
2. Name the file **calendar**.
3. The file opens and shows the Jigx's auto-complete popup listing the five jig types. For this solution, we will be using the **Calendar** jig to create the UI for displaying data in a calendar format. Click on **Calendar** to open the skeleton YAML created by the Jigx Builder.
4. On the line under `type:`, type `icon:`. To select an icon from the predefined list start typing the first two letters of the name of the icon, in this case \*ca, \*the list of icons starts to populate as you type. Select **calendar-3** from the list. This icon displays on the widget on the Home Hub of the Jigx App.
5. Delete the `header`, `onFocus` and `datasources` section. You created the calendar-data.jigx datasource file in the step above, now you can reference the data from the jig file by using an expression. At the data node add `calenar-data` so that it resembles `data: =@ctx.datasources.calendar-data`. With expressions, you can structure data before binding them to the UI components.

{% hint style="info" %}
Expressions are JSONata language-based. Learn more about :Link\[JSONata]{href="<https://jsonata.org/>" newTab="true" hasDisabledNofollow="false"} and try out your expressions in their :Link\[JSONata Exerciser]{href="<https://try.jsonata.org/>" newTab="true" hasDisabledNofollow="false"}. The root element of Expressions in .jigx files always starts with "@ctx" vs. "$$." in JSONata Exerciser (e.g. @ctx.data vs.$$.data). Jigx supports shorthand $ expressions for JSONata.
{% endhint %}

6\. The `component.event` type is used to display events related to the data records. Use **(ctrl+space)** next to each field to select the value you want returned.

7\. To display the date in UTC format we use a JSONata expression to convert the date from milliseconds to UTC for both the start and end date. Add the following expression under `from:` for the start date.

`from: =$fromMillis($toMillis($now()) + @ctx.current.item.eventStart * 3600000)`

For the end date under `to:` add the following expression:

`to: =$fromMillis($toMillis($now()) + @ctx.current.item.eventEnd * 3600000)`

For `title`, `location`, `people` and `tags` use **(ctrl+space)** after the `=@ctx.current.item`. to select the value available from the datasource.

{% code title="YAML" %}

```yaml
options:
    title: =@ctx.current.item.title
    # Use a jsonata expression to get the date in milliseconds and then convert it to UCT for the start time 
    from: =$fromMillis($toMillis($now()) + @ctx.current.item.eventStart * 3600000)
    # Use a jsonata expression to get the date in milliseconds and then convert it to UCT for the end time
    to: =$fromMillis($toMillis($now()) + @ctx.current.item.eventEnd * 3600000)
    location: =@ctx.current.item.location
    people: =@ctx.current.item.people
    tags: =@ctx.current.item.tags
```

{% endcode %}

8\. Your calendar.jigx file should resemble the code below.

{% hint style="info" %}
The Jigx Builder YAML editor includes **code completion by simultaneously pressing the control and spacebar (ctrl+space)** buttons. Only valid options in the current cursor context are displayed in the code popup.&#x20;
{% endhint %}

{% code title="calendar.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Calendar
# The jig type used to display a calendar with the current date
type: jig.calendar
# icon that displays on the widget on the home hub
icon: calendar-3

# The expression that structures the data from the datasource before binding it to the jig. Expressions are JSONata based
data: =@ctx.datasources.calendar-data

item:
  type: component.event
  options:
    title: =@ctx.current.item.title
    # Use a jsonata expression to get the date in milliseconds and then convert it to UCT for the start time 
    from: =$fromMillis($toMillis($now()) + @ctx.current.item.eventStart * 3600000)
    # Use a jsonata expression to get the date in milliseconds and then convert it to UCT for the end time
    to: =$fromMillis($toMillis($now()) + @ctx.current.item.eventEnd * 3600000)
    location: =@ctx.current.item.location
    people: =@ctx.current.item.people
    tags: =@ctx.current.item.tags
```

{% endcode %}

#### Add the calendar jigId in the index.jigx file

1. Click on the `index.jigx` file to add the calendar jig menu item to appear on the Home Hub screen next to map. Under the `tabs:` section **add** the following: `jigId: calendar`, `jigId: calendar`, `icon: calendar` and **save** the project.
2. Your index.jigx file should resemble the code below.

{% code title="index.jigx" %}

```yaml
# The system name that uniquely identifies the solution
name: hello-jigx-solution
# The friendly name of the solution
title: Hello-Jigx Solution
# The built-in category selected for this solution
category: business
#The widgets that act as top-level navigation elements for jigs
tabs:
  home:
    jigId: map
    icon: location
  calendar:
    jigId: calendar
    icon: calendar
```

{% endcode %}


# Publish your project

## Overview

With the calendar jig added to the Hello Jigx project, you are ready to publish the solution to the Jigx Cloud. If you are the owner of the solution, you do not need your Jigx app credentials again to publish the update.

{% columns %}
{% column %}

### Steps

1. In VS Code click on the **Jigx Builder** icon in the left navigation bar.
2. In the Jigx Explorer hover over the Hello Jigx node till you see the **publish icon (rocket)**. Click on the icon to start the publishing process.
3. Click **Publish** on the confirmation message screen.
4. The publishing process starts, and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/WSKVzX6VFFrc58aL1APh" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
You can use the shortcut keys straight from the file you in:

* Publish all files in Jigx solution on Mac is `⌘R⌘R`, and on Windows is `Alt+R Alt+R`
* Publishing an individual file on Mac is `⌘R⌘F`, and on Windows is `Alt+R Alt+F`&#x20;
  {% endhint %}


# Run the updated solution

With the Hello Jigx project published to the Cloud, you are ready to use the solution in the Jigx mobile app.

{% columns %}
{% column %}

## Steps

1. On your mobile device, **tap** the Jigx app icon.
2. Sign into the app with your [Jigx account](/getting-started/creating-an-account) details.
3. The app opens the [home hub](/building-apps-with-jigx/ui/home-hub) screen displaying the Hello Jigx solution, with the **map widget,** and next to it the **calendar widget.**
4. Tap on the **calendar** icon to display the week's event and meeting details.
   {% endcolumn %}

{% column %}

<figure><img src="/files/NQAZZD7pKeV18UL54YZn" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

**Congratulations** you added a second widget to the Hello Jigx solution. Why not try building the next step in the [Build your first Jigx solution](/getting-started/create-an-app-from-scratch/create-the-hello-jigx-solution-project).


# Create Data - Form & List

## Overview

Learn how to build [forms](/building-apps-with-jigx/ui/jigs-_screens_/forms) that create a new customer record that gets stored in the built-in Jigx data store called [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data). The data record is created in the data store by using the submit [action](https://docs.jigx.com/examples/readme/actions). Once the record is created you can view, edit and list the data records using queries that return the record details from SQLite. For more information on the supported data providers read the [Data](/building-apps-with-jigx/data) section.

{% hint style="info" %}
There are **two methods** to save data collected on a form to a database.

**The first method is to use the form submit action.** The submit form action automatically matches the `instanceIds` of the controls on the jig and creates a record in the local SQLite table with each `instanceIds` as a property for the JSON object in the Data column.

**The second method is to use an execute entity action.** The execute entity action allows you to specify the data properties for the SQLite table. You have more granular control over the saved values and can include expressions.
{% endhint %}

{% columns %}
{% column %}

<figure><img src="/files/Zec6TfkykTbKkBAdb5mm" alt="Form and list widgets" width="188"><figcaption><p>Form and list widgets</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/hiqDqXJ9JP2cQnrPAQdQ" alt="New customer form" width="188"><figcaption><p>New customer form</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

<figure><img src="/files/9YbJuWzzBFzkqULdKJW9" alt="View customer jig" width="188"><figcaption><p>View customer jig</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/hFtb6F7HkvXdLGgV3e55" alt="Edit customer jig" width="188"><figcaption><p>Edit customer jig</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="success" %}
We recommend you build out all the solution steps for the [Create an app from scratch](/getting-started/create-an-app-from-scratch/create-data-form-_-list), as each solution step builds on the previous step until you have a functioning mobile app.
{% endhint %}

## Steps

1. Open the Hello-Jigx solution in the Jigx Builder in VS Code.
2. [Create a new customer form](/getting-started/create-an-app-from-scratch/create-data-form-_-list/create-a-new-customer-form): Add the `new-customer.jigx` file with type `jig.default`, the form uses a two-column layout. Add the `component.form` to create the three fields on the form. Add the `action.submit-form` to submit the form data to the Jigx SQLite dynamic data store.
3. [Create a customer list with data](/getting-started/create-an-app-from-scratch/create-data-form-_-list/create-a-customer-list-with-data) Add the `list-customer.jigx` file with type `jig.list`. Specify the dynamic data provider and the `query` that returns the customer's details in the list.
4. [Create a view of the customer record](/getting-started/create-an-app-from-scratch/create-data-form-_-list/create-a-view-of-the-customer-record): Add the `view-customer.jigx` file with type `jig.default`, specify the `datasource.sqlite`, and the `query` to return a view of the customer and their details.
5. [Edit a customer record](/getting-started/create-an-app-from-scratch/create-data-form-_-list/edit-a-customer-record): Add the `edit-customer.jigx` file with type `jig.default`, specify the `datasource.sqlite`, the `query` to return the specified customer and their details. Add `component.form` to display the returned data. Then add the `action.submit-form` with the `method: update` to save the changes to the customer's details.
6. [Add the form & list to the Home Hub](/getting-started/create-an-app-from-scratch/create-data-form-_-list/add-the-form-_-list-to-the-home-hub) by adding their `jigIds` to the `tabs` in the `index.jigx` file.
7. [Publish your project](/getting-started/create-an-app-from-scratch/create-the-calendar/publish-your-project).
8. [Run the updated solution](/getting-started/create-an-app-from-scratch/create-the-calendar/run-the-updated-solution) in the Jigx mobile app, click on the customer icon, this opens a new customer form. Add details for a customer. Tap back to return to the Home Hub , the customer will appear in the customer list widget. You can view the customer by tapping on the customer name in the list.

## GitHub Samples

You can download the [Hello Jigx solution](https://github.com/jigx-com/jigx-samples/tree/main/quickstart/hello-jigx-solution) project on GitHub or build it yourself by following the detailed steps in this section.


# Create a new customer form

In this section, you learn how to create a form with a two-column layout and three fields, and how to configure an action button on the form that will create the record in the [Dynamic data provider](/building-apps-with-jigx/data/data-providers/dynamic-data).

## Steps

### Create the form jig to capture data

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, **right-click** on the jigs node in Explorer, and select **New file**.
2. Name the file **new-customer.** The file opens and shows the Jigx's auto-complete popup listing the five jig types. Click on **Default** to open the skeleton YAML created by the Jigx Builder.
3. Give the jig a `title` called *Customers* and provide a description like *New customer form*.
4. Add `icon: person` under the description line. This icon displays on the widget on the Home Hub .
5. You can delete this jig's header, onFocus, and datasource lines.
6. The controls displayed on the jig are defined under the `children` node on a default jig. All the input controls are placed on a `form component`. A control is uniquely identified by its `instanceId`. They are added as children of a `field-row component` to display two controls next to each other. A `text-field component` is used to capture text information on a form, and the `email field component` is used to capture email addresses. Under the `children:` node, add these fields as shown below to capture the customer's first and last name and email address:

{% code title="YAML" %}

```yaml
children:
  - type: component.form
    instanceId: customerInfo
    options:
      children:
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
        - type: component.email-field
          instanceId: email
          options:
            label: Email
```

{% endcode %}

### Add the submit form action (button)

1. The top-level action on a \*default \*jig places a button at the bottom of the screen. A *submit-form action* saves the data from the text boxes to the SQLite database. The `submit form action` automatically matches the `instanceIds` of the controls on the jig and creates a record in the local SQLite table with each `instanceIds` as a property for the JSON object in the Data column. At the same root YAML level as `children:` use **ctrl+space** to add the `actions` node. Use the code below to create the `action.submit-form` type, define the data provider to be the Dymamic data provider, and use the `method: create` to save the record.

{% code title="YAML" %}

```yaml
actions:
  - children:
      - type: action.submit-form
        options:
          formId: customerInfo
          provider: DATA_PROVIDER_DYNAMIC
          title: Save Customer
          entity: default/customers
          method: create
```

{% endcode %}

2\. After the record is created you want to navigate back to the Home Hub, add the `onSuccess: type: action.go-back` action to the bottom of the actions node. 3. With Dynamic Data you need to add the reference to the table in the database. In the databases node click on the *default.jigx* file. Type `customers: null` under `tables:` as shown below.&#x20;

{% code title="default.jigx" %}

```yaml
# tables:
tables:
  customers: null
```

{% endcode %}

4\. Your new-customer.jigx file should resemble the code below.

{% code title="new-customer.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: New Customer
# Description of the jig. This is not a required field and can be omitted
description: Add a new customer record
# The jig type used to display data
type: jig.default
# icon that displays on the widget on the home hub
icon: person

# The controls that will be displayed on the jig are defined under the children node on a default jig   
children:
  # All input controls are placed on a form component
  - type: component.form
    # A control is uniquely identified by its instance id
    instanceId: customerInfo
    options:
      children:
       # To display two controls next to each other, they are added as children of a field-row component
        - type: component.field-row
          options:
            children:
              # A text-field component is used to capture text information on a form
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
        - type: component.email-field
          instanceId: email
          options:
            label: Email

# The top level action on a default jig places a button at the bottom of the screen
actions:
  - children:
     # A submit-form action is used to save the data from the text boxes to the SQLite database. The submit form action will automatically match the instanceIds of the controls on the jig and create a record in the local SQLite table with each instanceIds as a property for the JSON object in the Data column
      - type: action.submit-form
        options:
          # The name of the form being submitted
          formId: customerInfo
          # The data provider being used. In this case, the Jigx Dynamic Data provider, which is a built-in database using methods to work with the data. 
          provider: DATA_PROVIDER_DYNAMIC
          # The title of the button
          title: Save Customer
          # The name of the table that the information is being save to. All Dynamic Data-based tables are saved in the "default" database 
          entity: default/customers
          # The Jigx Dynamic Data provider method to create the data
          method: create
          # The navigation action that is performed after the form-submit action completes
          onSuccess: 
            type: action.go-back
```

{% endcode %}


# Create a customer list with data

In this section, you learn how to create a [jig.list](https://docs.jigx.com/examples/jiglist) type that uses the [dynamic data provider](/building-apps-with-jigx/data/data-providers/dynamic-data) to return and display a list of records. You specify the fields that must be returned in the list jig and add an [onPress list action](https://docs.jigx.com/examples/list-item) that opens a jig used to view the selected list item record.

## Steps

### Create a list jig

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, **right-click** on the jigs node in Explorer, and select **New file**.
2. Name the file **list-customer**. The file opens and shows the Jigx's auto-complete popup listing the five types of jigs you can select. Click on **List** to open the skeleton YAML created by the Jigx Builder.
3. Give the jig a title called **List customers** and provide a description like *List my customers*.
4. Change the icon to `icon: list`.This icon displays on the widget on the Home Hub.
5. Delete the `header` and `onfocus` nodes.

### Add the data source to return data in the list

1. Under the `datasource` node specific the data provider where the customer records are stored. The name of the table that the information is being returned from. All Jigx Dynamic Data-based tables are saved in the "default" database. Use a SQLite `query` to specify the fields to be returned in the list, in this case, we want the customer's first and last name as well as their email address. You can add your own datasource entries or use the code example below.&#x20;

{% code title="YAML" %}

```yaml
datasources:
  customerList:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_DYNAMIC
      entities:
        - entity: default/customers
      query: SELECT id, '$.firstName', '$.lastName', '$.email' FROM [default/customers]
```

{% endcode %}

### Add controls and actions to the list item

1. All list output controls are placed on the `list-item component`. Use the `swipeable:` action to configure a left or right swipe and the method to call. For example, in this step, we use a left swipe to delete the customer using the delete method. You can add your own controls or use the code example below.

{% code title="YAML" %}

```yaml
data: =@ctx.datasources.customerList
item:
  type: component.list-item
  options:
    title: =@ctx.current.item.firstName & " " & @ctx.current.item.lastName
    subtitle: =@ctx.current.item.email
    swipeable:
      left:
        - label: Delete
          icon: delete
          color: warning
          onPress:
            type: action.execute-entity
            options:
              provider: DATA_PROVIDER_DYNAMIC
              entity: default/customers
              method: delete
```

{% endcode %}

2\. Configure the action to take you back to the list once the list-item has been deleted, by using the code below.

{% code title="YAML" %}

```yaml
data:
  id: =@ctx.current.item.id
onSuccess:
  type: action.go-back
```

{% endcode %}

### Add a navigation action

1. Add a navigation action that is performed when a single item is clicked in the list, and referenced by using the `custId` parameter. In this step clicking on a customer in the list opens the view-customer jig to view the customer's details. Use the `onPress` action with an `action.go-to` type and the `linkTo` option as shown below.

{% code title="YAML" %}

```yaml
onPress:
  type: action.go-to
  options:
    linkTo: view-customer
    parameters:
      custId: =@ctx.current.item.id
```

{% endcode %}

2\. Your list-customer.jigx file should resemble the code below.

{% code title="list-customer.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: List customers
# Description of the jig. This is not a required field and can be omitted.
description: List of our customers
# The jig type used to list data values and elements
type: jig.list
# icon that displays on the widget on the home hub
icon: list

# The type of datasource used to store the created data in the jig
datasources:
  customerList:
    type: datasource.sqlite
    options:
      # The data provider being used. In this case, the Jigx Dynamic Data provider
      provider: DATA_PROVIDER_DYNAMIC
      # The name of the table that the information is being returned from. All Dynamic Data-based tables are saved in the "default" database.
      entities:
        - entity: default/customers
      # The SQLite query used to specifiy the data to return
      query: SELECT id, '$.firstName', '$.lastName', '$.email' FROM [default/customers]

data: =@ctx.datasources.customerList
item:
  # All list output controls are placed on the list-item component
  type: component.list-item
  options:
    title: =@ctx.current.item.firstName & " " & @ctx.current.item.lastName
    subtitle: =@ctx.current.item.email
    # The list-item action that defines what to do when swiping left or right on the item
    swipeable:
      left:
        - label: Delete
          icon: delete
          color: warning
          onPress:
            type: action.execute-entity
            options:
              provider: DATA_PROVIDER_DYNAMIC
              entity: default/customers
              method: delete
              data:
                id: =@ctx.current.item.id
              onSuccess:
                type: action.go-back
    # The navigation action that is performed when an individual item is tapped in the list, in this instance to view the customer details
    onPress:
      type: action.go-to
      options:
        linkTo: view-customer
        parameters:
          custId: =@ctx.current.item.id
```

{% endcode %}

{% hint style="warning" %}
The list-customer.jigx file will display in red and cannot be saved yet as it references the view-customer.jigx file that you will be creating in the [Create a view of the customer record](/getting-started/create-an-app-from-scratch/create-data-form-_-list/create-a-view-of-the-customer-record) step.
{% endhint %}


# Create a view of the customer record

In this section, you learn how to create a view using the [entity-field](https://docs.jigx.com/examples/entity-field) component to display the data returned from the [Dynamic data provider](/building-apps-with-jigx/data/data-providers/dynamic-data). Add an action to go to a form that allows you to edit and [update a record](/building-apps-with-jigx/ui/jigs-_screens_/forms/updating-a-record).

## Steps

### Create a jig to view data

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, **right-click** on the jigs node in Explorer, and select **New file**.
2. Name the file **view-customer**. The file opens and shows the Jigx's auto-complete popup listing the five types of jigs you can select. Click on **Default** to open the skeleton YAML created by the Jigx Builder.
3. Give your jig a `title` and `description`.
4. Delete the `header` and `onfocus` nodes.
5. Specify the SQLite Dynamic data provider, the table, and the SQLite query needed to return the customer's details. Below is an example of the code you can use.

{% code title="YAML" %}

```yaml
datasources:
  customerInfo:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_DYNAMIC
      entities:
        - default/customers
      query: SELECT id, '$.firstName', '$.lastName', '$.email' FROM [default/customers] WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.custId
      isDocument: true
```

{% endcode %}

### Create the view form

1. Now that you have the data you want to view, specify how you want to view the data. For this step, we want to view the data in a form similar to the new customer form. The code below shows using the `form component`, `field-row`, and `entity- fields` to display the customer's first and last name, and email address.

{% code title="YAML" %}

```yaml
children:
  - type: component.entity
    options:
      children:
        - type: component.field-row
          options:
            children:
              - type: component.entity-field
                options:
                  label: First Name
                  value: =@ctx.datasources.customerInfo.firstName
              - type: component.entity-field
                options:
                  label: Last Name
                  value: =@ctx.datasources.customerInfo.lastName
        - type: component.entity-field
          options:
            label: Email
            value: =@ctx.datasources.customerInfo.email
```

{% endcode %}

### Add an edit action (button)

1. Once you can view the returned customer record, you want to be able to edit the record and save the changes to the SQLite Dynamic Data provider. Add the `action.go-to` that directs you to the edit form using the `custId` to reference the individual customer record. Use the code below to create the action button.

{% code title="YAML" %}

```yaml
actions:
  - children:
      - type: action.go-to
        options:
          title: Edit Customer
          linkTo: edit-customer
          parameters:
            custId: =@ctx.jig.inputs.custId
```

{% endcode %}

2\. Your view-customer.jigx file should resemble the code below.

{% code title="view-customer.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: View Customer
# The jig type used to display data
type: jig.default

# The type of datasource used to return data in the jig
datasources:
  customerInfo:
    type: datasource.sqlite
    options:
      # The data provider being used. In this case, the Jigx Dynamic Data provider, which is a built-in database that can be queried to get data from
      provider: DATA_PROVIDER_DYNAMIC
      # The name of the table that the information is being returned from. All Dynamic Data-based tables are saved in the "default" database
      entities:
        - default/customers
      # The SQLite query used to specifiy the data to return
      query: SELECT id, '$.firstName', '$.lastName', '$.email' FROM [default/customers] WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.custId
      isDocument: true
# The controls that will be displayed on the jig are defined under the children node on a default jig
children:
  # All input controls are placed on a form component
  - type: component.entity
    options:
      children:
        # To display two controls next to each other, they are added as children of a field-row component
        - type: component.field-row
          options:
            children:
              # A text-field component is used to display text information on a form
              - type: component.entity-field
                options:
                  label: First Name
                  value: =@ctx.datasources.customerInfo.firstName
              - type: component.entity-field
                options:
                  label: Last Name
                  value: =@ctx.datasources.customerInfo.lastName
        - type: component.entity-field
          options:
            label: Email
            value: =@ctx.datasources.customerInfo.email

# The top level action on a default jig places a button at the bottom of the screen
actions:
  - children:
      # The navigation action that is performed when the go-to action completes
      - type: action.go-to
        options:
          title: Edit Customer
          linkTo: edit-customer
          parameters:
            custId: =@ctx.jig.inputs.custId
```

{% endcode %}

{% hint style="warning" %}
The view-customer file will display in red and cannot be saved yet as it references the edit-customer file that you will be creating in the [Edit a customer record](/getting-started/create-an-app-from-scratch/create-data-form-_-list/edit-a-customer-record) step.
{% endhint %}


# Edit a customer record

In this section, you learn how to create a form using the `component.form` to display the fields returned from the dynamic data provider. Add an `action.submit-form` with a `method: update` that saves the changes to the record in the dynamic data provider.

## Steps

### Create a jig to edit data

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, **right-click** on the jigs node in Explorer, and select **New file**.
2. Name the file **edit-customer**. Click on **Default** to open the skeleton YAML created by the Jigx Builder.
3. Give the jig a title called *Edit customers* and provide a description like *Edit customer details*.
4. Delete the `header` and `onfocus` nodes.

### Add a datasource and form

1. You are going to use the same datasource, query, form, and form fields that you used in the view-customer.jigx file. Use the code below.

{% code title="YAML" %}

```yaml
datasources:
  customerInfo:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_DYNAMIC
      entities:
        - default/customers
      query: SELECT id, '$.firstName', '$.lastName', '$.email'  FROM [default/customers] WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.custId
      isDocument: true 
children:
  - type: component.form
    instanceId: editCustomer
    options:
      children:
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
                  initialValue: =@ctx.datasources.customerInfo.firstName
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
                  initialValue: =@ctx.datasources.customerInfo.lastName
              - type: component.text-field    
                instanceId: email
                options:
                  label: Email
                  initialValue: =@ctx.datasources.customerInfo.email    
```

{% endcode %}

### Add the submit-form action to save the data

1. A `submit-form` action is used to save the data from the text boxes to the SQLite database. The `submit form` action will automatically match the `instanceIds` of the controls on the jig and use the `update method` to save the changes to the record in the local SQLite table with each `instanceIds` as a property for the JSON object in the Data column. Use the submit.form action code below:

{% code title="YAML" %}

```yaml
actions:
  - children:
      - type: action.submit-form
        options:
          formId: editCustomer
          provider: DATA_PROVIDER_DYNAMIC
          title: Save Customers
          entity: default/customers             
          method: update
          recordId: =@ctx.jig.inputs.custId
          onSuccess: 
            type: action.go-back  
```

{% endcode %}

2\. Your edit-customer.jigx file should resemble the code below.

{% code title="edit-customer.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Edit Customer
# The jig type used to display data
type: jig.default

# The type of datasource used to store the edited data in the jig
datasources:
  customerInfo:
    type: datasource.sqlite
    options:
     # The data provider being used. In this case, the Jigx Dynamic Data provider, which is a built-in database using methods to work with the data. 
      provider: DATA_PROVIDER_DYNAMIC
      # The name of the table that the information is being returned from. All Dynamic Data-based tables are saved in the "default" database.
      entities:
        - default/customers
      # The SQLite query used to specifiy the data to return  
      query: SELECT id, '$.firstName', '$.lastName', '$.email'  FROM [default/customers] WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.custId
      isDocument: true
# The controls that will be displayed on the jig are defined under the children node on a default jig      
children:
  # All input controls are placed on a form component
  - type: component.form
    # A control is uniquely identified by its instance id
    instanceId: editCustomer
    options:
      children:
        # To display two controls next to each other, they are added as children of a field-row component
        - type: component.field-row
          options:
            children:
              # A text-field component is used to capture or update text information on a form. In this case the value is returned from the database
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
                  initialValue: =@ctx.datasources.customerInfo.firstName
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
                  initialValue: =@ctx.datasources.customerInfo.lastName
              - type: component.text-field    
                instanceId: email
                options:
                  label: Email
                  initialValue: =@ctx.datasources.customerInfo.email    

# The top level action on a default jig places a button at the bottom of the screen                  
actions:
  - children:
     # A submit-form action is used to save the data from the text boxes to the SQLite database. The submit form action will automatically match the instanceIds of the controls on the jig and update the record in the local SQLite table with each instanceIds as a property for the JSON object in the Data column
      - type: action.submit-form
        options:
          # The name of the form being submitted
          formId: editCustomer
          provider: DATA_PROVIDER_DYNAMIC
          title: Save Customers
          entity: default/customers
          # The Jigx Dynamic Data provider method to update the data                  
          method: update
          recordId: =@ctx.jig.inputs.custId
          onSuccess: 
            type: action.go-back  
```

{% endcode %}


# Add the form & list to the Home Hub

## Overview

In this step, you will add the new customer form and the customer list widgets to the Home Hub of the Jigx mobile app.

## Steps

#### Add jigIds to index.jigx file

1. Click on the `index.jigx` file to add the new customer form and list jigs to appear on the Home Hub screen under the `home` and `calendar` tabs. The `jigId` is used to reference the form and list jig that will be displayed, and **save** the project.
2. Your index.jigx file should resemble the code below. :&#x20;

{% code title="index.jigx" %}

```yaml
# The system name that uniquely identifies the solution
name: hello-jigx-solution
# The friendly name of the solution
title: Hello-Jigx Solution
# The built-in category selected for this solution
category: business
#The widgets that act as top-level navigation elements for jigs
tabs:
  home:
    jigId: map
    icon: location
  calendar:
    jigId: calendar
    icon: calendar
  customer:
    jigId: new-customer
    icon: person
  list:
    jigId: list-customer 
    icon: list 
```

{% endcode %}


# Publish your project

With the customer form and list added to the Hello Jigx project, you are ready to publish the update to the Jigx Cloud. If you are the owner of the solution you do not need your Jigx app credentials again to publish the update.

{% columns %}
{% column %}

## Steps

1. In VS Code click on the Jigx Builder **icon** in the left navigation bar.
2. In the Jigx Explorer hover over the Hello Jigx node till you see the **publish icon** (rocket). Click on the icon to start the publishing process.
3. Click **Publish** on the confirmation message screen.
4. The publishing process starts and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/rgXgdqEKpcv9ANcC8R6a" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
You can use the shortcut keys straight from the file you in:

* Publish all files in Jigx solution on Mac is `⌘R⌘R`, and on Windows is `Alt+R Alt+R`
* Publishing an individual file on Mac is `⌘R⌘F`, and on Windows is `Alt+R Alt+F`&#x20;
  {% endhint %}


# Run the updated solution

With the customer forms and list added to the Hello-Jigx solution and published to the Cloud, you are ready to use the solution in the Jigx mobile app.

## Steps

1. On your mobile device **tap** the Jigx app icon on your mobile device.
2. Sign into the app with your [Jigx account](/getting-started/creating-an-account) details.
3. The app opens the [home hub](/building-apps-with-jigx/ui/home-hub) screen displaying the Hello Jigx solution, there are now four widgets showing, the map, calendar, **customer**, and **customer list** widgets.
4. Tap on the **customer** icon to open the new customer form. Add details of a new customer and submit the form. Navigate back to the Home Hub, you will notice that the customer you created shows in the **customer list** widget. View the customer details by tapping the customer name in the list. Tap the Edit Customer button at the bottom of the view. Make changes to the customer's email and name tap the save customer button at the bottom of the screen. Navigate back to the Home Hub to see the updated details in the list.


# Combine the solution's elements

In the Build your first Jigx solution steps, you have already built a map using the [jig.default](https://docs.jigx.com/examples/jigdefault), added a calendar using the [jig.calendar](https://docs.jigx.com/examples/jigcalendar), added a new customer form using the [jig.default](https://docs.jigx.com/examples/jigdefault), and a customer list using [jig.list](https://docs.jigx.com/examples/jiglist).

Now you can expand the solution further by using the [jig.composite](https://docs.jigx.com/examples/jigcomposite) type to group the new customer jig and the customer list jig into one jig, and add a jig header to the new customer jig.

{% hint style="success" %}
We recommend you build out all the solution steps for the [Create an app from scratch](/getting-started/create-an-app-from-scratch/combine-the-solution_s-elements), as each solution step builds on the previous step until you have a functioning mobile app.
{% endhint %}

{% columns %}
{% column %}

## Steps

1. Open the Hello-Jigx - Solution in Jigx Builder in VS Code.
2. [Add the customer composite jig](/getting-started/create-an-app-from-scratch/combine-the-solution_s-elements/add-the-customer-composite-jig) file that joins the new customer form and list into one jig using the new-customer and list-customer `jigIds` and add a `header` for the jig.
3. [Edit the index.jigx file](/getting-started/create-an-app-from-scratch/combine-the-solution_s-elements/edit-the-index_jigx-file), add the customer composite jigId, remove the new customer and the list customer jigIds.
4. [Publish your project](/getting-started/create-an-app-from-scratch/create-the-calendar/publish-your-project).
5. [Run the updated solution](/getting-started/create-an-app-from-scratch/create-the-calendar/run-the-updated-solution) in the Jigx mobile app, click on each jig to view the solution, note on the customer jig the form, and list display in the same jig.
   {% endcolumn %}

{% column %}

<figure><img src="/files/8Pku7R8hg8vX4BsHzwtO" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

## GitHub Samples

You can download the [Hello Jigx solution](https://github.com/jigx-com/jigx-samples/tree/main/quickstart/hello-jigx-solution) project on GitHub or build it yourself by following the detailed steps in this section.


# Add the customer composite jig

In this section, you learn how to join jigs to create a single jig using the `jig.composite` type, this is useful in our solution as you want to capture a new customer and see the customer added to the list directly below the form, you also add an image header to the composite jig.

## Steps

### Create the composite jig

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, right-click on the jigs node in Explorer, and select New file.
2. Name the file **composite**. The file opens and shows the Jigx's auto-complete popup listing the five types of jigs you can select. Click on Composite to open the skeleton YAML created by the Jigx Builder.
3. Give the jig a title called Customers and provide a description like *Customer form and list*. Add `icon: person` under the description line. This icon displays on the widget on the Home Hub.
4. For this jig you can delete the `onFocus` node.
5. Under the `header` node you can leave it as is or add your own image uri. The `jig-header` component can be used in any type of jig. It serves as a container for specifying headers, such as images. Change the `height` value to small and add a `title: Customers` after options. Here is an example of the header code with an image.

{% code title="YAML" %}

```yaml
header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        title: Customers
        source:
          uri: https://cdn2.webdamdb.com/v1_1280_6enPaxIBt9M3.jpg?1554490336
```

{% endcode %}

### Add the jigIds

1. Next to the `jigIds` add `new-customer` and `list- customer`. The order of the children's `jigIds` determines the display order in the app.
2. You can remove the `inputs:` `recordid: =@ctx.jig.inputs.parameter`
3. Your composite.jigx file should resemble the code below.&#x20;

{% code title="composite.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Customers
description: New customer form and list
# The jig type used to join multiple jigs together
type: jig.composite
# icon that displays on the widget on the home hub
icon: person

# A container for specifying jig headers such as images, videos or location
header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        title: Customers
        source:
          uri: https://cdn2.webdamdb.com/v1_1280_6enPaxIBt9M3.jpg?1554490336
      
# Specifiy the jigs to combine by listing the jigIds for each jig.  
children:
  - jigId: new-customer
  - jigId: list-customer
```

{% endcode %}


# Edit the index file

The index.jigx file includes links to the jigs you want accessible as top-level navigation elements. In the previous steps you created a composite jig, and a static datasource, now you will add these to the `index.jigx` file to appear on the Home Hub, and remove the new customer and the list customer widgets which are now joined in the composite jig. In this step, the `jigId` is used to reference the composite jig. The order of the `jigId` determines the order in which the tabs appear on the Home Hub. You add the composite jig first in this solution as you want it to be the first bottom tab to display.

## Steps

### Add jigs to the index.jigx file

1. Click on the `index.jigx` file. Under `tabs:` **remove** the `jigId: new-customer`, and the `jigId: list-customer`. Now **add** the `jigId: composite`.
2. Your index.jigx file should resemble the code below.

{% code title="index.jigx" %}

```yaml
# The system name that uniquely identifies the solution
name: hello-jigx-solution
# The friendly name of the solution
title: Hello-Jigx Solution
# The built-in category selected for this solution
category: business
#The tabss that act as bottom-level navigation elements for jigs
tabs:
  customer: # The first tab of the app.
    jigId: composite
    icon: people
  home: 
    jigId: map
    icon: location
  calendar:
    jigId: calendar
    icon: calendar
```

{% endcode %}


# Publish the Hello Jigx Solution

With the Hello-Jigx solution complete, you are ready to publish the final update to the Jigx server. If you are the owner of the solution, you do not need your Jigx app credentials again to publish the update.

{% columns %}
{% column %}

## Steps

1. In VS Code click on the **Jigx Builder** icon in the left navigation bar.
2. In the Jigx Explorer hover over the Hello-Jigx node till you see the **publishicon (rocket)**. Click on the icon to start the publishing process.
3. Click **Publish** on the confirmation message screen.
4. The publishing process starts and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/rgXgdqEKpcv9ANcC8R6a" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
You can use the shortcut keys straight from the file you in:

* Publish all files in Jigx solution on Mac is `⌘R⌘R`, and on Windows is `Alt+R Alt+R`
* Publishing an individual file on Mac is `⌘R⌘F`, and on Windows is `Alt+R Alt+F`&#x20;
  {% endhint %}


# Run the Hello Jigx Solution

With the final update to the Hello Jigx solution published on the server, you are ready to use the solution in the Jigx mobile app.

{% columns %}
{% column %}

## Steps

1. On your mobile device **tap** the Jigx app icon on your mobile device.
2. Sign into the app with your [Jigx account](/getting-started/creating-an-account) details.
3. Notice the customer composite widget. Tap the widget to see the customer header, form, and list.
   {% endcolumn %}

{% column %}

<figure><img src="/files/8Pku7R8hg8vX4BsHzwtO" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

**Congratulations** you have successfully built your first functioning Jigx solution. Explore the solution by adding new customers or extend the solution by adding to the existing code by [customizing the solution](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution).


# Customize the Hello-Jigx solution

Now you have built a functioning solution that works, but you can do much more with Jigx. In this section, you will customize three of the widgets on the Home Hub. You will learn how easy it is to work with the Jigx components to create, style, and customize the app that works for your organization.

{% hint style="success" %}
We recommend you build out all the solution steps for the [Create an app from scratch](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution), as each solution step builds on the previous step until you have a functioning mobile app.
{% endhint %}

{% columns %}
{% column %}

## Steps

1. Change the icon on a widget and [use an expression](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution/change-an-icon-and-add-a-badge) to add a **badge** to the calendar jig to show the number of calendar events for the week.
2. [Add widgets](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution/add-widgets) to replace the map icon with a location widget in the map.jigx file, and the people icon with an image widget in the composite.jigx file.&#x20;
   {% endcolumn %}

{% column %}

<figure><img src="/files/Worb3JOl0SY1uePZg53K" alt="Hello Jigx Solution" width="188"><figcaption><p>Hello Jigx Solution</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

**Congratulations** you have successfully completed the Hello Jigx solution series by building your first functioning Jigx solution, and then customizing the style and added additional functionality.

Now fast-track your development by adding sample solutions from our [Quick Start](https://manage.jigx.com/quickstart) library to your organization. For more information on the various samples, see [Overview](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution), and to understand the options available when setting up the projects, publishing, and using the sample solution,/ see [Setting up your solution](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution).

We recommend starting with the [Jigx-samples](https://github.com/jigx-com/jigx-samples/tree/main/quickstart/jigx-samples) solution that showcases [jig.calendar](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution), [actions (buttons)](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution), [action-list](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution) and [jig-header](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution).

### See Also

* [Planning your app](/getting-started/planning-your-app)


# Change an icon and add a badge

## Overview

You can easily customize widgets on the Home Hub by changing their icons and adding additional components such as badges to the widgets. In this section, you learn to change the calendar icon and add a badge [using an expression](/building-apps-with-jigx/logic/expressions) on the calendar jig to show the number of calendar events for the week.

{% hint style="info" %}
For a view of the icons in a list see the *Types - List - List with all icons* in the *jigx-samples solution* available in [https://manage.jigx.com/quickstartQuick ](https://manage.jigx.com/quickstart)start.
{% endhint %}

{% columns %}
{% column %}

<figure><img src="/files/UzVc2zBiQRwQzd6R9L3L" alt="Solution with Calendar -3 icon" width="188"><figcaption><p>Solution with Calendar -3 icon</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/9d8wrDmIIoqMMwApqpIp" alt="Solution with calendar badge" width="188"><figcaption><p>Solution with calendar badge</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Steps

#### Change an widget icon

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, click on the calendar.jigx file.
2. Replace `icon: calendar-3` with `icon: calendar`.

#### Add a badge to the calendar widget

1. Under icon add a new line for the badge code that shows the number of calendar events for the week. Add `badge:` Then use the `=$count(@ctx.datasources.calendar-data.id)` [expression](/building-apps-with-jigx/logic/expressions) to count the events in the calendar and show the number in the badge on the Home Hub.

{% hint style="info" %}
Expressions are JSONata language-based. Learn more about [JSONata](https://jsonata.org/) and try out your expressions in their [JSONata Exerciser](https://try.jsonata.org/). The root element of Expressions in .jigx files always starts with "@ctx" vs. "$$." in JSONata Exerciser (e.g. @ctx.data vs.$$.data). Jigx supports shorthand $ expressions for JSONata.
{% endhint %}

{% code title="calendar.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Calendar
# The jig type used to display a calendar with the current date
type: jig.calendar
# icon that displays on the widget on the home hub
icon: calendar
# Add a badge to the calendar widget and use an expression to count the entries in the calendar by id
badge: =$count(@ctx.datasources.calendar-data.id)
# The expression that structures the data from the datasource before binding it to the jig. Expressions are JSONata based
data: =@ctx.datasources.calendar-data
item:
  options:
    title: =@ctx.current.item.title
    from:
      format:
        dateFormat: lll
      text: =$fromMillis($toMillis($now()) + @ctx.current.item.eventStart * 3600000)
    location: =@ctx.current.item.location
    people: =@ctx.current.item.people
    tags: =@ctx.current.item.tags
    to:
      format:
        dateFormat: lll
      text: =$fromMillis($toMillis($now()) + @ctx.current.item.eventEnd * 3600000)
  type: component.event
```

{% endcode %}

4\. **Save** and **publish** the Hello-Jigx solution. 5. **Run** the Hello-Jigx solution on your mobile device to see the change to the calendar icon and see the badge displaying 3 events for the week on the Home Hub.


# Add widgets

## Overview

Widgets can be customized in many ways to reflect the styling and functionality you require. Use the widget [image](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution/add-widgets), [location](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution/add-widgets), [chart](/getting-started/create-an-app-from-scratch/customize-the-hello-jigx-solution/add-widgets), and other elements for customizations. In this section, you will learn how to change your map jig with an icon to a `widget.location`, and add a `widget.image` widget to the `composite.jigx` file.

{% columns %}
{% column %}

<figure><img src="/files/UzVc2zBiQRwQzd6R9L3L" alt="Hello Jigx solution with location icon" width="188"><figcaption><p>Hello Jigx solution with location icon</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/9d8wrDmIIoqMMwApqpIp" alt="Widget location &#x26; image" width="188"><figcaption><p>Widget location &#x26; image</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Steps

#### Add a widget to a jig

1. Open the Hello-Jigx solution in Jigx Builder in VS Code, and click on the map.jigx file.
2. Delete the `icon: location` entry.
3. Add the `widget.location` code below. For the address you use [expressions](/building-apps-with-jigx/logic/expressions) to call the city New York from the static datasource.

{% hint style="info" %}
Expressions are JSONata language-based. Learn more about [JSONata](https://jsonata.org/) and try out your expressions in their [JSONata Exerciser](https://try.jsonata.org/). The root element of Expressions in .jigx files always starts with "@ctx" vs. "$$." in JSONata Exerciser (e.g. @ctx.data vs.$$.data). Jigx supports shorthand $ expressions for JSONata.
{% endhint %}

{% code title="map.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Location with address
# The jig type used to display data
type: jig.default

isCollapsible: true
# The type of datasource used to return data in the jig
datasources:
  address: 
    # The static dataset is created directly inside the jig file
    type: datasource.static
    options:
      data:
        - street: 768 5th Ave
          city: New York
          country: US
# The control used by the jig          
children:
  - type: component.location
    options:
      viewPoint:
        address: =@ctx.datasources.address.street & ',' & @ctx.datasources.address.city & ',' & @ctx.datasources.address.country
        zoomLevel: 9
# The widget that displays on the home hub.    
widgets: 
  map-location: 
    type: widget.location
    options: 
      viewPoint: 
       address: =@ctx.datasources.address.city        
```

{% endcode %}

4\. Open the `composite.jigx` file and copy the code below. Note the new widgets section using `widget.image` showing a source uri for the image you want displayed.

{% code title="composite.jigx" %}

```yaml
# The system name that uniquely identifies the jig
title: Customers
description: Shows list and new customers together
# The jig type used to join multiple jigs together
type: jig.composite

widgets:
  image:
    type: widget.image
    options:
      source: 
        uri: https://cdn2.webdamdb.com/v1_1280_6enPaxIBt9M3.jpg?1554490336
        
# A container for specifying jig headers such as images, videos or location
header:
  type: component.jig-header
  options:
    children:
      type: component.image
      options:
        title: Customers
        source:
          uri: https://cdn2.webdamdb.com/v1_1280_6enPaxIBt9M3.jpg?1554490336
    height: small    
  
# Specifiy the jigs to combine by listing the jigIds for each jig
children:
  - jigId: new-customer
  - jigId: list-customer
```

{% endcode %}

5\. **Save** and **publish** the Hello-Jigx solution. 6. **Run** the Hello-Jigx solution on your mobile device to see the change to the map widget on the Home Hub.


# Add a component using a template

We have used the default jig template to add a profile jig to the project in the previous step. Let's go ahead and add a component template. Component templates allow you to quickly build up your solution by inserting the required component into the jig file.

In our solution, we have a new customer form, when we signup the new customer we want them to sign the form. Let's use the signature component template to do this.

<figure><img src="/files/zEnLhiVuCdUHkmFsm0KX" alt="Signature component template" width="188"><figcaption><p>Signature component template</p></figcaption></figure>

1. In Explorer in the **jigs** folder, right-click on the **new-customer.jigx** file.
2. Components are normally added under a `children` node in the YAML. Under the last `component.email-field` section just above the `actions` node place your cursor in the correct node position in the YAML editor and press the **ctrl+space** keys. The Jigx component IntelliSense popup displays listing the available components.

<figure><img src="/files/izzRedOuwa02fxiDNUlV" alt="Component template"><figcaption><p>Component template</p></figcaption></figure>

3\. Scroll to the bottom and select **Use template**. The template gallery opens providing the templates for various components. Use the *Search* and *category* fields to find the signature template or browse the gallery by scrolling through the options.

<figure><img src="/files/q4K7RsaX69iVcheWsUDv" alt="Template gallery"><figcaption><p>Template gallery</p></figcaption></figure>

4\. Hover over the**Form signature field** template and click the blue **insert** button.

<figure><img src="/files/gUSwztm4e5uWlB1kvnkB" alt="Insert template"><figcaption><p>Insert template</p></figcaption></figure>

5\. The template YAML will be inserted into your jig file.

<figure><img src="/files/SlnGHyxZbWl9GpKIpJ9k" alt="Inserted YAML"><figcaption><p>Inserted YAML</p></figcaption></figure>

6\. Publish your project and tap on the new customer widget on the Home Hub in the app. See the signature component on the form.


# Use pre-built solutions

Utilizing pre-built solutions in Jigx provides benefits in terms of time efficiency in development and selecting appropriate app functionalities. Opting for a pre-built solution seamlessly incorporates the solution into your Jigx App, making it readily available for utilization.

## Steps

<figure><img src="/files/1Pjy75LM01PoGrZV5g2i" alt="Pre-built Solutions"><figcaption><p>Pre-built Solutions</p></figcaption></figure>

1. Create a [Creating an account](/getting-started/creating-an-account)
2. Install Jigx App on a mobile device from the [App Store](https://apps.apple.com/app/jigx/id1495596537) or [Google Play Store](https://play.google.com/store/apps/details?id=com.jigx.android)&#x20;
3. Log onto <https://manage.jigx.com/>
4. Browse to <https://manage.jigx.com/quickstart>
5. Choose the sample app you want and click **Add to My Organization.**
6. Add a unique title and system name for the app solution.
7. Click **Add.**
8. Open the Jigx App on your mobile device and start using the added solution.

{% hint style="success" %}
With Jigx you can build and publish more than one solution to your Jigx mobile app, you can toggle between the solutions by tapping on the home icon and selecting the solution you want to use. If you are deep in the solution, long-press the home icon to toggle back to the Solutions screen. The number badge on the home icon shows how many solutions are available to you.
{% endhint %}

## Want to see how the solution is built or edit the solution?

### Download the solution files

<figure><img src="/files/F0oi9ef40FJ1GQZ56iQj" alt="Download solution files"><figcaption><p>Download solution files</p></figcaption></figure>

1. Navigate to **Solutions.**
2. Click on the prebuilt solution.
3. Press the **Download Solution** button at the top of the Solutions Details screen. The solution downloads as a zip to your download folder .

### Open the solution in Jigx Builder

<figure><img src="/files/ZagFHAPGuSxHcJ8TvbWH" alt="Solution in Jigx builder"><figcaption><p>Solution in Jigx builder</p></figcaption></figure>

1. [Install the Jigx Builder](/getting-started/install-the-jigx-builder) and unzip the download file.
2. Use the **Open** option, browse, and select the folder.
3. The Jigx solution opens, you can view or edit the YAML files. Publish your changes by selecting the Jigx Builder icon in the left navigation bar.
   * In the Jigx Explorer hover over the **solution name** till you see the **publish** **icon (rocket)**. Click on the icon to start the publishing process.
   * Enter your Jigx username and press **Enter**.
   * Enter your Jigx password and press **Enter**. The publishing process starts, and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published. The changes are immediately visible in the Jigx App.

## What next?

Why not build your own app? See how to [plan your app](/getting-started/planning-your-app) and learn how to [create an app from scratch](/getting-started/create-an-app-from-scratch).


# Integrate with external data

Integrating with external data is often a crucial step in building a mobile app, enriching the functionality and user experience. This process involves pulling data from outside sources, such as APIs, web services, or large data sets, and seamlessly incorporating it into the app's ecosystem.

Jigx provides a set of data providers to make integrating with external data easy. The following examples show how to build apps using these providers.

<table><thead><tr><th width="180.91796875">Example</th><th></th></tr></thead><tbody><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/rest">Hello REST</a></td><td>In this section, a REST API is used to create a customers Jigx app, allowing you to add new customers and update and view customer details, location, and images.</td></tr><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/rest/ms-graph">MS Graph</a></td><td>The MS Graph examples use the User, Calendar, Mail, Insights, and To-do tasks to create a powerful Jigx apps with everything you need in one app.</td></tr><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/salesforce">Microsoft OneDrive</a></td><td>Use the Microsoft OneDrive data provider to create, update, list, delete, and download files.</td></tr><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/salesforce">Salesforce</a></td><td>The Jigx Salesforce provider brings data directly into the app from Salesforce, giving you access to real-time data and visual insights no matter where you are.</td></tr><tr><td><a href="https://docs.jigx.com/examples/readme/openai-integration">OpenAI</a></td><td>Jigx supports any AI service that is exposed to a REST service. By leveraging the power of advanced AI models, you can create smarter, more responsive, and engaging apps that meet users' evolving needs.</td></tr></tbody></table>


# Planning your app

You want to build a Jigx App but where do you start, and how do you build an app that fulfills your users' expectations and engages them every time they open it? It all starts with planning, not just planning what it will look like but also planning the building and testing of the app. In this section, we guide you on how to plan your Jigx App from beginning to end. Creating a good plan makes building an app easier and faster; you may skip or combine some of these steps or even order them differently, which is fine; these steps aim to help you know what to think about before building your app.

### Checklist

Here is a checklist of the high-level steps when planning your app:

* [ ] [Identify the solution requirements](/getting-started/planning-your-app/solution-requirements)
* [ ] [Plan the solution design](/getting-started/planning-your-app/solution-design)
* [ ] [Home screen](/getting-started/planning-your-app/home-screen)
* [ ] [Data planning](/getting-started/planning-your-app/data-planning)
* [ ] [Build the App](/getting-started/planning-your-app/building-the-app)
* [ ] [Test plan](/getting-started/planning-your-app/testing-plan)
* [ ] [Post App launch](/getting-started/planning-your-app/post-app-launch)

### Example

As you will learn in this section, a series of plans go into creating an app. We suggest logically linking flowcharts, mind maps, entity relationship diagrams, and wireframes. This helps the creator and stakeholders walk through the entire app concept and know exactly how elements are going to work. Below is an example of a Pizza Store App plan created in Miro.

{% embed url="<https://miro.com/app/embed/uXjVM2JhDPc=/?share_link_id=595977255475>" %}


# Solution Requirements

The first step is to identify or define the requirements of your App.

#### Steps

1. Write down the purpose of the app in a few sentences, start with I want to.....;
2. Now break it down and list the requirements. create a list of must-haves and nice-to-haves; always keep in mind that it is a mobile app solution. \
   ![Purpose statement](/files/TZmO46x8w65icEmSN9Wm)
3. Next create a user flow diagram or mind map mapping out the user journey, whether that is on paper or in an application like *Miro, Powerpoint, Visio*. The user flow diagram helps later in the solution design, to plan out the screens of the app. \
   ![Flow chart](/files/usJcJG1AHfLgdeMQs9WG)

#### Considerations

* What is the purpose, story, or use case of the app?
* What business solution or problem is to be addressed?
* Are there specific requirements?
* Who is the target audience or persona, e.g., employees, customers, sales staff, targeted age groups such as scholars?
* Is the requirement based on an existing process? If so, gather the requirements and steps from that process or site.
* If it is a new process or idea, research similar apps to get an understanding of what works.
* How will your users onboard? Will they download the app, register a profile?

#### Tips

* Use a tool or method that allows for collaboration with others and groups. Create the plan in a single location that is easy to refer to. Planning is a living document, a work in progress. As the plan starts to form, you want to be able to add, edit and collaborate on it.
* Think of yourself as the end user of the app, and what you would expect an app to provide, this helps personalize the experience and creates a user-centric approach.


# Solution Design

Next, you are ready to map out the requirements of the app. Each requirement or must-have will be represented on a screen in the app. This is the first visual representation of all the screens and will help uncover usability issues. This is where you get to decide how many screens there will be, what each will look like, and put them in a logical order for navigational purposes.

### Steps

1. Visualize the screens to match the requirements by creating a screen flow diagram, storyboard, or wireframes. There are many methods you can use, the easiest is to start by drawing out each screen on a piece of paper. Then add the drawings in Miro, Figma, or the application of your choice.
2. In the design, show the navigation between screens and buttons.
3. For guidance on mobile UI, refer to Jigx [Templates](/building-apps-with-jigx/ui/jigs-_screens_/jig-templates) or resources such as: \
   \- [Apple Design - Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines) \
   \- [Google -material design principles](https://m2.material.io/design/introduction)
4. Design how people will get the app and onboard. If a profile is required, create a design for it.
5. In your design, you can already decide which features to add, such as buttons, dropdowns, or text fields. This turns your ideas into pictures, which will be converted into navigable screens during the build stage.
6. Draw out functionality that should be available to certain user groups/personas. Think about if people need to see a different view of the screen, i.e., Manager vs employee.
7. Collaborate with a UX designer and your team. \
   ![](/files/OgNEUTgXb8RMnJ4kQR6y)

### Considerations

* Spend time on your design because this determines the look and feel of your app. Add as much information as you can.
* Drive interaction in the app as much as possible with intuitive design, cues and simplicity.
* Personalize screens for users in the screen design.
* Include designs for main screens, and decide if there will be multiple main screens.
* Layout the navigation of the screens, how or what will lead the user to interact with the various elements of the app.
* With every screen think of the usability, this can be how much to include, or how it will display on the screen.
* Enhance the user's experience through well-planned UX and UI design.
* Consider scalability and future-proofing to accommodate growth and expansion.
* Feature overload, including too many features, can lead to a cluttered and confusing user experience.

### Tips

* Only put things on a screen that add value.
* Using a header on screens helps with personalization and visualization.
* Consider scrolling on the screen, for example, if it is a form, two thumb scrolls should be the maximum. For large forms, break it up into sections, and add the sections as a list with right arrows that takes you to a form for that section.
* Have the required input fields on the form with optional fields in another section.
* Limit the number of items returned on the screen in a list or add search or filter functionality.
* Try to minimize navigation and aim for smart navigation.
* Aim for a 30 -40 second engagement on screens, especially forms.
* Jigx design methodology encourages a 30-second success.
* Use one solution for multiple personas by using groups and permissions in [Jigx Management](/administration/management-overview).
* Keep things in-app, for example opening a site inside the app.


# Home screen

The home screen or [Home Hub](/building-apps-with-jigx/ui/home-hub) as it is called in Jigx is the entry point to your app and, therefore, needs to show the most relevant and important information upfront. Determine what users will interact with, then deep navigate into other screens.

<figure><img src="/files/8ja5pTVfTSM9hCRA5Iyw" alt="Plan the home hub"><figcaption><p>Plan the home hub</p></figcaption></figure>

#### Considerations

* Do you want a Home Hub with just widgets only or a custom home screen?
* The Home Hubis the entry point to the app, making it appealing by adding interactive elements. You can use [video-player](https://docs.jigx.com/examples/readme/components/video-player) or [carousel](https://docs.jigx.com/examples/readme/components/carousel) for visual interaction that includes videos, announcements, news clips, and more.

#### Tips

* Use the *jigx-widget* solution available in [Quick Start](/administration/quick-start) as a starting point to determine what widgets you want to use on the Home Hub.


# Data planning

Why create a data plan? Data is used throughout the Jigx App, knowing where the data is coming from or going to, how to use that data on the device, whether online or offline, what data you can prefetch and made available on the device, and what data you will fetch just in time is important to design before building apps. This saves developers time and ensures the correct data is used from the beginning.

<figure><img src="/files/0USy4iCMl1n6n4CLjCpA" alt="Data visualization"><figcaption><p>Data visualization</p></figcaption></figure>

#### Steps

1. Map out the data for the app. This includes the data that will be used on each screen.
2. Are you using pre-existing data sets or creating new data sets?
3. Decide where the data is coming from or going to, for example, [Microsoft Azure SQL](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql), [REST](/building-apps-with-jigx/data/data-providers/rest), [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data) (local or global), Salesforce or [Microsoft OneDrive](/building-apps-with-jigx/data/data-providers/microsoft-onedrive).
4. Map out the tables and joins that will help visualize the data and assist when building the data out.
5. Create an entity relationship diagram to model the app data.
6. Draw where the data points are needed on your sketch or Miro board created in the solution design step.
7. Most importantly, decide when to load data in the app and on the screens. For example, when must you cache fresh data from SQL vs. using local data, this helps with offline capabilities. See [When To Load Data](/building-apps-with-jigx/data/when-to-load-data) to understand the various options, benefits, and drawbacks.

#### Considerations

* Design the data flow with offline in mind. This helps to know when to plan the loading of data on an app.
* Privacy and keeping data safe are important, in this instance, it would be better to use an SQL server that provides this functionality.
* Data grows with time, plan for scalability.
* Data must be structured in the backend. Clean data ensures you show the latest and applicable data to your users. You can add filters and search fields to assist users in the app screens. Using relevant clean data from the start creates a real user experience while developing.
* Having the screens drawn out, as described in the Solution Design section above, helps visualize what data you need and when to load the data.
* Determine when you want to save or send data to a database, for example - only once a submit button is pressed. This is important as it determines what code is required at build time.
* In Jigx if the same data is reused in multiple screens, you can decide whether to create a global data source that can be reused in different jigs. Include this on the data plan as it helps the creator know where to build the datasource. In Jigx Builder global data is created under the datasources folder and referenced in multiple jigs, and local data is created in the jig file for use in that single jig.

#### Tip

* Having to create a database can be time-consuming or daunting, use tools such as ChatGPT to create a database, a database script, or build a CSV file for a data structure.
* For Dynamic Data a CSV file can be [uploaded](/administration/solutions/data) to Jigx Management to create the tables and data.
* In Jigx use [actions](/building-apps-with-jigx/ui/actions) to move data from screen to screen.
* When using REST or SQL, you need functions and stored procedures. Decide what the functions will do. Use Postman to understand the properties required.
* Be smart in the design of data by thinking of creating experiences, for example, data can be shown as charts rather than lists.


# Building the app

Now you are ready to start using your well-designed plan to build the app in Jigx Builder.

<figure><img src="/files/KpskbcJZr37rHz7WXiQR" alt="Build plan"><figcaption><p>Build plan</p></figcaption></figure>

### Steps

1. Start with the data. If you have a pre-existing datasource, create the functions, and stored procedures. If your data source is from scratch, start building the tables using [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data/creating-tables) or in [Microsoft Azure SQL](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql). Refer to your data plan for details.
2. Next, build out the skeleton app based on must-have functionality, follow your solution design for each screen, and create the corresponding jig file. Choose components and UI elements that meet the requirements. See [examples](https://docs.jigx.com/examples) for a list of components, actions, widgets and jigs that can be used.
3. Now add visual improvements and nice-to-haves. e.g., on an email field, add the email icon to interact with sending an email.
4. Publish your app to the Jigx Cloud. Open the app on the mobile device and test each screen, data, and usability. Use [Jigx Dev Tools](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/debugging.md) to debug the app, make changes and test again.
5. When the building of the app is complete, move on to the test plan.

<figure><img src="/files/OYRvPcJEQwIEdO9RoBiS" alt="App skeleton"><figcaption><p>App skeleton</p></figcaption></figure>

### Considerations

* If you not sure what component, action or widget to use in your app build - get inspired by using [Templates](/building-apps-with-jigx/ui/jigs-_screens_/jig-templates), the Jigx-sample, and the Jigx-widget projects in [GitHub](https://github.com/jigx-com/jigx-samples/tree/main/quickstart).
* When selecting the elements to add to the YAML, consider the usability, and shortest steps possible to get to where you want in the app.
* Minimize navigation, aim for smart navigation, 30-40 second engagement on screens, especially forms.
* Have the required input fields on the form with optional fields in another section.
* Jigx design methodology encourages 30-second success. This is important as mobile development is different from Web, and space is limited.

### Tips

* Create a prototype using [Templates](/building-apps-with-jigx/ui/jigs-_screens_/jig-templates) to see if a component or jig will work in your build, from there, you can customize the template YAML snippet.
* Practice continuous testing by testing after building each screen.


# Testing Plan

Test plans provide a baseline against which the actual testing activities can be evaluated. It helps track progress, measure the effectiveness of the app design, and identify any usability issues, errors, or missing functionality and avoid a compromised user experience.

### Steps

1. Decide who will perform user acceptance testing (UAT), it could be a colleague, test subject group, beta program, or even a friend or family member.
2. Test if the app is intuitive for the end user.
3. Cover functional testing.
4. Consider how to test the performance of the app, how long it takes to load data, or navigate between screens, or even to initiate the app.
5. Test what the experience is for a user when users run into expected errors.
6. Test the data for a first solution opening experience what do you see data/ empty screen/ errors? Often the solution might not have data in as it will get populated as the app is used, if you have not planned for this, the initial opening of the app could be a terrible experience. You can cater for this in the design.
7. Test the stages of onboarding or creating a profile.

### Tip

* Use placeholders when the app is new; you know that lists will be empty until they are populated with data. See Tips and Tricks - Use placeholders.


# Post App launch

Your Jigx App has successfully launched and is available in the App Store and Google Play store. This is not the end, a successful app solution has a plan for support and updates after the launch to ensure user satisfaction and app growth. Your app will require updates and new features that can be planned as part of a mobile application development lifecycle. Maintaining the app will continually be required by building new enhancements, fixing problems, and including updates to ensure its success.

<figure><img src="/files/bcqaue9Ig7eSxJVJmhyy" alt="" width="188"><figcaption></figcaption></figure>

In conclusion, by effectively planning a good app, you can engage users through a user-friendly UI that is consistent, secure, and provides a unique value offering to the user.


# Understanding the basics


# App Supported Versions

The following matrix outlines the supported operating systems and version requirements for the mobile app, ensuring compatibility, performance, and continued support.

**Minimum OS Version:** The lowest OS version required to install and run the app.

| OS / Version | Supported Devices    | Minimum OS Version |
| ------------ | -------------------- | ------------------ |
| iOS          | iPhone               | iOS 14             |
| iPadOS       | iPad                 | iPadOS 14          |
| Android      | Smartphones, Tablets | Android 14         |


# Architecture

The Jigx platform consists of components that work together enabling you to build enterprise mobile app solutions.

<figure><img src="/files/71S3tnNLRb99Pw6yeu93" alt="Jigx Overview"><figcaption><p>Jigx Overview</p></figcaption></figure>

<table><thead><tr><th width="165.296875">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/jigx-builder-code-editor.md">Jigx Builder</a></td><td>The Jigx Builder is an extension in Microsoft VS Code, a development environment that can be installed on many platforms, including Windows and Mac. Use YAML, SQL, JSON, and JSONata to build, test, debug, and publish Jigx mobile apps.</td></tr><tr><td>Jigx Cloud</td><td>JigxCloud authenticates users, stores organizations and solutions, and sends notifications.</td></tr><tr><td><a href="/pages/LrDzQIvcdLA1lqTH7yRY">Jigx Management</a></td><td>Jigx Management exposes the Jigx Cloud functionality in a browser-based portal, allowing you to manage users and solutions, set up send and push notifications, and view usage metrics of your organization.</td></tr><tr><td>Jigx App</td><td>The Jigx App is an iOS and Android app that works on mobile devices such as phones and tablets. The app is available in the iOS and Google Play stores. Jigx solutions built-in Jigx Builder, published to Jigx Cloud and permissions granted in Jigx Management are accessible in the Jigx App. The Jigx App is only supported in portrait mode on iOS and Android phones.</td></tr><tr><td><a href="/pages/MbccaAZUfezKGZhyJFq5">Data</a></td><td>Understanding how data is used and how it flows between the Jigx components is important. Jigx data concepts, including data lifecycles, syncing and loading data, and how to work with REST, Azure SQL, and Dynamic Data are covered in the <a href="/pages/MbccaAZUfezKGZhyJFq5">Data</a> topic.</td></tr></tbody></table>

### See Also

* [REST Authentication](/building-apps-with-jigx/data/data-providers/rest/rest-authentication)
* [Local REST Calls](/building-apps-with-jigx/data/data-providers/rest/local-rest-calls)


# Jigx Concepts

Jigx uses concepts, terminology, and elements you might not be familiar with. Below is an explanation of the main core concepts to help you understand and use Jigx better.

## Jigx Solutions

Jigx refers to a native mobile app as a *solution*. With Jigx you can build and publish more than one solution to your Jigx mobile app. You can *switch* between solutions by tapping the *More* ellipsis icon in the navigation bar and selecting your desired solution. The currently active solution is highlighted with a checkmark icon. If only one solution is available, the *More* icon is hidden.

<figure><img src="/files/dHchXKWzFU23igRRguGt" alt="" width="375"><figcaption></figcaption></figure>

## Home Hub

The *home hub* is the first screen you see when you open and sign into the Jigx mobile app. The Home Hub can display navigational menu blocks called *grid-items*, containing *images*, *widgets*, or custom controls. Once you tap on a grid-item, you are directed to a jig, which is a screen used to display various forms of content. The *index.jigx* file ﻿is the place to configure the bottom navigation bar. In addition to grid-items, you can style the Home Hub by adding a [video-player](/understanding-the-basics/jigx-concepts) or [carousel](/understanding-the-basics/jigx-concepts) at the top of the Home Hub. For more information, see ﻿[Home Hub](/building-apps-with-jigx/ui/home-hub) and [Creating a Home Hub](/building-apps-with-jigx/ui/home-hub/creating-a-home-hub).

<figure><img src="/files/EnV2P4cLwU0tP0PnDlrH" alt="" width="375"><figcaption></figcaption></figure>

## Jigx Builder

Native mobile solutions are built in Microsoft Visual Studio Code, a development environment installed on many platforms, including Windows and Mac. Jigx extends VS Code with the [Jigx Builder](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/jigx-builder-code-editor.md), which is an extension that allows you to build, test, and publish Jigx mobile app solutions. The **Jigx Builder** extension uses YAML, SQL, JSON, and JSONata. A YAML editor is provided that includes IntelliSense, which allows for code completion by simultaneously pressing the control and spacebar (ctrl+space) keys. Only valid options in the current cursor context are displayed in the code popup. There is built-in [debugging](/building-apps-with-jigx/jigx-builder-code-editor/debugging) functionality to assist with troubleshooting your development. Predefined code snippets are provided in the .jigx files to help make development easier and faster. The Jigx Builder loads with a [folder structure](/building-apps-with-jigx/jigx-builder-code-editor/editor#solution-scaffolding) to categorize the various files needed to build app solutions. These folders are actions, assets, databases, datasources, functions, jigs, and translations.

<figure><img src="/files/oqfjzPESCayWOsc7oofm" alt=""><figcaption></figcaption></figure>

## index.jigx file

The *index.jigx* file is located at the root of the Jigx solution project in the Jigx Builder. In the index.jigx file, you configure what must be displayed on the home screen (Home Hub) of your solution on the Jigx mobile app. The file opens with a pre-populated code snippet to help you configure the Home Hub. For more information, see [Index settings](/building-apps-with-jigx/ui/home-hub/index-settings), and [Creating a Home Hub](/building-apps-with-jigx/ui/home-hub/creating-a-home-hub).

<figure><img src="/files/OArwIg4uQFD9LNnBSWpk" alt=""><figcaption></figcaption></figure>

## Widgets

Widgets are navigational menu blocks set up on jigs, allowing them to be utilized in various parts of the solution, including the Home Hub and multiple jigs (screens). These widgets are configurable to display various UI elements, such as locations, images, charts, and more. For more information, see [Content widget components](/understanding-the-basics/jigx-concepts).

<figure><img src="/files/hCuRWE01kLvsM1mFfHrF" alt="" width="375"><figcaption></figcaption></figure>

## Jig

A jig is a container used to configure content. A jig can be configured as a calendar, a form to capture or view data, a PDF or HTML document, a list of data, or even a combination of any one of these. Usually, tapping on a widget in the [Home Hub](/building-apps-with-jigx/ui/home-hub) opens a jig. For more information, see [Jigs (screens)](/building-apps-with-jigx/ui/jigs-_screens_) and [Jig Types](/understanding-the-basics/jigx-concepts) sections in this guide.

<figure><img src="/files/yLFf8rHX67CXzrPlOB8C" alt="" width="375"><figcaption></figcaption></figure>

## Components

Components are elements that can be used when creating a Jigx solution in the Jigx Builder. These elements provide an incredible amount of functionality. Components include interactive images, video players, expanders, and charts. For more information, see [Components (controls)](/building-apps-with-jigx/ui/components-_controls_) and [Components](/understanding-the-basics/jigx-concepts) example topics in this guide.

<figure><img src="/files/3QzZFYtQIs0L8G1Pqc3s" alt=""><figcaption></figcaption></figure>

## Actions

Actions allow you to do something, for example, go back to a previous screen, open a URL, or submit a form. For more information on the available actions as well as code samples for each one, see the [actions](/building-apps-with-jigx/ui/actions) and [action examples](/understanding-the-basics/jigx-concepts) sections of this guide.

<figure><img src="/files/uGGQpnf3YaRUINAZgvUf" alt=""><figcaption></figcaption></figure>

## Functions

Functions enable integration with other platforms through data providers. Creating a new function using one of the provided template options adds the skeleton code to the function definition, making it easier to configure with their authentication requirements. For more information, see [REST Functions](/administration/solutions/rest-functions), [SOAP Functions](/administration/solutions/soap-functions), and [SQL Functions](/administration/solutions/sql-functions).

<figure><img src="/files/kopcNYx619BQfu9YUBmA" alt=""><figcaption></figcaption></figure>

## Expressions

Expressions allow you to structure data before binding it to the UI components. Expressions are **JSONata** language-based. JSONata is a lightweight query and transformation language for JSON data. JSONata is a rich complement of built-in operators and functions providing options to manipulate and combine data. Learn more about [JSONata](https://jsonata.org/) and try out your expressions in their [JSONata Exerciser](https://try.jsonata.org/). The root element of Expressions in .jigx files starts with "@ctx" vs. "$." in JSONata Exerciser (e.g., @ctx.data vs. $.data). Jigx supports shorthand $ expressions for JSONata. For more information, see [Expressions](/building-apps-with-jigx/logic/expressions), [Expressions - cheatsheet](/building-apps-with-jigx/logic/expressions/expressions-cheatsheet) and [Expression examples](/understanding-the-basics/jigx-concepts).

<figure><img src="/files/N5TD3S71arxKLFN6pFYq" alt=""><figcaption></figcaption></figure>

## Datasources

[Datasources](/building-apps-with-jigx/data/datasources) are sets of data that are available throughout your whole solution (global) or only inside a jig (local). Datasources can be static or dynamic. Jigx **Dynamic Data** is a built-in database that can be used to create, read, update, and delete data in an app. The underlying data store for Dynamic Data is a NoSQL store. This means that each record can have its own field structure, and you can add or remove any fields on a per-record basis. Only the id column is a system column and cannot be changed or removed from the record. Jigx Dynamic Data is managed in Jigx Management. For more information, see [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data) and [Dynamic Data examples](/understanding-the-basics/jigx-concepts) .

## Database

A [data provider](/building-apps-with-jigx/data/data-providers) is a service that accepts data inputs and returns data outputs. Jigx data providers include dynamic, local, REST, Salesforce, SOAP and SQL. For more information see [Data Providers](/building-apps-with-jigx/data/data-providers) and [Data Provider examples](/understanding-the-basics/jigx-concepts).

## Entities

Entities are tables in Jigx Dynamic Data or other databases where your data gets saved, created, updated, and deleted. Use an action such as execute-entity to work with the data. Jigx data is managed in the [Data](/administration/solutions/data) menu option in Jigx Management. Other databases are managed using the [connections](/administration/solutions/connections), [SQL Functions](/administration/solutions/sql-functions), [REST Functions](/administration/solutions/rest-functions), and [SOAP Functions](/administration/solutions/soap-functions) in Jigx Management. For more information, see [execute-entity](/understanding-the-basics/jigx-concepts).

## Jigx Management

Jigx Management exposes the Jigx Cloud functionality in a browser-based portal allowing you to manage users and solutions, set up send-and-push notifications, set up data, and view usage metrics of your organization. For more information, see [Management Overview](/administration/management-overview).

<figure><img src="/files/Dd3TLP8jyqCaK8XpUcTG" alt=""><figcaption></figcaption></figure>

## Jigx App

The Jigx app is available on iOS and Android and works on any device.

* Download the Jigx iOS app from the [App Store](https://apps.apple.com/sg/app/jigx/id1495596537)
* Download the Jigx Android app from the [Google Play Store](https://play.google.com/store/apps/details?id=com.jigx.android\&pli=1)
* The Jigx App is only supported in portrait mode on iOS and Android phones.
* You can brand your app through [Organization Settings](/administration/organization-settings)

### See Also

* [Jigx color palette](/understanding-the-basics/jigx-color-palette)
* [Jigx icons](/understanding-the-basics/jigx-icons)


# Authentication

There are several options available to verify the identity of an individual using the Jigx App. The authentication options are:

### Jigx User Manager

When a user logs into the app on a mobile device, they need to be [registered](http://manage.jigx.com/register) in Jigx and assigned a Jigx account. This can either be through an email invitation, registering at <http://manage.jigx.com/register>, or requesting to join an organization on the app's Home Hub. Jigx user manager uses AWS Cognito for Authentication. Passwords are encrypted and cannot be read by users in Jigx Cloud.

When the user signs in, the credentials are matched in Jigx Cloud, and if valid, a Jigx token is returned to the device, where it is stored in the device keychain. All subsequent calls are made using the Jigx token in an SSL tunnel.

<figure><img src="/files/U5KJhYX2G8nbFVvCjg72" alt=""><figcaption></figcaption></figure>

### Jigx User Manager with Secondary credentials

Jigx user manager with Secondary credentials or authentication providers. This requires users to sign in with their Jigx user credentials and secondary credentials such as Microsoft or Salesforce. Secondary credentials are set up on a solution using OAuth. The OAuth is referenced by name in the REST (OAuth) function call.

An organization is configured for auto provisioning or a per-user invite, requiring administrative approval. The AAD or Okta configuration is stored in AWS-secured storage in Jigx Cloud. When the user signs in, the configuration for the organization is retrieved and sent to the mobile device. The configuration information runs the user through an OAuth loop with the configured external IDP, AAD, or Okta.

When auto-provisioning is enabled, if the user is validated by AAD or Okta and does not yet exist in the organization, Jigx will automatically create the user and do the necessary Jigx token creation and assignment. If the user exists in the Jigx Cloud and is authenticated successfully by AAD or Okta, the user is assigned a Jigx token for all subsequent calls. If the organization does not enable auto-provisioning, the user can request access, which needs to be approved by an administrator. Once approved, the user will be provisioned in Jigx.

* See [REST Authentication](/building-apps-with-jigx/data/data-providers/rest/rest-authentication) for OAuth configuration steps in Jigx Management
* See [Create and configure a new OAuth app in Microsoft Azure AAD](/building-apps-with-jigx/data/data-providers/rest/microsoft-graph-oauth/configuring-oauth-for-ms-graph/create-and-configure-a-new-oauth-app-in-microsoft-azure-aad)
* See [Configuring OAuth for MS Graph](/building-apps-with-jigx/data/data-providers/rest/microsoft-graph-oauth/configuring-oauth-for-ms-graph)

<figure><img src="/files/5xXtfi14owsHvPp6b4cb" alt=""><figcaption></figcaption></figure>

**Data flow with REST**

1. Jigx fetches the solution definition with a valid Jigx token.
2. Function calls are made to the [REST](/building-apps-with-jigx/data/data-providers/rest)-enabled cloud service using the Jigx Cloud as a proxy, for example, for IP Allowlisting. The function calls can use OAuth, secrets, and tokens, but not basic authentication. OAuth configuration, secrets, tokens, and basic authentication are securely encrypted and stored in AWS. They are not user readable and are only used when the function call is made by a device with a valid Jigx token. The result is processed in the Jigx Cloud, including all function transforms, continuation, and error transforms, and sent to the device. The data is never stored in the Jigx Cloud and is only ever kept in memory while the function is executing. Function calls can be made directly from the device to the REST-enabled cloud service using the [local execution model](/building-apps-with-jigx/data/data-providers/rest/local-rest-calls).
3. OAuth configuration, secrets, and tokens are stored in the secure keychain on the device when the solution definition is synced. The result is processed on the device, including all function transforms, continuation, and error transforms, and the result is stored in SQLite on the device. The data never travels through the Jigx Cloud. SQL Server is currently not supported for local on-device execution.

**Data flow with Microsoft SQL**

1. Jigx fetches the solution definition with a valid Jigx token.
2. Jigx function calls are made from the device to SQL Azure or Microsoft SQL Server, using the Jigx Cloud as a proxy, for IP Allowlisting. The function calls use the connection configuration stored as a secure encrypted secret in Jigx Cloud on AWS. The SQL credentials are never sent to the mobile device. Once saved, the SQL credentials are not user readable and are only used by the Jigx Cloud when the function call is made by a device with a valid Jigx token. The result is processed in the Jigx Cloud, including all function transforms, continuation, and error transforms, and sent to the device. The data is never stored in the Jigx Cloud and is only ever kept in memory while the function is executing.&#x20;

### Single Sign-on (SSO)

[Single Sign-On (SSO)](/administration/organization-settings/single-sign-on-_sso_) authenticates the user against a 3rd Party Identity Provider (IDP). When a user logs into the app, Jigx checks if SSO is enabled for the organization, the check is based on the domain of the emails linked to the organization. Next, the OAuth configuration is checked to see if it points to the same domain. The OAuth redirect URL is verified for a match against the app configuration. The user is then authenticated against the 3rd party IDP. If the user is a match in Jigx and the 3rd party IDP, a Jigx access token is generated, and the user is granted access to the app. SSO is enabled in Jigx Management on an organizational level. The diagram below explains the Jigx SSO flow. See the [Single Sign-On (SSO)](/administration/organization-settings/single-sign-on-_sso_) and [OAuth Configurations](/administration/organization-settings/oauth-configurations) sections to learn how to enable SSO and OAuth.

<figure><img src="/files/TSxpfJjkMF37ZTp91i2Q" alt=""><figcaption></figcaption></figure>


# Jigx color palette

The Jigx mobile app color palette, or color scheme, is a predefined selection of colors used consistently throughout the mobile application's user interface (UI). The color palette is essential for creating a visually appealing and cohesive user experience.

### Default color palette

Below is an image showing the Jigx default color palette, and which UI interfaces use the color.

<figure><img src="/files/RfLaJ4YVZRpUwF6e1UVm" alt=""><figcaption></figcaption></figure>

### Selecting default colors in Jigx Builder

While creating your solution you can configure certain components, and widget colors in the YAML to use either the default primary, semantic, or complementary colors. Use intelliSense (ctrl+space) to determine if you can specify a color. If you can choose a color from the list of available colors.

<figure><img src="/files/3kYch43uVDKO5DLDaJbT" alt=""><figcaption></figcaption></figure>

### Changing the default colors

You can define colors for branded apps in Jigx Management [Organization Settings](/administration/organization-settings). Note that any changes to colors in a branded app requires the app to be re-uploaded to the app stores.

### Applying colors based on specific conditions

Colors can be configured based on specific conditions. For example, a payment amount exceeding a certain threshold can be displayed in red. However, conditional color configurations are only available in areas that support conditions, such as list items. In contrast, direct color options are more widely supported, for example, `lists` allow both conditional and direct setups, whereas `interactive-images` only support direct options. Additionally, certain areas restrict the available color choices, while UI elements support the predefined set of fourteen colors.

* When configuring the `color` property, select the `color condition`boption.
* Under the `when` property, add an expression that defines the condition under which the specified color should be applied.&#x20;

{% code title="color-condition" %}

```yaml
color:
   - when: =@ctx.current.item.registered = true 
     color: color2
   - when: =@ctx.current.item.registered = false
     color: color4          
```

{% endcode %}

{% code title="color (no condition)" %}

```yaml
options:
  color: color2
```

{% endcode %}


# Jigx icons

Incorporating icons into your mobile app design enhances user navigation and interaction, making the app more user-friendly and visually appealing. At Jigx we provide you with an extensive list of icons.

### Where can you use icons?

While creating your solution, you can configure certain UI components, jigs, and widgets to use icons in the YAML. Additionally, you can determine the icon's position, size, and interaction. Use IntelliSense (ctrl+space) in the YAML in Jigx Builder to determine if you can specify an icon. Choose an icon from the list and configure the provided properties if you can. Examples of properties that use icons are `leftElement`, `rightElement`, and `leftIcon`. Here is an example showing you how to specify an icon in a `leftElement` and how to use an [expression](/building-apps-with-jigx/logic/expressions) to determine which icon to display depending on the current list item.

{% columns %}
{% column width="41.66666666666667%" %}

<figure><img src="/files/EsjT456e71GdQB6dHN5M" alt="List icons in a list" width="188"><figcaption><p>List icons in a list</p></figcaption></figure>
{% endcolumn %}

{% column width="58.33333333333333%" %}
{% code title="YAML" %}

```yaml
type: component.list-item
  options:
    title: =@ctx.current.item.service
    subtitle: =@ctx.current.item.time & 'minutes for task completion'
    leftElement:
      element: icon
      icon: =(@ctx.current.item.materials) = true ? 'home' :'car-garage'
```

{% endcode %}

{% endcolumn %}
{% endcolumns %}

### How do you add an icon?

Icons can be used either in the YAML key position to select an icon, for example `icon: house`, or as the YAML value to determine that a property must use an icon, for example, in a `LeftElement: icon` property. IntelliSense propmts you and shows where the icon can be used in the YAML.

**Examples**

{% columns %}
{% column %}
Using the `icon` as a key in YAML to display an alarm bell icon on the Home Hub widget.

{% code title="YAML (icon key)" %}

```yaml
title: Home Security
type: jig.default
icon: alarm-bell
```

{% endcode %}
{% endcolumn %}

{% column %}
Using the icon as a value and then as the key in YAML to display the dollar icon in a `component.summary` .

{% code title="YAML (icon value)" %}

```yaml
summary:
  children:
    type: component.summary
    options:
      layout: default
      title: Add to cart
      leftIcon:
        element: icon
        icon: currency-dollar-circle
```

{% endcode %}
{% endcolumn %}
{% endcolumns %}

1. Next to `icon:` start typing the first two letters of an icon name, for example al, this will open the list of icons starting with two letters.
2. A preview of the icon is shown in the right popup with a link to the icon in [streamline](https://www.streamlinehq.com/icons/streamline-bold).
3. Use the up and down arrows on your keyboard to browse through the list with the preview showing.
4. Once you have decided on an icon click Enter.

### Where can you see a preview of the icon?

The list of available icons is extensive and is based off the icons in [https://www.streamlinehq.com/icons/streamline-bold ](https://www.streamlinehq.com/icons/streamline-bold). You welcome to browse this link. In Jigx Builder a preview of each icon is available in the right popup with a link to the icon in [streamline](https://www.streamlinehq.com/icons/streamline-bold). All you need to do is start typing the first two letters of an icon you want.

<figure><img src="/files/BOlQnDEZW6DbfKymcZkO" alt="Preview of icons"><figcaption><p>Preview of icons</p></figcaption></figure>

### Icon assets in solutions

All icons used throughout a solution are automatically added to the **icon.jigx** file under the **assets** folder. This improves performance of the app and ensures that all icons are available when the mobile device is offline and the app is in use.

The following applies to the asset list:

* Each icon change detection automatically causes an update in the list in the icon.jigx file.
* All icons from all jig files are added to the list, expect icons referenced or listed within datasources e.g., `=@ctx.datasources.ds.icon`. You can manually add these icons to the asset list in the icon.jigx file.
* Icons are added to the icon asset list automatically or you can manually add icons to the list.
  * Automatically generated icons are indicated by a comment `# auto-generated` after the icon name in the list.
  * Manually added icons do not have the comment added

<figure><img src="/files/U544YTvkwBDTOiTPpBgY" alt="Icon asset list"><figcaption><p>Icon asset list</p></figcaption></figure>

### Icons in actions

Adding an `icon` property in an action only applies to `swipeable`, `secondary`, and `header` actions. Primary actions do not support icon setups.

### Can I add custom icons?

The list of icons is not customizable, and you cannot add custom icons. If you are unable to find the icon you need, contact [**support@jigx.com**](mailto:support@jigx.com).


# Building Apps with Jigx


# Jigx Builder (code editor)

The Jigx's development environment is called Jigx Builder, which is a VS Code extension that uses YAML, SQL, JSON, and JSONata, and makes use of the rich set of functionality that VS Code offers. To learn more about VS Code functionality and managing extensions, see [Visual Studio Code](https://code.visualstudio.com/docs) documentation.

{% embed url="<https://vimeo.com/829856148?share=copy>" %}

Below is what you need to know when developing in Jigx Builder.

* [Installing](/building-apps-with-jigx/jigx-builder-code-editor/install) the Jigx extension
* Configurable [settings](/building-apps-with-jigx/jigx-builder-code-editor/settings)
* Supported [source control](/building-apps-with-jigx/jigx-builder-code-editor/install)
* Using the [Editor](/building-apps-with-jigx/jigx-builder-code-editor/editor)
* How to [create a new solution](/building-apps-with-jigx/jigx-builder-code-editor/create-a-new-jigx-solution)
* How to [publish a solution](/building-apps-with-jigx/jigx-builder-code-editor/publishing-a-solution)
* How to [debug and test solutions](/building-apps-with-jigx/jigx-builder-code-editor/debugging)
* [Tips, tricks and shortcuts](/building-apps-with-jigx/jigx-builder-code-editor/tips-tricks-and-shortcuts) to help you accelerate your development


# Install

This section covers installing the Jigx Builder extension, versions, updates, uninstalling, and the recommended source control. The numbered image below indicates each of these areas in the Jigx Builder.

<figure><img src="/files/bjtaYW6aUzNJPSTsJuoC" alt="Jigx Builder installed"><figcaption><p>Jigx Builder installed</p></figcaption></figure>

## 1. Install steps

1. Start by downloading and installing VS Code on your development machine. The download is available from <https://code.visualstudio.com/download>.
2. The Jigx Builder extension is in the [Microsoft Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=Jigx.jigx-builder). Click on the VS Code extension icon in the left navigation bar and search for Jigx Builder.
3. Click the blue **install** button.
4. The Jigx Builder now appears under your list of installed extensions, and is automatically added to the side bar, and is identifiable by its unique icon.

## 2. Versions

The current version of the Jigx Builder extension is shown at the top of the *Extension: Jigx Builder* screen. When a new version is available VS Code automatically installs the latest version and prompts you to reload VS Code.

## 3. Updates

When a new version is available VS Code automatically installs the latest version and prompts you to reload VS Code. Refer to the changelog tab in the *Extension: Jigx Builder* screen to see what changes are included in the new version. If you prefer to manually update the extension see [VS Code documentation - Manage extensions](https://code.visualstudio.com/docs/editor/extension-marketplace#_manage-extensions).

## 4. Uninstall steps

1. To uninstall the Jigx Builder, click on the extensions icon in VS Code.
2. Click the blue **Uninstall** button in the *Extension: Jigx Builder* screen.
3. You can also uninstall the extension by clicking on the **Manage** gear icon at the top right of the extension and selecting **Uninstall.**
4. Reload VS Code.

## 5. Source Control

Manage your Jigx solutions with Git integration in VS Code. See using [Git source control in VS Code](https://code.visualstudio.com/docs/sourcecontrol/overview) for more information. When a solution in Jigx Builder is connected to a Git repository the files in the side bar will show in green when a new file is added, yellow for files that have been modified, when there are validation issues that need to be addressed, or *white* when files are commited.

{% columns %}
{% column %}
In Jigx Management under [Solution Settings](/administration/solutions/solution-settings) you can store the details of your Jigx solution's sourcecode repository, allowing people to easily find the details and contribute to the solution.
{% endcolumn %}

{% column %}

<figure><img src="/files/ea7EINOiSHlJE96JwJsf" alt="Sourcecode details"><figcaption><p>Sourcecode details</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}


# Settings

The Jigx *Extension Settings*, accessed via the *manage gea*r icon, contain many options that can be modified. For Jigx, there is one main option to modify; the remaining options can be left unchanged. This is the **Jigx: App name** setting, which determines which Jigx App on a device must be connected when [debugging](/building-apps-with-jigx/jigx-builder-code-editor/debugging) a solution in Jigx Builder. There are two main types of apps, namely:

1. Jigx App- downloaded from the Play or App stores.
2. Jigx branded apps - a Jigx App that has been branded for your organization in [Jigx Management](/administration/organization-settings), and added to the Play or App stores.

It is important to configure which app you want to connect to as the [debugging](/building-apps-with-jigx/jigx-builder-code-editor/debugging) Jigx Dev tools QR code is generated using the **Jigx: App name** setting.

<figure><img src="/files/9MYYQZWFiLOk6v88LkaT" alt="Jigx extension settings"><figcaption><p>Jigx extension settings</p></figcaption></figure>

To configure the **Jigx: App name** setting follow the steps below:

1. When connecting to the Jigx App available from the Play or App stores leave the setting empty.
2. When connecting to a Jigx branded app, go to Jigx Management / Branding/ App configuration and copy the **App Name**, then paste the name in the **Jigx: App name** setting in Jigx Builder. \
   ![](/files/wSc2E8EGifcR2jSmbgO9)
3. Regenerate the QR code when changing app names in settings by clicking the **Refresh QR code** icon in Jigx Dev tools - **Connect to Device** pane.

{% hint style="info" %}
You can check which app your Jigx Dev Tools will connect to by hovering over the QR code and look for the *appname* in the string, if it is blank you connecting to the Jigx App.
{% endhint %}


# Editor

To accelerate the build experience, Jigx Builder has a YAML editor that includes IntelliSense for code completion, predefined code snippets, and preloads with scaffolding ready to add your Jigx files in the correct structure needed to build app solutions.

## Solution scaffolding

By default Jigx creates scaffolding when loading a new project in Jigx Builder. We recommend avoiding naming new files with the same name in the scaffolding. Words used by the Jigx system include actions, components, jig, databases, datasources, functions, and index.

<table><thead><tr><th width="155.66796875">Folder</th><th width="171.30859375">Default File</th><th>Description</th></tr></thead><tbody><tr><td>.vscode</td><td>settings.json</td><td>Relates to your Jigx solution and contains internal parameter settings required by Jigx Builder runtime. This file's scope is local (workspace) and applies to the current solution. For more information, see .</td></tr><tr><td>actions</td><td></td><td>Actions refer to specific controls or operations responding to an event or input. Create under the actions folder to define actions once and reuse them multiple times in different jigs.</td></tr><tr><td>assets</td><td></td><td>The solution's images and icons defined under the folder will preload and cache when the solution downloads or updates in the app. Allows images and icons to display when the app is offline and improves the app's performance.</td></tr><tr><td>databases</td><td>default.jigx</td><td>You can use the <code>default.jigx</code> file to define the tables in the Provider.</td></tr><tr><td>datasources</td><td></td><td>Create global data files with .jigx extension- these are available for use in your whole solution to any of the jigs.</td></tr><tr><td>functions</td><td>myfirstfunction.jigx</td><td>You can build logic into your solution by adding functions to get or update data from a remote service, such as or <a href="/pages/Ni1XqR8LcaD3SLRqxSeB">SQL Functions</a>.</td></tr><tr><td>jigs</td><td>myfirstjig.jigx</td><td>The jigs folder is where you create all the files used to configure the screens for the app on your mobile device. You can create sub-folders inside the jigs folder for categorization. All files in the jigs folder must have the <code>.jigx</code> extension, e.g., leave-form.jigx</td></tr><tr><td>translations</td><td></td><td>Create files for various languages using localization, then reference the file in your jig using the <code>Text Locale</code> property with <code>id: file name</code>. For more information, see .</td></tr><tr><td></td><td>index.jigx</td><td>The index.jigx file is the app's home screen. It uses bottom tabs to determine the layout. See and <a href="/pages/I5dmYIsnycXmYDmFzu6S">Index settings</a> for more information.</td></tr><tr><td><p>scripts/</p><p>expressions</p></td><td></td><td>Create .js files to define your that can be used in <a href="/pages/Rf2BS4MUdVtqcEy928C1">expressions</a>.</td></tr></tbody></table>

## IntelliSense

To invoke IntelliSense, simultaneously press the control and spacebar (ctrl+space) keys. The code popup displays only valid options in the current cursor context. Selecting an option from the IntelliSense menu will load the code snippet with the necessary properties for that option.

{% embed url="<https://vimeo.com/829865905?share=copy>" %}

## YAML indentation

In Jigx Builder the YAML code snippets use indentation. The nested structure of the YAML is visible with spaces, not tabs, and is used for indentation. Each nested level is indented further than its parent, illustrating the hierarchical structure of the YAML file. Line numbers are visible on the left side, and your cursor blinks at one of the lines. You can use a VS Code plugin to highlight the indention levels in different colors. One such plugin is [Indent-Rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow).

<figure><img src="/files/EQLqvrXmHM2PGnMM30VD" alt="Indentation levels in color"><figcaption><p>Indentation levels in color</p></figcaption></figure>

## Code snippets

Code snippets are there to help you develop quicker by providing you with recommended properties to use for a jig type, component, action, or widget. You do not need to use all the code snippets provided; you can remove the unwanted properties.

<figure><img src="/files/7lBE4jbalnNjLbsxyOQD" alt="IntelliSense &#x26; code snippets"><figcaption><p>IntelliSense &#x26; code snippets</p></figcaption></figure>

## Validation

Jigx validates the structure and values in the `.jigx` YAML files and shows the issues that you need to fix.

<figure><img src="/files/kFrAuuL755XzLJUGIT1g" alt="Validation"><figcaption><p>Validation</p></figcaption></figure>

Validation issues are shown in:

* The **file name** in the side bar will be red, with the number of issues in the file shown by a red number on the right of the file name.
* **Red squiggles** appear under the YAML. Hover over the YAML for more information, if we can detect what the value should be we offer a quick-fix link. Clicking on the link will fix the issue and resolve the validation.
* In the **Problems tab** of the Jigx Dev tools window, the file and a description of the issue is shown. Click on the item to go to the exact ssue in the file.

{% hint style="warning" %}
Validation does not always prevent you from publishing your solution. The solution on the mobile app might not function as expected if the validation issues are not resolved.
{% endhint %}

## Validation - Solution Diagnostics

**Jigx Solution Diagnostics** is a built-in analysis tool that helps you identify and troubleshoot issues across your entire Jigx solution or a subset of files in the solution. It detects project build errors, missing references, and scans your source code for programmatic errors, warnings, and overall solution health.

### Running Solutions Diagnostics

You can access the Jigx Solution Diagnostics tool through the **Jigx Explorer** by clicking the diagnostics icon, or by using the VS code command-palette accessed by fn+F1 / command+shift+P / ⇧⌘P / alt+shift+P and selecting **Run Jigx Solution Diagnostics**.

<figure><img src="/files/uj2HXAqksIoSDPiYCGU4" alt="Diagnostics icon" width="563"><figcaption><p>Diagnostics icon</p></figcaption></figure>

To run the tool on a subset of files, use the VS code comman-palette accessed by fn+F1 / command+shift+P /⇧⌘P / alt+shift+P and select **Run Jigx Solution Diagnostics – with filter**. Then, provide a regular expression (regex) to filter and analyze only the matching files, for example an expression for all files is `/jigs/.*`.

<figure><img src="/files/gfiCJ5TU0UwO8NITvPS7" alt="Diagnostics commands"><figcaption><p>Diagnostics commands</p></figcaption></figure>

### Solutions Diagnostics progress

The progress is shown as a **notification** in the bottom-right of the VS code window.

<figure><img src="/files/eBlcBURO1WLIVPSxutsO" alt="Solution Diagnostics notifications"><figcaption><p>Solution Diagnostics notifications</p></figcaption></figure>

When the diagnostics run is complete, the results are displayed in the **Jigx Output** panel. The output includes the file path, a description of the issue, and the number of issues found in each file. You can navigate to the relevant file to review and resolve the errors.

{% hint style="warning" %}
The URL to open the file in the Jigx ouput panel will not work if the folder contains spaces.
{% endhint %}

<figure><img src="/files/58zx0ulny09aQVKBg5tD" alt="Jigx output"><figcaption><p>Jigx output</p></figcaption></figure>

## Quick-fix validation

{% columns %}
{% column %}
The **quick-fix validation popup** in VS Code helps you identify and resolve issues in your code or configuration files quickly and efficiently. When a validation error or warning is detected (such as a missing property, invalid value, or syntax issue), a lightbulb icon appears next to the line.
{% endcolumn %}

{% column %}

<figure><img src="/files/6udN69rSDAstCcjhRE5j" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

**How to Use It:**

1. **Hover or place your cursor** on the line showing the issue or on the highlighted error squiggle.
2. Press `Cmd + .` (Mac) or `Ctrl + .` (Windows/Linux) to open the **quick-fix popup**.
3. A list of suggested fixes or options will appear. These may include:
   * Adding missing fields or properties
   * Correcting values
   * Applying code suggestions
   * Ignoring the issue
4. **Select a fix** from the list using your arrow keys and press Enter to apply it.

## Navigating code definitions & references

This feature is particularly useful in large projects or when working with unfamiliar codebases, as it helps you understand how and where certain pieces of code are implemented without manually searching through files. If the code has multiple definitions or references, VS Code presents a list of all these instances, allowing you to choose the one you're interested in.

The following code definitions and references can be navigated:

* fileId references
  * jigs
  * linkTo, jigId
  * datasources
  * ctx.datasources.datasourceName
  * functions
  * components
  * actions
* entity references
  * databases/default.jigx
  * entity, entities
* components references
  * instanceId, @ctx.components.componentInstanceId...
* script references
  * JavaScript functions

### Definition (F12)

<figure><img src="/files/Ke8tIuNKcnJDMYJbXTC2" alt=""><figcaption></figcaption></figure>

Place your cursor on the code and press **F12** or right-click and select **Go to Definition** from the menu options, VS Code displays a preview window that lists all the lines of code in your project where that code is used, either in the same jig or another file in the project. VS Code will open the file where that code is defined and move the cursor to the definition's location.

### References (shift+F12)

<figure><img src="/files/qaVGLeUrf2xG9BmfWuMa" alt=""><figcaption></figcaption></figure>

Place your cursor on the code and press **Shift + F12** or right-click and select **Go to References** from the menu options, VS Code displays a preview window that lists all the lines of code in your project where that code is used or referenced. If there are multiple references, you can click on any of the listed references in the preview window to go directly to that location in the code.


# Create a new Jigx Solution

Creating a Jigx App starts with building a solution in Jigx Builder, then [publishing](/building-apps-with-jigx/jigx-builder-code-editor/publishing-a-solution) the solution to Jigx Cloud.

### Solution requirements

Every Jigx solution requires the following:

* **Solution title** - the solution title is visible at the top of the [home hub](/building-apps-with-jigx/ui/home-hub) screen in the app. Ensure that the title is unique, as there is no validation on the name, which could result in overwriting an existing solution with the same title.
* **Solution name** - The solution name is the system name and Jigx derives the name from the solution title with the following rules applied:
  * Cannot start with a number
  * No spaces are allowed; hyphens replace spaces
  * It must be in lowercase
* **Solution category** - Provides a list of predefined categories to choose from. The category you select displays as a tag at the top of your solution in the [Home Hub](/building-apps-with-jigx/ui/home-hub) under the solution title in the app.
* **Solution location** - either on your local machine or in a Git repository.
* **Index.jigx** - The index.jigx file is the home screen for the app. Add tabs to determine the layout. See [Home Hub](/building-apps-with-jigx/ui/home-hub) and [Index settings](/building-apps-with-jigx/ui/home-hub/index-settings) for more information.

{% embed url="<https://vimeo.com/829859076?share=copy>" %}

### Steps

1. Open VS Code, and click on the Jigx Builder **icon** in the left navigation bar. Select the **Create New Jigx Solution** button.
2. Provide a **solution title** and press enter.
3. The **Solution name** field pre-populates with the solution's system name. You can provide a different solution name if you want.
4. Select a relevant **category** where you want the solution saved.
5. Select a local folder or Git repository where the project files are saved too.
6. Your Jigx [solution scaffolding](/building-apps-with-jigx/jigx-builder-code-editor/editor) opens in the VS Code editor with the .jigx extensions ready for editing.

Follow the steps in the getting started section to [build your first Jigx solution](/getting-started/create-an-app-from-scratch).


# Publishing a solution

After building the solution in Jigx Builder, you publish the solution to Jigx Cloud. The solution is immediately available in the Jigx App.

You can publish the full solution or choose to publish a single file. Publishing the full solution is required on the first publish. Single file publishing is useful if you made a change to only one file and want to publish the changes or you working on a solution with multiple developers and you only want to publish your changes. Note that the index.jigx file is a shared file that people all work on, so the last updates on the server get published.

## Permissions

When a solution is published, the solution is automatically added to [Solutions](/administration/solutions) in Jigx Management. The creator of the solution is given Owner permissions and can give users access to the solution in Jigx Management, define their role in the solution scope, and assign `Solution Group` membership for the visibility of widgets.

## Publishing steps

### Full solution

To publish the **entire** solution, follow the steps below:

1. In VS Code click on the Jigx Builder **icon** in the left navigation bar.
2. In the Jigx Explorer hover over the solution node till you see the **publish icon (rocket)**.\ <img src="/files/erar8Ep7GESi86Rf1vN5" alt="" data-size="original">\
   &#x20;
3. Click on the icon to start the publishing process.
4. On a new solution you will be asked to enter your Jigx username and password, organization and region.
5. If you are already logged in, the solution will publish without having to sign in again. The solution's name and organization are displayed in the VS Code status bar.
6. The publishing process starts and the progress shows in the bottom right corner of the VS Code editor. A message displays when the solution is successfully published.

### Single files

To publish a **single** file in the solution follow the steps below:

1. In Jigx Builder locate the file in the side bar explorer that you want to publish.
2. Right-click on the file and click **Publish Jigx file**. If you not signed in you will be asked to enter your Jigx username and password, organization and region. Alternatively you can use the shortcut keys given below. \
   ![](/files/Bs7yNpGTMMwslglU3hQV)<br>

## Publishing shortcuts

<table><thead><tr><th width="257.83203125">Shortcuts</th><th>Mac</th><th>Windows</th></tr></thead><tbody><tr><td>Publish all files in Jigx solution</td><td>⌘R⌘R</td><td>Alt+R Alt+R</td></tr><tr><td>Publish an individual file</td><td>⌘R⌘F</td><td>Alt+R Alt+F</td></tr></tbody></table>

## Viewing published solutions in the app

{% columns %}
{% column width="41.66666666666667%" %}
With Jigx, you can build and publish multiple solutions to your mobile app.

You can switch between them by tapping the *More* (ellipsis) icon in the navigation bar and selecting the solution you want to use.

The currently active solution is highlighted with a *checkmark* icon.

If only one solution is available, the M*ore* icon is hidden.
{% endcolumn %}

{% column width="58.33333333333333%" %}

<figure><img src="/files/dHchXKWzFU23igRRguGt" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}


# Debugging

Jigx Builder provides debugging capabilities in VS Code to identify and fix YAML, SQLite, and app problems and errors. Connect your phone using the debugging QR code to troubleshoot a solution directly from the Jigx App. Quickly locate and resolve issues preventing the application from functioning correctly or as intended. Examine your code, write and test SQL queries in the debug tool, trace program execution, and analyze error messages or unexpected behaviors to pinpoint the root cause of the problem. You can improve an application's reliability, performance, and functionality by debugging an application.

<figure><img src="/files/AyJxudJIHDUj4Gm4ZlIX" alt="Jigx Dev Tools"><figcaption><p>Jigx Dev Tools</p></figcaption></figure>

### Debugging capabilities

* Auto-sensing of code issues
* Detailed debug console
* Separate testing environment
* Hot reload to the connected device
* Live updates as code changes

### Connecting your device to Jigx Dev Tools

Enable Jigx Dev Tools by following these steps:

<figure><img src="/files/Zaga7cmF3L8M8gGaraRX" alt="Enabling Jigx Dev Tools" width="174"><figcaption><p>Enabling Jigx Dev Tools</p></figcaption></figure>

1. Open the solution you want to debug in Jigx Builder.
2. Click on the Jigx Builder icon in the activity bar.
3. In the sidebar, click the **+** next to CONNECT TO DEVICE. Enter your Jigx user name and password if prompted.
4. Now scan the **QR code** with your mobile device; you can open the QR code in full size if you having issues scanning the code. If you are using a branded app, see [Settings](/building-apps-with-jigx/jigx-builder-code-editor/settings) to ensure the QR code is generated for the correct app.
5. On your device, tap **Enable** on the Jigx Dev tools message.
6. The solution opens in the Jigx App.
7. Your device will show in Jigx Builder in the sidebar, with a data and functions node.
8. Ensure that the VS Code panel is open.

### Debugging Tools

There are four main tools in the Jigx Dev Tool set that specifically target debugging Jigx solutions. Each tool is described below:

#### Problems

Jigx validates the structure and values in the `.jigx` YAML files and shows the issues that you need to fix in the **Problems tab** of the Jigx Dev tools pane.

* The pane shows the .jigx file, the area in the YAML that has the issue, and a badge count of the number of issues in that file, for example, *all-orders.jigx datasources 2.*
* Drill down into the list of issues to see the short descriptions and the location.
* Clicking on the issue will take you to the line of YAML code in the file.
* Hover over the issue to see the popup that offers validation assistance and a quick-fix link if applicable.

<figure><img src="/files/9xFBq5Kvvn7fg4DFGVg3" alt="Problems pane"><figcaption><p>Problems pane</p></figcaption></figure>

#### Jigx console

Use the Jigx Console to debug your data and functions.

**Debugging data:**

<figure><img src="/files/bMRog5uZ1WCJkxqMsY71" alt="Debugging data in Jigx Console"><figcaption><p>Debugging data in Jigx Console</p></figcaption></figure>

1. [Connect your device to Jigx Dev Tools](/building-apps-with-jigx/jigx-builder-code-editor/debugging#connecting-your-device-to-jigx-dev-tools)
2. Under the **Device** node, click on the **data** node and select the SQLite data table.
3. Use the **▷** icon to run the SQL query in the Jigx Console.
4. You can run multiple SQLite queries and functions simultaneously, as each one opens in a new tab in the console panel.
5. The data table entries are listed.
6. Drill down into the data entries by clicking on an item in the list, the data object is displayed in the right-hand panel.
7. You can test your data by writing queries in the query editor and press the **Execute** button to test what is being returned from the SQL table. Once you have the correct SQL query, copy it to the jig or file where needed.
8. Click Format to auto-format your query ready for copying into your YAML code.

**Debugging functions:**

<figure><img src="/files/COERXKzfKpcLsp8W0Rm5" alt="Debugging functions in Jigx Console"><figcaption><p>Debugging functions in Jigx Console</p></figcaption></figure>

1. [Connect your device to Jigx Dev Tools](https://docs.jigx.com/debugging#p8neI)
2. Under the **Device** node, click on the **functions** node and select the function to debug.
3. The *function*.jigx file will open above the Jigx Console panel.
4. Use the **▷** icon to run the function in the Jigx Console.
5. You can run multiple functions and SQL queries simultaneously, as each one opens in a new tab in the console panel.
6. The function parameters are shown.
7. Click **Execute** to run the function and see the data in the console panel.
8. Drill down into the data entries that are returned by clicking on an item in the list, the data is displayed in the right-hand panel.
9. Click **Clear** in the right corner of the parameter panel to clear the parameters, to test your function parameteters add new values for the parameters and press the **Execute** button to test what data is being returned.
10. Required parameters are indicated with an \*.
11. The data type is shown next to the parameter, e.g., string, or array.

#### Jigx Logs

Jigx Logs records your interactions with the solution on the device when connected to the Jigx Dev Tools.

<figure><img src="/files/sg2MqLisIkXmaIYn8oX7" alt="Jigx logs"><figcaption><p>Jigx logs</p></figcaption></figure>

The following is logged:

* Datasource
* Error
* Execute
* Expression
* Navigate
* State
* Warning

**Ordering** - By default the oldest interaction is at the top, and the latest at the bottom. Order the list from latest at the top and the oldest at the bottom by clicking the up-arrow (**⋀**) in the Time column.

**Filtering** - You can filter by type or by jig, click on the filter icon next to Type or Jig. Select the options you want to display. The badges next to each option shows the number of entries in the log for that option. Once selected click the filter button.

**Searching** - All columns except Time can be searched using the search field.

**Detail** - Drill into each record by clicking on the item in the list. The full details for that item displays in the right hand panel.

**Clear the log** - Use the Clear logs icon to clear the log entries. As soon as you interact with the solution on the device while connected to Jigx Dev Tools the log will start populating again.

#### Jigx watcher

As you building out your solution in Jigx Builder you can monitor expressions and SQL queries to see the results as you navigate the app on the device.

<figure><img src="/files/ojfq2wWB8aPSDj1GAZ3N" alt="Jigx watcher"><figcaption><p>Jigx watcher</p></figcaption></figure>

1. [Connect your device to Jigx Dev Tools](https://docs.jigx.com/debugging#p8neI)
2. Open a `.jigx` file in Jigx Builder.
3. Locate the expression or SQL query in the YAML code.
4. Right click on the expression/SQL query and choose **Add to Jigx Watcher**. The Jigx Watcher opens in the panel below and shows the type, value and result. The result field is populated when you use the expression or SQL Query in a solution on your device.
5. Use the **Show logs** button to open the entry in Jigx Logs and view additional detail for the expression/ SQL query.
6. Use the **Remove** button to remove a single item. Click **Clear** in the right corner of the Jigx Watcher panel to clear all items in the list.


# YAML order

When it comes to ordering YAML elements, it's crucial to structure your Jigx file in a clear and logical manner. By doing so, you can ensure that your YAML data is easy to read, maintain, and troubleshoot, and sometimes, even the performance and order of execution are determined by the order.

Here are the best practices for ordering YAML elements in a jig file and the recommended structure for items in a section, for example, components.

{% hint style="info" %}
You won't necessarily use every element listed below in a single jig. You can modify the list to suit the elements you are including in your jig.
{% endhint %}

### Jig YAML order

* Title
* Description
* Type
* Icon
* Badge
* Inputs
* Placeholders
* onFocus/onRefresh
* Expressions
* header
* actions
* summary
* datasources
* children
* preview
* widgets

{% code title="YAML order" %}

```yaml
title: Name
description: Description of your Jig
type: jig.default
icon: hold-balloon
badge: empty

inputs:
  name: 
    type: string
    
placeholders:
  - title: No data to display

onFocus: 
  type: action.sync-entities
  options:
    provider: DATA_PROVIDER_LOCAL
    entities:
      - entity: default/department

onRefresh: 
  type: action.sync-entities
  options:
    provider: DATA_PROVIDER_DYNAMIC
    entities:
      - default/employee

expressions: 
  ExpressionName: =@ctx.datasources.employee-data.email
  
header:
  type: component.jig-header
  options:
    height: medium
    children:
      type: component.image
      options:
        source:
          uri: https://builder.jigx.com/assets/images/header.jpg

actions:
  - children:
      - type: action.go-back
        options:
          title: go back

summary:
  children:
    type: component.summary
    options: 
      layout: default
      
datasources:
  food: 
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_DYNAMIC
  
      entities:
        - default/employee
  
      query: SELECT id, '$.id', '$.name' FROM [default/employee] 

children:
  - type: component.avatar
    options:
      title: Jigx
      
preview:
  children:
    - type: component.web-view
      options:
        uri: https://jigx.com/
        
widgets:
  widget name: 
    type: widget.image
    options:
      source:
        uri: https://jigx.com/
```

{% endcode %}

### Order of items in a section

Order of items within a section, for example when defining a component we should aim to standardise as follows:

* Type is always the first thing to be defined so that we know what we are dealing with
* Meta elements for the list (data)
* Item definition
* Title
* Subtitle
* Description
* Left element , Right element , Label
* action
* OnPress
* Swipeable

{% code title="section-order" %}

```yaml
children:
  - type: component.list
    options:
      data: =@ctx.datasources.loads
      item:
        type: component.list-item
        options:
          title: Altitude
          subtitle: =@ctx.current.item.altitude
          description: =@ctx.current.item.altitude
          leftElement:
            element: avatar
            text: =$string(@ctx.current.item.loadNumber)
            uri: ''
          rightElement:
            element: value
            text: =$substring(@ctx.current.item.loadTime,0,5)
          label:
            title: =@ctx.current.item.loadStatus
            color: color1
            - when: =@ctx.current.item.loadStatus = 'Pending'
            color: color4
            - when: =@ctx.current.item.loadStatus= 'Accepted'
            color: color3
            - when: =@ctx.current.item.loadStatus = 'Completed'
            color: color2
            onPress:
            type: action.go-to
            options:
            linkTo: form-load
            parameters:
            loadid: =@ctx.current.item.id
            swipeable:
            right:
            - label: Delete
            icon: delete-2
            color: negative
              onPress:
              type: action.execute-entity
              options:
              provider: DATA_PROVIDER_DYNAMIC
              entity: default/load
                  method: delete
            data:
            id: =@ctx.current.item.id
```

{% endcode %}


# Tips, tricks and shortcuts

Discover shortcuts and tricks that boost efficiency and maximize your output.

## Jigx Builder shortcuts

<table><thead><tr><th width="235.0390625">Shortcuts</th><th width="233.90625">Mac</th><th>Windows</th></tr></thead><tbody><tr><td>Publish all files in Jigx solution</td><td>⌘R⌘R</td><td>Alt+R Alt+R</td></tr><tr><td>Publishing an individual file is useful if multiple developers work on the same solution. You only want to publish your changes. Note index.jigx, is a shared file that people all work on, so the last one updated on the server gets published.</td><td>⌘R⌘F</td><td>Alt+R Alt+F</td></tr><tr><td>Invoke IntelliSense</td><td>Ctrl+space</td><td>Ctrl+space</td></tr><tr><td>Quick Fix</td><td>⌘+.</td><td>Ctrl+.</td></tr><tr><td></td><td>F12 or ⌘+click</td><td>F12 or Ctrl+click</td></tr><tr><td></td><td>shift+F12 F12</td><td>shift+F12 F12</td></tr><tr><td>The swagger parser function</td><td>⌘ + shift + p <code>Generate Jigx Functions</code></td><td>Ctrl + shift + p <code>Generate Jigx Functions</code></td></tr></tbody></table>

## What colors indicate in Jigx Builder

<table><thead><tr><th width="104.65625">Color</th><th>Description</th></tr></thead><tbody><tr><td>white</td><td>The file is issue-free. If connected to a Git repository, the file is committed.</td></tr><tr><td><mark style="color:red;">red</mark></td><td>The file has validation issues/errors/deprecated properties that must be fixed. The number of issues is shown by a red number on the right of the file name in the sidebar.</td></tr><tr><td><mark style="color:yellow;">yellow</mark></td><td>This means the file is connected to a Git repository and is modified; the letter M displays on the right of the file name in the sidebar. YAML is squiggled in yellow to show deprecated properties, hover over the YAML to see the expected property.</td></tr><tr><td><mark style="color:green;">green</mark></td><td>Indicates a new file has been created but not committed to the Git repository yet.</td></tr><tr><td><mark style="color:blue;">blue</mark></td><td>Indicates the active screen on the mobile device that you are debugging in the builder using Jigx Dev Tools.</td></tr></tbody></table>


# Data

Data is the most crucial aspect of developing a mobile app; leveraging this data intelligently can transform a good app into a great one, harnessing the power of data within mobile applications drives engagement, personalization, and functionality.

This section covers data concepts, lifecycles, syncing and loading data, and data providers integrating with other systems to expose data.

### Concepts

1. [Data Lifecycles in Jigx](/building-apps-with-jigx/data/data-lifecycles-in-jigx) explains when data is loaded when it is cached and what triggers loading from cache vs loading from tables.
2. [Syncing Remote and Loading Local Data](/building-apps-with-jigx/data/syncing-remote-and-loading-local-data) explains how to sync data from the cloud and how to display it on a jig. It also explains the difference between coordinating local and remote updates and their effect on a user's experience.
3. [When To Load Data](/building-apps-with-jigx/data/when-to-load-data) is probably one of the most important topics when you design your solution. The timing of this will determine how robust the solution will work in offline environments and how loading data just in time can affect the user's experience.
4. [Offline Solutions](/building-apps-with-jigx/data/offline-solutions) access to data while a device is offline, for example, in airplane mode or without an internet signal. Once the device is back online, how is the data synced.

### Data Providers

1. [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data) is a Jigx-specific data source that automatically syncs data in real time between devices. It is a great platform for disposable data, defining data that is not already available in existing systems, and how to sync data in real time between users and their devices, regardless of where it is updated.
2. [Microsoft Azure SQL](https://docs.jigx.com/examples/readme/data-providers/microsoft-azure-sql) provides an overview of working with Microsoft Azure SQL and a guide on configuring secure access and Jigx functions to read, update and delete data with queries and stored procedures.
3. [Microsoft OneDrive](/building-apps-with-jigx/data/data-providers/microsoft-onedrive) integration allows you to create, updated, and delete files in OneDrive. In a solution, you can list, and download files from OneDrive.
4. [REST](/building-apps-with-jigx/data/data-providers/rest) provides an overview of working with REST services, including how data is returned, transformed, and used in the solution. This section explains selective data updates and how to configure security and more complex REST calls.
5. [Salesforce](/building-apps-with-jigx/data/data-providers/salesforce) provider allows you to integrate with your Salesforce instance, with access to share data about sales, customers
6. LOCAL - Stores data locally inside your solution until the app closes.
7. SOAP - works with APIs based on SOAP protocols.

### Datasources

[Datasources](/building-apps-with-jigx/data/datasources) are sets of data referenced when building solutions in Jigx. These are:

1. [Global](/building-apps-with-jigx/data/datasources) - the data set is defined once and is available throughout your solution to be reused in multiple jigs.
2. [Local](/building-apps-with-jigx/data/datasources) - the data sets are available inside the individual jig.

### Entities

Entities refer to tables in data providers or datasources where data is saved, created, updated, read, and deleted. [Actions](/building-apps-with-jigx/ui/actions) provide the ability to execute the CRUD methods, sync data, and refresh data on individual rows [execute-entity](https://docs.jigx.com/examples/readme/actions/execute-entity) or multiple rows [execute-entities](https://docs.jigx.com/examples/readme/actions/execute-entities).


# Data lifecycles in Jigx

Understanding the data lifecycle in a Jigx solution is essential to help you plan your data calls and when and why to make them. The diagrams below describe when and why data is loaded when a jig is accessed.

### Navigating to a Jig for the first time

<figure><img src="/files/mvohqNoc3olt97VERpCy" alt=""><figcaption></figcaption></figure>

### Navigating to the same jig a second time

<figure><img src="/files/QN9LhG7YhvKPIlhLmLRn" alt=""><figcaption></figcaption></figure>

### Editing the record

<figure><img src="/files/v8z0yRGKnxM8ddxTXZ0I" alt=""><figcaption></figcaption></figure>

### Navigating back to view the edited record

<figure><img src="/files/QzSnCyUjsjwud275wI3I" alt=""><figcaption></figcaption></figure>


# Syncing remote and loading local Data

<figure><img src="/files/0U0G9as7lCIms6egE4AQ" alt="" width="563"><figcaption></figcaption></figure>

Key:

1. **Sync data from the cloud** Use a `sync-entities` action to fetch data from the cloud and store it in the local SQLite database. Use the `onLoad`, `onFocus`, `onRefresh`, or any other event where actions are defined.
2. **Load data from SQLite to use on a jig** Use the `DATA_PROVIDER_LOCAL` in the datasource defined in the jig or a global datasource to execute an SQLite query.
3. **Save data to SQLite ONLY** To save data locally only and not sync to the cloud, use an `execute-entity` action with the `DATA_PROVIDER_LOCAL`.
4. **Save data to SQLite and sync data to the cloud** Update the local SQLite and sync to the cloud in a single action to ensure high-performing user experiences without lag. Use `execute-entity` or `execute-entities` actions with `DATA_PROVIDER_REST` or `DATA_PROVIDER_SQL`. Specify the function call to make, the local entity/table to update, and the method to perform on the local table. If the method is an update, delete, or save, specify the record's ID.
5. **Save data to the cloud ONLY** Use `execute-entity` or `execute-entities` actions with `DATA_PROVIDER_REST` or `DATA_PROVIDER_SQL`. Set the method to functionCall and specify the function to be called. The local tables will not be updated; you must sync the data from the cloud before it is available to display on a jig.

{% hint style="info" %}
Dynamic Data automatically syncs its data with the cloud when server-side or device-side updates are made to the tables, using `DATA_PROVIDER_DYNAMIC`.&#x20;
{% endhint %}

## Using sync-entities action

1. Use the `sync-entities` action to sync data from the remote data store (REST and SQL) to the local SQLite data provider. Syncing data locally results in high performance with minimal lag and ensures that all data is available in the app when the device is offline.
2. Best practice is to configure a global action, the `sync-entities` action, with the REST or SQL data provider, allowing reuse throughout the solution.
3. Add the global sync action to the `onFocus` and `onLoad` events in the index.jigx file ensures data is synced to the local data provider as soon as the app loads or is focused on the device.
4. Add the global sync action to the `onRefresh` or `onFocus` events in a jig when data is changed, for example, on the list of customers, this ensures that when a new customer is created, the list is updated immediately when navigating to it or refreshing the list with a downward swipe.

## Using Execute-entity/entities action

There are two options when using the `execute-entity` and `execute-entities` actions with remote data, such as REST or SQL.

1. **To update BOTH the local SQLite table and the remote data store (REST and SQL)**. To update the local table, specify CREATE, UPDATE, or DELETE methods in the `method` property of the data provider, then specify the function to use in the `function` property, and under `parameters` specify the exact data to be updated in the remote data store (REST/SQL). Under `data` specify the exact data to be updated in the local SQLite table. After execution, a tempId is created, and then synced to the local table.

<figure><img src="/files/wuCVSREIPPaRAPdxEcBy" alt="Update local and REST providers"><figcaption><p>Update local and REST providers</p></figcaption></figure>

1. **To ONLY update the remote data store (REST and SQL)**. To update the remote data store specify `functionCall` in the `method` property. Then specify the function to be called in the `function` property and under `parameters` specify the exact data to be updated. Note that the data will not be visible on the jig until a `sync-entities` action is executed.

<figure><img src="/files/fdqrjX2iYBgKorWVQcrK" alt="Only update REST Service"><figcaption><p>Only update REST Service</p></figcaption></figure>

### Consideration

* Using the `save` method in `execute-entity/entities` action will perform an upsert in the local SQLite table.
* Dealing with offline remote data is fundamental to ensuring data synchronization and consistency between the mobile app and the remote data source, allowing users to continue using the app and performing actions without interruption. [Offline remote data handling](/building-apps-with-jigx/data/offline-remote-data-handling) explains how to configure solutions to deal with data when the device is offline.

## Using local data provider in a jig's datasources

1. Once the data has been synced using the `sync-entities` action the data is available in the local data provider.
2. Reference the local data provider in the jig's `datasource` property to define the data required in the jig.
3. Write a SQLite query to define the exact data required.
4. Use IntelliSence and expressions to reference the specific datasource values to use in each component, such as `data: =@ctx.datasources.customers`

<figure><img src="/files/RXPIwc1CZmrcjnTqoNda" alt="Local data provider"><figcaption><p>Local data provider</p></figcaption></figure>


# When to load data

### Sync data when the solution loads or gets focus

**Benefits:**

* The app is robust for offline scenarios.
* Jig rendering and interaction are very fast.
* There are only 2 distinct cloud interaction cycles in the example below: once when all data is synced and once when an update is sent to the cloud.

This is the recommended pattern when designing a Jigx solution.

**Drawbacks:**

* Initial app load time is slightly longer and heavier.
* Doesn’t work for all scenarios where the app depends on up-to-date data from the cloud when a jig is displayed.

<figure><img src="/files/pgvB7DHG7TAa6fP3Z9sd" alt="Solution data sync"><figcaption><p>Solution data sync</p></figcaption></figure>

### Sync just in time when a jig is used

**Benefits:**

* Initial load is lighter.
* Only the data needed per screen is synced to the device.

Elements of this approach can be combined with the recommended approach above.

**Drawbacks:**

* The solution cannot robustly go offline.
* The data might not be available for the jig when the app is offline.
* The user might experience a slower performance of jigs because of just-in-time cloud operations.
* There are 9 (8 reads and one update) cloud operations throughout the UI cycles at 5 different distinct stages.

<figure><img src="/files/eML3bWic2Dh4wROutmsL" alt="Sync data just in time"><figcaption><p>Sync data just in time</p></figcaption></figure>

### Dynamically syncing data

When building a solution, the number of entities to sync and the parameters for each are not always known; for example, when syncing the attachments for a message, there can be zero, one or more attachments, or files/documents stored in a OneDrive directory. It is necessary to dynamically specify a list of the entities and function+parameters to return from the database using an expression. See [Dynamically sync multiple entities](https://docs.jigx.com/examples/readme/actions/sync-entities#dynamically-sync-multiple-entities) for more information.


# Offline Solutions

The Jigx platform syncs all data to a local SQL database from where it is used in [Expressions](/building-apps-with-jigx/logic/expressions) and user interfaces ([jigs](/building-apps-with-jigx/ui/jigs-_screens_)). Once the data syncs, it is available without the need for an internet connection.

Data is synced to the device from one of five supported locations:

* [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data): A built-in Jigx data source that automatically syncs data in real time between devices and the cloud.
* [REST](/building-apps-with-jigx/data/data-providers/rest) Services: REST-based web services that return data in JSON format.
* [Microsoft Azure SQL](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql): Either Azure SQL Database or Microsoft SQL Server.
* [Salesforce](/building-apps-with-jigx/data/data-providers/salesforce): A Jigx provider for syncing Salesforce.com data.
* SOAP: A data provider for syncing data from SOAP-based services such as SAP.

When the app is online, data is synced from the cloud to the local SQLite database, from where it is accessed using data sources in jigs.

The command is put on a [queue](/building-apps-with-jigx/data/offline-remote-data-handling) when data is saved to the cloud. The queue is immediately executed when the device is online, and the data is sent to the applicable cloud service. When the device is offline, the cloud commands continue to be added to the queue until the device goes online.

The best practice for a robust offline solution is to sync as much data as is needed as early as possible in the usage cycle. This is typically when the solution launches. After that, the solution design should ensure the latest data is synced to the device to avoid just-in-time data loading.

Refer to the [Data lifecycles in Jigx](/building-apps-with-jigx/data/data-lifecycles-in-jigx) and [Syncing remote and loading local Data](/building-apps-with-jigx/data/syncing-remote-and-loading-local-data) sections to understand how to build robust solutions that go offline.

{% hint style="warning" %}
When a Jigx solution switches from offline to online, the queue is processed on a first-in-first-out basis. Jigx does not do conflict resolution. It assumes that the cloud-based system will handle its own data integrity.
{% endhint %}


# Offline remote data handling

Dealing with offline remote data is fundamental to ensuring data synchronization and consistency between the mobile app and the remote data source, allowing users to continue using the app and performing actions without interruption. Queue operations provide the functionality needed when the device regains network connectivity and manages a sequence of elements in a specific order. The commands in the queue can be manipulated to reduce the number of calls to the remote data store or Dynamic Data.

## What happens to data when you are offline?

1. **Data Capture Offline**:
   * When the mobile app is offline, any actions that require remote data interaction, such as submitting a form, uploading a file, or syncing data, are queued.
   * Each action is captured and stored in a queue in the local data provider on the device.
2. **Network Monitoring**:
   * The app monitors the network status. It triggers the dequeuing process when it detects that the device has regained connectivity.
3. **Dequeue and Sync**:
   * The app starts processing the commands in the queue. It dequeues each command and attempts to send it to the remote server.
   * If the operation is successful, the app removes the command from the queue.

## How to configure the queue

In the [execute-entity](https://docs.jigx.com/examples/readme/actions/execute-entity), [execute-entities](https://docs.jigx.com/examples/readme/actions/execute-entities) , and [submit-form](https://docs.jigx.com/examples/readme/actions/submit-form) actions, the `queueOperation` property is configured to determine how the record must be handled in the queue when the device is offline. There are two configuration options:

<table><thead><tr><th width="137.48046875">Property</th><th>description</th></tr></thead><tbody><tr><td><code>replace</code></td><td><p>All queued commands for the specified record and method type are replaced with the current action. For example, a record is created and then updated a few times. Using replace for the update method results in only two commands in the queue for the record: create and update. If replace is not used, there will be a command for every action: create, update, update, update. Replace is recommended for backend systems with rate limits. The <code>queueOperation: replace</code> requires an <code>id</code> (must be in lowercase). This is configured in the: </p><ul><li><code>Parameter</code> of the <code>execute-entity</code> action with an <code>id</code> configured in the <code>parameters</code> of the function file.</li><li><code>data</code> property in the <code>execute-entity</code> action.</li></ul></td></tr><tr><td><code>add</code></td><td>All commands are added to the queue. When the <code>queueOperation</code> property is omitted, the default is <code>add</code>.</td></tr></tbody></table>

{% tabs %}
{% tab title="execute-entity-replace (REST)" %}

```yaml
actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          # Use replace to ensure you only have one update on the queue related
          # to a record. Not adding the replace will not break the solution but
          # will help to avoid chattiness and scenarios where backends have 
          # rate limits.
          queueOperation: replace
          function: rest-update-customer
          # Parameters to update in the remote server.
          parameters:
            # id is a required property for the replace queue
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            email: =$lowercase(@ctx.components.email.state.value)
          # Data records to update in the local SQLite table. 
          data: 
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            email: =$lowercase(@ctx.components.email.state.value)
```

{% endtab %}

{% tab title="execute-entity-add (REST)" %}

```yaml
actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          # Using add will add a command for every update to the queue related
          # to a record. Using add can be cumbersome and costly for scenarios
          # where backends have rate limits.
          queueOperation: add
          goBack: previous
          function: rest-update-customer
          # Parameters to update in the remote server.
          parameters:
            # id is a required property for the replace queue
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            email: =$lowercase(@ctx.components.email.state.value)
         # Data records to update in the local SQLite table. 
          data: 
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            email: =$lowercase(@ctx.components.email.state.value)   
```

{% endtab %}

{% tab title="execute-entity-replace (DD)" %}

```yaml
actions:
 - children:
    - type: action.execute-entity
      options:
        title: Create Record
        provider: DATA_PROVIDER_DYNAMIC
        entity: default/customers
        method: update
        # Use replace to ensure you only have one update on the queue related
        # to a record. Not adding the replace will not break the solution but
        # will help to avoid chattiness and scenarios where backends have 
        # rate limits.
        queueOperation: replace
        # Data records to update in Dynamic data tables. 
        data:
          # id is a required property for the replace queue.
          id: =@ctx.jig.inputs.customer.id
          firstName: =@ctx.components.firstName.state.value
          lastName: =@ctx.components.lastName.state.value
          companyName: =@ctx.components.companyName.state.value
          address: =@ctx.components.address.state.value
          city: =@ctx.components.city.state.value
          email: =$lowercase(@ctx.components.email.state.value)
```

{% endtab %}

{% tab title="execute-entity-add (DD)" %}

```yaml
actions:
 - children:
    - type: action.execute-entity
      options:
        title: Create Record
        provider: DATA_PROVIDER_DYNAMIC
        entity: default/customers
        method: update
        # Using add will add a command for every update to the queue related
        # to a record. 
        queueOperation: add
        # Data records to update in the Dynamic Data table.
        data:
          id: =@ctx.jig.inputs.customer.id
          firstName: =@ctx.components.firstName.state.value
          lastName: =@ctx.components.lastName.state.value
          companyName: =@ctx.components.companyName.state.value
          address: =@ctx.components.address.state.value
          city: =@ctx.components.city.state.value
          email: =$lowercase(@ctx.components.email.state.value)
```

{% endtab %}
{% endtabs %}

Examples of configuring the required `id` property when using `queueOperation: replace`.

{% tabs %}
{% tab title="execute-entity-data-id" %}

```yaml
# This action is configured with a replace queue operation and the id is 
# specified, in the data property. The id comes from an input.
actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          function: rest-update-customer
          # Replace current update on the queue.
          queueOperation: replace
          # id is required for the replace operation.
          parameters:
            id: =@ctx.jig.inputs.customer.id 
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
          # id is required for the replace operation.
          data:
            id: =@ctx.jig.inputs.customer.id  
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
```

{% endtab %}

{% tab title="execute-entity-parameters-id" %}

```yaml
# This action is configured with a replace queue operation and the id is specified,
# in the paramaters property. 
# The id is specified in the function file under parameters.
actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          # Use replace to ensure you only have one update on the queue related 
          # to a record.
          # Not adding the replace will not break the solution but will help 
          # to avoid chattiness and scenarios where backends have rate limits.
          queueOperation: replace
          goBack: previous
          function: rest-update-customer
          parameters:
            # id is a required property for the replace queue
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            email: =$lowercase(@ctx.components.email.state.value)
          data:
            # id is a required property for the replace queue
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            email: =$lowercase(@ctx.components.email.state.value)   
```

{% endtab %}
{% endtabs %}

## How to clear the queue

For scenarios where operations on a record must be treated as draft and all queued commands must be removed without impacting the local record, use the `clear-queue` action, and specify the `id` of the record and a `title` for the action. See [clear all commands in the queue](#clear-commands-in-the-queue-for-a-record) example.

{% code title="clear-queue-action" %}

```yaml
actions:
  - children:
      - type: action.clear-queue
        options:
          title: Remove record from Queue
          id: =@ctx.datasources.region.id
```

{% endcode %}

## Queue handling for delete methods

When using the `replace` property with a `delete` method, all commands on the queue for the specified record are removed. The delete method will still delete the local entity record as expected, for example while offline a record is created with a tempId, then updated, and then deleted with a `queueOperations: replace`, the commands for that record are removed from the queue and local entity will also be deleted. This avoids the need for the full cycle of calls to be sent to the backend (create, update, delete) if the end result is that the record is deleted.

If the record to be deleted has a valid Id then the `queueOperations: add` is used to add the record to the queue, when the device is back online the queue is processed and the record is deleted using the function.

If you want to cater for both tempId and a valid Id records when offline in one `queueOperation` configuration use the following expression `=$isTempId(@ctx.current.item.id) ? replace:add`

{% hint style="danger" %}
**Note** that `queueOperation: replace` with the `delete` method does not behave the same for Dynamic Data as it does for REST. Dynamic Data does not generate a tempId, so the `$isTempId()` check is not applicable. When working with Dynamic Data, you must use `queueOperation: add` for delete operations, as `replace` clears the queue without executing the delete method.
{% endhint %}

{% tabs %}
{% tab title="execute-entity-delete (REST)" %}

```yaml
actions:
  - children:
      - type: action.execute-entity
        options:
          title: Delete Record
          provider: DATA_PROVIDER_REST
          entity: customers
          method: delete
          # For delete use an expression to evaluate if there is a valid or
          # tempId. If the record has a tempId it will remove all operations 
          # related to the record from the queue. If it is a valid Id the record
          # will use the add and place it on the queue, which will delete the 
          # record from the remote data store using the function.
          queueOperation: =$isTempId(@ctx.current.item.id) ? replace:add
          function: rest-delete-customer
          parameters:
            custId: =$number(@ctx.current.item.id)
          data:
            id: =@ctx.current.item.id
```

{% endtab %}

{% tab title="execute-entity-delete (Dynamic Data)" %}

```yaml
actions:
 - children:
    - type: action.execute-entity
      options:
        title: Create Record
        provider: DATA_PROVIDER_DYNAMIC
        entity: default/customers
        method: delete
        # The record id will be used to add it on the queue, which will delete the 
        # record from the Dynamic Data. 
        # Do not use replace as the queue is cleared without executing the delete method.
        queueOperation: add
        data:
          id: =@ctx.current.item.id
```

{% endtab %}
{% endtabs %}

## Handling TempIds

All tempIds for a record are replaced in all other queued commands if a valid id is returned. If you use a record's id in another record while offline and a valid id is returned back when the device is back online, Jigx updates the tempId used in all the other records that used it with the valid id. This makes for smoother integration with backend systems as the ids will match up. This is applicable to remote stores, but not to Dynamic Data which does not generate tempIds. See [working with REST ids](/building-apps-with-jigx/data/data-providers/rest/rest-best-practice) for more information on returning the id.

## Dynamic Data change tracking & queuing

What you need to know about how Dynamic Data table changes are tracked and queued:

* Applies to Dynamic Data tables defined as `default/table name`&#x20;
* All changes made to the tables are automatically queued
* Purpose is to facilitate offline sync / cloud sync support
* Supported operations are:
  * CRUD operations
  * SQL execution
  * Find & replace
* Behavior is automatic and consistent
* Use `queueOperations` with `add` or `replace`

#### Behavior overview

The change tracking and queuing is executed in the following way:&#x20;

Update Dynamic Data table **→** Temp table created **→** Changes detected **→** Batch queued **→** Temp cleaned up

## Examples and code snippets

{% hint style="info" %}
See the [Dynamic data examples](https://docs.jigx.com/examples/readme/data-providers/dynamic-data) for examples demonstrating how to use `queueOperation` with the `execute-entity` action when working with a Dynamic Data database.
{% endhint %}

### Execute-entity with queueOperation (replace)

In this example, when the device is offline and a customer record is created and then updated multiple times, only one create and one update command is queued. When the device is back online the queue is cleared. The remote data store returns an id that we can use to map back to the record locally in the `outputTransform` of the function (rest-create-customer). `queueOperation` is not required for the create of the customer because once the device comes online, the record will be created, and the id from the remote data store will be returned and any records with the same tempId will be updated with the returning id and will update the correct record. The `queueOperation: replace` is rather used in the update-customer jig.

<figure><img src="/files/pHM0wWOwldpYdKZYfpqx" alt="" width="169"><figcaption></figcaption></figure>

{% tabs %}
{% tab title="new-customer.jigx" %}

```yaml
title: New Customer
type: jig.default

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

onFocus:
  type: action.reset-state
  options:
    state: =@ctx.jig.components.customerForm.state.data

datasources:
  region:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: us-states
      query: |
        SELECT 
          uss.id AS id, 
          json_extract(uss.data, '$.state') AS state, 
          json_extract(uss.data, '$.abbreviation') AS abbreviation,
          json_extract(uss.data, '$.stateCapital') AS stateCapital,
          json_extract(uss.data, '$.region') AS region,
          json_extract(uss.data, '$.flag') AS flag
        FROM 
          [us-states] AS uss
        WHERE  
          json_extract(uss.data, '$.abbreviation') = @selectedState

      queryParameters:
        selectedState: =@ctx.components.usState.state.value

  customerType:
    type: datasource.static
    options:
      data:
        - id: 1
          type: New
          value: new
        - id: 2
          type: Gold
          value: Gold
        - id: 3
          type: Silver
          value: Silver
children:
  - type: component.form
    instanceId: customerForm
    options:
      isDiscardChangesAlertEnabled: false
      children:
        - type: component.text-field
          instanceId: companyName
          options:
            label: Company Name
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
        - type: component.text-field
          instanceId: jobTitle
          options:
            label: Job Title
        - type: component.text-field
          instanceId: email
          options:
            label: Email
        - type: component.text-field
          instanceId: phone1
          options:
            label: Mobile
        - type: component.text-field
          instanceId: web
          options:
            label: Web
        - type: component.text-field
          instanceId: address
          options:
            label: Street
        - type: component.text-field
          instanceId: city
          options:
            label: City
        - type: component.field-row
          options:
            children:
              - type: component.dropdown
                instanceId: usState
                options:
                  label: State
                  data: =@ctx.datasources.us-states
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.state
                      value: =@ctx.current.item.abbreviation
                      leftElement:
                        element: avatar
                        text: =@ctx.current.item.abbreviation
                        uri: =@ctx.current.item.flag
              - type: component.text-field
                instanceId: zip
                options:
                  label: ZIP
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: region
                options:
                  label: Region
                  value: =@ctx.datasources.region.region
              - type: component.dropdown
                instanceId: customerType
                options:
                  label: Customer Type
                  data: =@ctx.datasources.customerType
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.type
                      value: =@ctx.current.item.value

actions:
  - children:
      - type: action.execute-entity
        options:
          title: Create Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: create
          # In this scenario, the backend system returns an Id that we can use
          # to map back to the record locally in the Output transform of the 
          # function (rest-create-customer). You don’t need to use
          # queueOperation in this scenario. Once the device goes online,
          # the record will be created, and the id from the backend will come
          # back. Any records with the same tempId will be updated with
          # the returning id and will update the correct record.
          function: rest-create-customer
          parameters:
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.usState.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
         data:
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.usState.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value   
```

{% endtab %}

{% tab title="update-customer.jigx" %}

```yaml
title: Update Customer
type: jig.default

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

datasources:
  region:
    type: datasource.static
    options:
      data:
        - id: 1
          region: US Central
        - id: 2
          region: US East
        - id: 3
          region: US West
  customerType:
    type: datasource.static
    options:
      data:
        - id: 1
          type: New
          value:
        - id: 2
          type: Gold
          value: Gold
        - id: 3
          type: Silver
          value: Silver
  customers:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: customers
      query: |
        SELECT 
          cus.id AS id, 
          json_extract(cus.data, '$.firstName') AS firstName, 
          json_extract(cus.data, '$.lastName') AS lastName,
          json_extract(cus.data, '$.companyName') AS companyName,
          json_extract(cus.data, '$.address') AS address,
          json_extract(cus.data, '$.city') AS city,
          json_extract(cus.data, '$.state') AS state,
          json_extract(cus.data, '$.zip') AS zip,
          json_extract(cus.data, '$.phone1') AS phone1,
          json_extract(cus.data, '$.phone2') AS phone2,
          json_extract(cus.data, '$.email') AS email,
          json_extract(cus.data, '$.web') AS web,
          json_extract(cus.data, '$.customerType') AS customerType,
          json_extract(cus.data, '$.jobTitle') AS jobTitle,
          json_extract(cus.data, '$.region') AS region
        FROM 
          [customers] AS cus
        WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.customer.id
      isDocument: true

children:
  - type: component.form
    instanceId: customer
    options:
      isDiscardChangesAlertEnabled: false
      children:
        - type: component.text-field
          instanceId: companyName
          options:
            label: Company Name
            initialValue: =@ctx.datasources.customers.companyName
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
                  initialValue: =@ctx.datasources.customers.firstName
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
                  initialValue: =@ctx.datasources.customers.lastName
        - type: component.text-field
          instanceId: jobTitle
          options:
            label: Job Title
            initialValue: =@ctx.datasources.customers.jobTitle
        - type: component.text-field
          instanceId: email
          options:
            label: Email
            initialValue: =@ctx.datasources.customers.email
        - type: component.text-field
          instanceId: phone1
          options:
            label: Mobile
            initialValue: =@ctx.datasources.customers.phone1
        - type: component.text-field
          instanceId: web
          options:
            label: Web
            initialValue: =@ctx.datasources.customers.web
        - type: component.text-field
          instanceId: address
          options:
            label: Street
            initialValue: =@ctx.datasources.customers.address
        - type: component.text-field
          instanceId: city
          options:
            label: City
            initialValue: =@ctx.datasources.customers.city
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: state
                options:
                  label: State
                  initialValue: =@ctx.datasources.customers.state
              - type: component.text-field
                instanceId: zip
                options:
                  label: ZIP
                  initialValue: =@ctx.datasources.customers.zip
        - type: component.field-row
          options:
            children:
              - type: component.dropdown
                instanceId: region
                options:
                  label: Region
                  data: =@ctx.datasources.region
                  initialValue: =@ctx.datasources.customers.region
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.region
                      value: =@ctx.current.item.region
              - type: component.dropdown
                instanceId: customerType
                options:
                  label: Customer Type
                  data: =@ctx.datasources.customerType
                  initialValue: =@ctx.datasources.customers.customerType
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.type
                      value: =@ctx.current.item.value

actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          # Use replace to ensure you only have one update on the queue related
          # to a record. Not doing this will not break the solution but will
          # help to avoid chattiness and scenarios where backends have rate limits
          queueOperation: replace
          goBack: previous
          function: rest-update-customer
          parameters:
            # id is a required parameter when using the queueOperation: replace
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
          data:
            # id is a required when using the queueOperation: replace
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value    
```

{% endtab %}

{% tab title="rest-create-customer.jigx (function)" %}

```yaml
provider: DATA_PROVIDER_REST
# Create new record in the backend
method: POST 
# Use your REST service URL
url: https://[your_rest_service]/api/customers 
# Direct the function call to use local execution between the mobile device
# and the REST service.
useLocalCall: true 

parameters:
  accessToken:
    location: header
    required: true
    type: string
  # Use manage.jigx.com to define credentials for your solution.
  firstName:
    value: service.oauth 
    type: string
    location: body
    required: true
  lastName:
    type: string
    location: body
    required: true
  companyName:
    type: string
    location: body
    required: true
  address:
    type: string
    location: body
    required: false
  city:
    type: string
    location: body
    required: false
  state:
    type: string
    location: body
    required: false
  zip:
    type: string
    location: body
    required: false
  phone1:
    type: string
    location: body
    required: false
  phone2:
    type: string
    location: body
    required: false
  email:
    type: string
    location: body
    required: false
  web:
    type: string
    location: body
    required: false
  region:
    type: string
    location: body
    required: false
  customerType:
    type: string
    location: body
    required: false
  jobTitle:
    type: string
    location: body
    required: false

inputTransform: |
  {
    "firstName": firstName,
    "lastName": lastName,
    "companyName": companyName,
    "address": address,
    "city": city,
    "state": state, 
    "zip": zip,
    "phone1": phone1,
    "phone2": phone2,
    "email": email,
    "web": web,
    "region": region,
    "customerType": customerType,
    "jobTitle": jobTitle
  }

# In this scenario, the backend system returns an ID that we can use to map
# back to the record locally in the Output transform of the function 
# (rest-create-customer). You don’t need to use queueOperation in this scenario
# for Create. Once the device goes online, the record will be created, and the
# ID from the backend will come back. Any records with the same tempId will be
# updated with the returning ID and will update the correct record.
outputTransform: |
  {
    "id": custId,
    "status": status
  }
```

{% endtab %}

{% tab title="rest-update-customer.jigx (function)" %}

```yaml
provider: DATA_PROVIDER_REST
method: PUT
#Use your REST service URL
url: https://[your_rest_service]/api/customers 
# Direct the function call to use local execution between the mobile device and the 
# REST service.
useLocalCall: true 
format: text

parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution.
    value: service.oauth 
 # id is a required property when using the queueOperation: replace.
 id:
    type: int
    location: body
    required: true
  firstName:
    type: string
    location: body
    required: true
  lastName:
    type: string
    location: body
    required: true
  companyName:
    type: string
    location: body
    required: true
  address:
    type: string
    location: body
    required: false
  city:
    type: string
    location: body
    required: false
  state:
    type: string
    location: body
    required: false
  zip:
    type: string
    location: body
    required: false
  phone1:
    type: string
    location: body
    required: false
  phone2:
    type: string
    location: body
    required: false
  email:
    type: string
    location: body
    required: false
  web:
    type: string
    location: body
    required: false
  region:
    type: string
    location: body
    required: false
  customerType:
    type: string
    location: body
    required: false
  jobTitle:
    type: string
    location: body
    required: false

inputTransform: |
  {
    "custId": id,
    "firstName": firstName,
    "lastName": lastName,
    "companyName": companyName,
    "address": address,
    "city": city,
    "state": state,
    "zip": zip,
    "phone1": phone1,
    "phone2": phone2,
    "email": email,
    "web": web,
    "region": region,
    "customerType": customerType,
    "jobTitle": jobTitle
  }
```

{% endtab %}
{% endtabs %}

### Execute-entity with queueOperation (add)

In this example, when the device is offline and a customer record is updated multiple times , all the update commands are queued. When the device is back online the queue is cleared.

{% tabs %}
{% tab title="update-customer.jigx (REST)" %}

```yaml
title: Update Customer
type: jig.default

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

datasources:
  region:
    type: datasource.static
    options:
      data:
        - id: 1
          region: US Central
        - id: 2
          region: US East
        - id: 3
          region: US West
  customerType:
    type: datasource.static
    options:
      data:
        - id: 1
          type: New
          value:
        - id: 2
          type: Gold
          value: Gold
        - id: 3
          type: Silver
          value: Silver
  customers:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: customers
      query: |
        SELECT 
          cus.id AS id, 
          json_extract(cus.data, '$.firstName') AS firstName, 
          json_extract(cus.data, '$.lastName') AS lastName,
          json_extract(cus.data, '$.companyName') AS companyName,
          json_extract(cus.data, '$.address') AS address,
          json_extract(cus.data, '$.city') AS city,
          json_extract(cus.data, '$.state') AS state,
          json_extract(cus.data, '$.zip') AS zip,
          json_extract(cus.data, '$.phone1') AS phone1,
          json_extract(cus.data, '$.phone2') AS phone2,
          json_extract(cus.data, '$.email') AS email,
          json_extract(cus.data, '$.web') AS web,
          json_extract(cus.data, '$.customerType') AS customerType,
          json_extract(cus.data, '$.jobTitle') AS jobTitle,
          json_extract(cus.data, '$.region') AS region
        FROM 
          [customers] AS cus
        WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.customer.id
      isDocument: true

children:
  - type: component.form
    instanceId: customer
    options:
      isDiscardChangesAlertEnabled: false
      children:
        - type: component.text-field
          instanceId: companyName
          options:
            label: Company Name
            initialValue: =@ctx.datasources.customers.companyName
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
                  initialValue: =@ctx.datasources.customers.firstName
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
                  initialValue: =@ctx.datasources.customers.lastName
        - type: component.text-field
          instanceId: jobTitle
          options:
            label: Job Title
            initialValue: =@ctx.datasources.customers.jobTitle
        - type: component.text-field
          instanceId: email
          options:
            label: Email
            initialValue: =@ctx.datasources.customers.email
        - type: component.text-field
          instanceId: phone1
          options:
            label: Mobile
            initialValue: =@ctx.datasources.customers.phone1
        - type: component.text-field
          instanceId: web
          options:
            label: Web
            initialValue: =@ctx.datasources.customers.web
        - type: component.text-field
          instanceId: address
          options:
            label: Street
            initialValue: =@ctx.datasources.customers.address
        - type: component.text-field
          instanceId: city
          options:
            label: City
            initialValue: =@ctx.datasources.customers.city
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: state
                options:
                  label: State
                  initialValue: =@ctx.datasources.customers.state
              - type: component.text-field
                instanceId: zip
                options:
                  label: ZIP
                  initialValue: =@ctx.datasources.customers.zip
        - type: component.field-row
          options:
            children:
              - type: component.dropdown
                instanceId: region
                options:
                  label: Region
                  data: =@ctx.datasources.region
                  initialValue: =@ctx.datasources.customers.region
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.region
                      value: =@ctx.current.item.region
              - type: component.dropdown
                instanceId: customerType
                options:
                  label: Customer Type
                  data: =@ctx.datasources.customerType
                  initialValue: =@ctx.datasources.customers.customerType
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.type
                      value: =@ctx.current.item.value

actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          # Use add to queue all the updates related to a record.
          queueOperation: add
          function: rest-update-customer
          parameters:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
          data:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value    
```

{% endtab %}

{% tab title="rest-update-customer.jigx (function)" %}

```yaml
provider: DATA_PROVIDER_REST
method: PUT
# Use your REST service URL
url: https://[your_rest_service]/api/customers 
# Direct the function call to use local execution between the mobile device 
# and the REST service.
format: text
useLocalCall: true 

parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials.
    value: service.oauth 
  id:
    type: int
    location: body
    required: true
  firstName:
    type: string
    location: body
    required: true
  lastName:
    type: string
    location: body
    required: true
  companyName:
    type: string
    location: body
    required: true
  address:
    type: string
    location: body
    required: false
  city:
    type: string
    location: body
    required: false
  state:
    type: string
    location: body
    required: false
  zip:
    type: string
    location: body
    required: false
  phone1:
    type: string
    location: body
    required: false
  phone2:
    type: string
    location: body
    required: false
  email:
    type: string
    location: body
    required: false
  web:
    type: string
    location: body
    required: false
  region:
    type: string
    location: body
    required: false
  customerType:
    type: string
    location: body
    required: false
  jobTitle:
    type: string
    location: body
    required: false

inputTransform: |
  {
    "custId": id,
    "firstName": firstName,
    "lastName": lastName,
    "companyName": companyName,
    "address": address,
    "city": city,
    "state": state, 
    "zip": zip,
    "phone1": phone1,
    "phone2": phone2,
    "email": email,
    "web": web,
    "region": region,
    "customerType": customerType,
    "jobTitle": jobTitle
  }
```

{% endtab %}
{% endtabs %}

### Execute-entity (delete) with queueOperation (replace)

In this example, when the device is offline and a customer record is updated multiple times and then deleted, all the the commands for the record are removed from the queue and local entity is deleted. When the device is back online the queue is cleared.

{% tabs %}
{% tab title=" delete-customer" %}

```yaml
title: Customers
type: jig.list
icon: list

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

onRefresh:
  type: action.execute-action
  options:
    action: load-customers

datasources:
  customers:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: customers
      query: |
          SELECT
          cus.id AS id,
          json_extract(cus.data, '$.firstName') AS firstName,
          json_extract(cus.data, '$.lastName') AS lastName,
          json_extract(cus.data, '$.companyName') AS companyName,
          json_extract(cus.data, '$.address') AS address,
          json_extract(cus.data, '$.city') AS city,
          json_extract(cus.data, '$.state') AS state,
          json_extract(cus.data, '$.zip') AS zip,
          json_extract(cus.data, '$.phone1') AS phone1,
          json_extract(cus.data, '$.phone2') AS phone2,
          json_extract(cus.data, '$.email') AS email,
          json_extract(cus.data, '$.web') AS web,
          json_extract(cus.data, '$.customerType') AS customerType,
          json_extract(cus.data, '$.jobTitle') AS jobTitle,
          json_extract(cus.data, '$.logo') AS logo
        FROM
          [customers] AS cus
        ORDER BY
          json_extract(cus.data, '$.companyName')

data: =@ctx.datasources.customers
item:
  type: component.list-item
  options:
    title: =@ctx.current.item.companyName & ' (' & @ctx.current.item.id & ')'
    subtitle: =@ctx.current.item.firstName & ' ' & @ctx.current.item.lastName
    leftElement:
      element: avatar
      text: =@ctx.current.item.state
      uri: =@ctx.current.item.logo
    label:
      title: |
        =$uppercase((@ctx.current.item.customerType = 'Silver' ? @ctx.current.item.customerType:@ctx.current.item.customerType = 'Gold' ? @ctx.current.item.customerType:''))
      color:
        - when: =@ctx.current.item.customerType = 'Gold'
          color: color3
        - when: =@ctx.current.item.customerType = 'Silver'
          color: color14
    onPress:
      type: action.go-to
      options:
        linkTo: update-customer
        parameters:
          customer: =@ctx.current.item
    swipeable:
      left:
        - label: DELETE
          icon: delete-2
          color: negative
          onPress:
            type: action.confirm
            options:
              isConfirmedAutomatically: false
              onConfirmed:
                type: action.execute-entity
                options:
                  provider: DATA_PROVIDER_REST
                  entity: customers
                  method: delete
                  # For delete use replace, If the record has tempId it will 
                  # remove all opperations related to the record from the queue
                  queueOperation: replace
                  function: rest-delete-customer
                  parameters:
                    custId: =$number(@ctx.current.item.id)
                  data:
                    id: =@ctx.current.item.id
              modal:
                title: Are you sure?
                description: |
                  =('Press Confirm to permanently delete ' & @ctx.current.item.companyName)
```

{% endtab %}

{% tab title="rest-delete-customer.jigx (function)" %}

```yaml
provider: DATA_PROVIDER_REST
method: DELETE
# Use your REST service URL
url: https://[your_rest_service]/api/customers?id={custId} 
# Direct the function call to use local execution between the mobile device
# and the REST service.
format: text
useLocalCall: true 

parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution.
    value: service.oauth 
  custId:
    type: int
    location: query
    required: true
```

{% endtab %}
{% endtabs %}

### Execute-entity with queueOperations when no id is returned

In this example, the remote data store does not return an id, and we need to sync the data before we get the correct backend id for the record. We need to be careful not to create and update the same record on the queue because the backend cannot associate the records after the sync. To accommodate for this in the update-customer jig we configure two `execute-entity` actions.

* The first action checks to see if a record has a tempId by using the following expression `when: =$isTempId(@ctx.jig.inputs.customer.id)`. If the record on the queue has a tempId, we replace it using the **create** method with a new item that will be placed on the queue.
* The second action checks to see if the record has a valid Id rather than a tempId by using the following expression `when: =$not($isTempId(@ctx.jig.inputs.customer.id))`. If the record on the queue has a valid id, we replace it using the **update** method with an item that will be placed on the queue.

{% tabs %}
{% tab title="new-customer.jigx" %}

```yaml
title: New Customer
type: jig.default

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

onFocus:
  type: action.reset-state
  options:
    state: =@ctx.jig.components.customerForm.state.data

datasources:
  region:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: us-states
      query: |
        SELECT 
          uss.id AS id, 
          json_extract(uss.data, '$.state') AS state, 
          json_extract(uss.data, '$.abbreviation') AS abbreviation,
          json_extract(uss.data, '$.stateCapital') AS stateCapital,
          json_extract(uss.data, '$.region') AS region,
          json_extract(uss.data, '$.flag') AS flag
        FROM 
          [us-states] AS uss
        WHERE  
          json_extract(uss.data, '$.abbreviation') = @selectedState
      queryParameters:
        selectedState: =@ctx.components.usState.state.value

  customerType:
    type: datasource.static
    options:
      data:
        - id: 1
          type: New
          value: new
        - id: 2
          type: Gold
          value: Gold
        - id: 3
          type: Silver
          value: Silver
children:
  - type: component.form
    instanceId: customerForm
    options:
      isDiscardChangesAlertEnabled: false
      children:
        - type: component.text-field
          instanceId: companyName
          options:
            label: Company Name
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
        - type: component.text-field
          instanceId: jobTitle
          options:
            label: Job Title
        - type: component.text-field
          instanceId: email
          options:
            label: Email
        - type: component.text-field
          instanceId: phone1
          options:
            label: Mobile
        - type: component.text-field
          instanceId: web
          options:
            label: Web
        - type: component.text-field
          instanceId: address
          options:
            label: Street
        - type: component.text-field
          instanceId: city
          options:
            label: City
        - type: component.field-row
          options:
            children:
              - type: component.dropdown
                instanceId: usState
                options:
                  label: State
                  data: =@ctx.datasources.us-states
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.state
                      value: =@ctx.current.item.abbreviation
                      leftElement:
                        element: avatar
                        text: =@ctx.current.item.abbreviation
                        uri: =@ctx.current.item.flag
              - type: component.text-field
                instanceId: zip
                options:
                  label: ZIP
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: region
                options:
                  label: Region
                  value: =@ctx.datasources.region.region
              - type: component.dropdown
                instanceId: customerType
                options:
                  label: Customer Type
                  data: =@ctx.datasources.customerType
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.type
                      value: =@ctx.current.item.value

actions:
  - children:
      - type: action.execute-entity
        options:
          title: Create Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: create
          # In this scenario, the backend system does not return an ID, 
          # you need to sync the data before we get the correct backend ID for 
          # the record. With this in mind, you'll need to be careful not to 
          # create and update the same record on the queue because the backend 
          # cannot associate the records after the sync. Have a look at the 
          # Update jig to see the correct way of dealing with this scenario.
          function: rest-create-customer
          parameters:
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.usState.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
          data:
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.usState.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value   
```

{% endtab %}

{% tab title="update-customer.jigx" %}

```yaml
title: Update Customer
type: jig.default

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

datasources:
  region:
    type: datasource.static
    options:
      data:
        - id: 1
          region: US Central
        - id: 2
          region: US East
        - id: 3
          region: US West
  customerType:
    type: datasource.static
    options:
      data:
        - id: 1
          type: New
          value:
        - id: 2
          type: Gold
          value: Gold
        - id: 3
          type: Silver
          value: Silver
  customers:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL

      entities:
        - entity: customers

      query: |
        SELECT 
          cus.id AS id, 
          json_extract(cus.data, '$.firstName') AS firstName, 
          json_extract(cus.data, '$.lastName') AS lastName,
          json_extract(cus.data, '$.companyName') AS companyName,
          json_extract(cus.data, '$.address') AS address,
          json_extract(cus.data, '$.city') AS city,
          json_extract(cus.data, '$.state') AS state,
          json_extract(cus.data, '$.zip') AS zip,
          json_extract(cus.data, '$.phone1') AS phone1,
          json_extract(cus.data, '$.phone2') AS phone2,
          json_extract(cus.data, '$.email') AS email,
          json_extract(cus.data, '$.web') AS web,
          json_extract(cus.data, '$.customerType') AS customerType,
          json_extract(cus.data, '$.jobTitle') AS jobTitle,
          json_extract(cus.data, '$.region') AS region
        FROM 
          [customers] AS cus
        WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.customer.id
      isDocument: true

children:
  - type: component.form
    instanceId: customer
    options:
      isDiscardChangesAlertEnabled: false
      children:
        - type: component.text-field
          instanceId: companyName
          options:
            label: Company Name
            initialValue: =@ctx.datasources.customers.companyName
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
                  initialValue: =@ctx.datasources.customers.firstName
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
                  initialValue: =@ctx.datasources.customers.lastName
        - type: component.text-field
          instanceId: jobTitle
          options:
            label: Job Title
            initialValue: =@ctx.datasources.customers.jobTitle
        - type: component.text-field
          instanceId: email
          options:
            label: Email
            initialValue: =@ctx.datasources.customers.email
        - type: component.text-field
          instanceId: phone1
          options:
            label: Mobile
            initialValue: =@ctx.datasources.customers.phone1
        - type: component.text-field
          instanceId: web
          options:
            label: Web
            initialValue: =@ctx.datasources.customers.web
        - type: component.text-field
          instanceId: address
          options:
            label: Street
            initialValue: =@ctx.datasources.customers.address
        - type: component.text-field
          instanceId: city
          options:
            label: City
            initialValue: =@ctx.datasources.customers.city
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: state
                options:
                  label: State
                  initialValue: =@ctx.datasources.customers.state
              - type: component.text-field
                instanceId: zip
                options:
                  label: ZIP
                  initialValue: =@ctx.datasources.customers.zip
        - type: component.field-row
          options:
            children:
              - type: component.dropdown
                instanceId: region
                options:
                  label: Region
                  data: =@ctx.datasources.region
                  initialValue: =@ctx.datasources.customers.region
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.region
                      value: =@ctx.current.item.region
              - type: component.dropdown
                instanceId: customerType
                options:
                  label: Customer Type
                  data: =@ctx.datasources.customerType
                  initialValue: =@ctx.datasources.customers.customerType
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.type
                      value: =@ctx.current.item.value

actions:
  - children:
      - type: action.execute-entity
        # The best way to tell if a record has a temp ID is to use the following function
        # =$isTempId(@ctx.jig.inputs.customer.id). If you have a record on the queue with
        # a temp ID, you need to replace it with a new item that will be placed on the queue.
        when: =$isTempId(@ctx.jig.inputs.customer.id)
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: create
          goBack: previous
          function: rest-create-customer
          # Replace current create on the queue
          queueOperation: replace
          # Replace requires an id, if no id is specified in the parameter,
          # use the data property to specify the id.
          data:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
          parameters:
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
      - type: action.execute-entity
        when: =$not($isTempId(@ctx.jig.inputs.customer.id))
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          goBack: previous
          queueOperation: replace
          function: rest-update-customer
          parameters:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
          data:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value   
```

{% endtab %}

{% tab title="rest-create-customer.jigx (function)" %}

```yaml
provider: DATA_PROVIDER_REST
# Create new record in the backend
method: POST 
# Use your REST service URL
url: url: https://[your_rest_service]/api/customers 
useLocalCall: true

parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution
    value: service.oauth 
  firstName:
    type: string
    location: body
    required: true
  lastName:
    type: string
    location: body
    required: true
  companyName:
    type: string
    location: body
    required: true
  address:
    type: string
    location: body
    required: false
  city:
    type: string
    location: body
    required: false
  state:
    type: string
    location: body
    required: false
  zip:
    type: string
    location: body
    required: false
  phone1:
    type: string
    location: body
    required: false
  phone2:
    type: string
    location: body
    required: false
  email:
    type: string
    location: body
    required: false
  web:
    type: string
    location: body
    required: false
  region:
    type: string
    location: body
    required: false
  customerType:
    type: string
    location: body
    required: false
  jobTitle:
    type: string
    location: body
    required: false

inputTransform: |
  {
    "firstName": firstName,
    "lastName": lastName,
    "companyName": companyName,
    "address": address,
    "city": city,
    "state": state,
    "zip": zip,
    "phone1": phone1,
    "phone2": phone2,
    "email": email,
    "web": web,
    "region": region,
    "customerType": customerType,
    "jobTitle": jobTitle
  }
# In this scenario, the backend system does not return an ID, you need to sync
# the data before we get the correct backend ID for the record. With this in mind,
# you'll need to be careful not to create and update the same record on the queue
# because the backend cannot associate the records after the sync. Have a look at
# the Update jig to see the correct way of dealing with this scenario.
```

{% endtab %}
{% endtabs %}

### Clear commands in the queue for a record

In this example, a secondary button is added to clear the queue for commands for a specific record using the `action.clear-queue`.&#x20;

{% tabs %}
{% tab title="clear-customer-updates.jigx" %}
{% code title="clear-customer-updates.jigx" %}

```yaml
title: Update Customer
type: jig.default

header:
  type: component.jig-header
  options:
    height: small
    children:
      type: component.image
      options:
        source:
          uri: https://www.dropbox.com/scl/fi/ha9zh6wnixblrbubrfg3e/business-5475661_640.jpg?rlkey=anemjh5c9qsspvzt5ri0i9hva&raw=1

children:
  - type: component.form
    instanceId: customer
    options:
      isDiscardChangesAlertEnabled: false
      children:
        - type: component.text-field
          instanceId: companyName
          options:
            label: Company Name
            initialValue: =@ctx.datasources.customers.companyName
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: firstName
                options:
                  label: First Name
                  initialValue: =@ctx.datasources.customers.firstName
              - type: component.text-field
                instanceId: lastName
                options:
                  label: Last Name
                  initialValue: =@ctx.datasources.customers.lastName
        - type: component.text-field
          instanceId: jobTitle
          options:
            label: Job Title
            initialValue: =@ctx.datasources.customers.jobTitle
        - type: component.text-field
          instanceId: email
          options:
            label: Email
            initialValue: =@ctx.datasources.customers.email
        - type: component.text-field
          instanceId: phone1
          options:
            label: Mobile
            initialValue: =@ctx.datasources.customers.phone1
        - type: component.text-field
          instanceId: web
          options:
            label: Web
            initialValue: =@ctx.datasources.customers.web
        - type: component.text-field
          instanceId: address
          options:
            label: Street
            initialValue: =@ctx.datasources.customers.address
        - type: component.text-field
          instanceId: city
          options:
            label: City
            initialValue: =@ctx.datasources.customers.city
        - type: component.field-row
          options:
            children:
              - type: component.text-field
                instanceId: state
                options:
                  label: State
                  initialValue: =@ctx.datasources.customers.state
              - type: component.text-field
                instanceId: zip
                options:
                  label: ZIP
                  initialValue: =@ctx.datasources.customers.zip
        - type: component.field-row
          options:
            children:
              - type: component.dropdown
                instanceId: region
                options:
                  label: Region
                  data: =@ctx.datasources.region
                  initialValue: =@ctx.datasources.customers.region
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.region
                      value: =@ctx.current.item.region
              - type: component.dropdown
                instanceId: customerType
                options:
                  label: Customer Type
                  data: =@ctx.datasources.customerType
                  initialValue: =@ctx.datasources.customers.customerType
                  item:
                    type: component.dropdown-item
                    options:
                      title: =@ctx.current.item.type
                      value: =@ctx.current.item.value

actions:
  - children:
      - type: action.execute-entity
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          method: update
          # Use replace to ensure you only have one update on the queue related 
          # to a record. Not doing this will not break the solution but will 
          # help to avoid chattiness and scenarios where backends have rate limits.
          queueOperation: replace
          function: rest-update-customer
          parameters:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value
          data:
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            customerType: =@ctx.components.customerType.state.value
            email: =$lowercase(@ctx.components.email.state.value)
            jobTitle: =@ctx.components.jobTitle.state.value
            phone1: =@ctx.components.phone1.state.value
            phone2: =@ctx.components.phone1.state.value
            region: =@ctx.components.region.state.value
            state: =@ctx.components.state.state.value
            web: =$lowercase(@ctx.components.web.state.value)
            zip: =@ctx.components.zip.state.value   
      # Use the clear-queue to discard any commands in the queue for this record
      # while the device is offline.
      - type: action.clear-queue
        options:
          title: Cancel updates
          id: =@ctx.jig.inputs.customer.id
```

{% endcode %}
{% endtab %}

{% tab title="datasources" %}

```yaml
datasources:
  region:
    type: datasource.static
    options:
      data:
        - id: 1
          region: US Central
        - id: 2
          region: US East
        - id: 3
          region: US West
  customerType:
    type: datasource.static
    options:
      data:
        - id: 1
          type: New
          value:
        - id: 2
          type: Gold
          value: Gold
        - id: 3
          type: Silver
          value: Silver
  customers:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: customers
      query: |
        SELECT 
          cus.id AS id, 
          json_extract(cus.data, '$.firstName') AS firstName, 
          json_extract(cus.data, '$.lastName') AS lastName,
          json_extract(cus.data, '$.companyName') AS companyName,
          json_extract(cus.data, '$.address') AS address,
          json_extract(cus.data, '$.city') AS city,
          json_extract(cus.data, '$.state') AS state,
          json_extract(cus.data, '$.zip') AS zip,
          json_extract(cus.data, '$.phone1') AS phone1,
          json_extract(cus.data, '$.phone2') AS phone2,
          json_extract(cus.data, '$.email') AS email,
          json_extract(cus.data, '$.web') AS web,
          json_extract(cus.data, '$.customerType') AS customerType,
          json_extract(cus.data, '$.jobTitle') AS jobTitle,
          json_extract(cus.data, '$.region') AS region
        FROM 
          [customers] AS cus
        WHERE id = @custId
      queryParameters:
        custId: =@ctx.jig.inputs.customer.id
```

{% endtab %}
{% endtabs %}

### Testing and debugging queues

As you add the `queueOperation` property to actions, it is helpful to test or debug that the commands are being executed as configured. Here is a jig that can help you see the commands being queued when the device is offline, and then see the queue clear when the device is back online.

{% code title="debugging-queues" %}

```yaml
title: Queue
type: jig.list
icon: database-2

datasources:
  listdata:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - _commandQueue
      query: |
        SELECT 
          id, 
          json_extract(payload, '$.functionId') as functionId,
          [type], 
          [queue], 
          [state], 
          [error],
          @dummy as dummy
        FROM [_commandQueue]
      queryParameters:
        dummy: =@ctx.jig.inputs.dummyID

data: =@ctx.datasources.listdata
item:
  type: component.list-item
  options:
    title: =@ctx.current.item.functionId & ' ' & @ctx.current.item.dummy
    subtitle: =@ctx.current.item.type & ' ' & @ctx.current.item.state
    description: =@ctx.current.item.error
```

{% endcode %}


# File handling

Jigx stores files as local files on the device and returns the file's URI as the default value. When saving these files to a datasource, you must convert files from the local-uri to base64, data-uri, or buffer. The opposite is true when handling the files returned from the datasource; you must convert them from their saved state (base64, data-uri, or buffer) to a local-uri.

Type of files:

* Images
* Documents

Image files can be used in the following functionality:

<table><thead><tr><th width="238.828125">Data</th><th width="289.21484375">Conversion configuration</th><th>Result</th></tr></thead><tbody><tr><td>REST Provider calls with files</td><td>Add the conversion to the REST function</td><td>GET - incoming<br>SAVE - outgoing<br>CREATE - outgoing<br>UPDATE - outgoing</td></tr><tr><td>SQL Provider calls with files</td><td>Add the conversion to the REST function</td><td>GET - incoming<br>SAVE - outgoing<br>CREATE - outgoing<br>UPDATE - outgoing</td></tr><tr><td>Datasource queries with files</td><td>Add the conversion to the datasource when using Dynamic Data.</td><td>Incoming</td></tr><tr><td>Actions with files</td><td>Add the conversion to the action when saving images and files.</td><td>outgoing</td></tr></tbody></table>

The `conversions` property allows you to configure the file conversion to the required format.

<table><thead><tr><th width="159.19921875">Core structure</th><th></th></tr></thead><tbody><tr><td><code>conversions:</code></td><td><p>This holds an array of properties that should be converted. The following properties control the conversion:</p><ul><li><code>property:</code> The name of the property to convert.</li><li><code>from:</code> Format of the input data. It can be buffer, base64, data-uri, or local-uri.</li><li><code>to:</code> Format of the converted data. It can be base64, data-uri, buffer, or local-uri.</li><li><code>convertHeicToJpg:</code> When set to <code>true</code>, and the file being converted is HEIC, it is converted to JPG.</li></ul><p>Conversions can be set up as a static array of definitions or dynamically as an array returned by an expression. To set up dynamic conversions, use the expression <code>conversions: =@ctx.datasources.conversions</code>, applicable to both local and global actions.</p></td></tr></tbody></table>

Referencing files in a jig - You can access the file using the `state` of the components and properties in a jig, such as [media-field](https://docs.jigx.com/examples/readme/components/media-field) or [avatar-field](https://docs.jigx.com/examples/readme/components/avatar). When referencing files in jigs use the `.state.value` configuration. For example:

* `file: =@ctx.components.profilePicture.state.value`
* `image: =@ctx.components.image.state.value`

## Considerations

* Conversions should be configured within the SQL and REST functions. When the conversion is configured in the function, it stores the data as the 'from' type in the datasource.
* When conversions are done at the datasource level, they are still stored in the datasource as their original value. They are only converted after the fact when requested; however, the datasource value does not change.
* Do not load data back from buffer using the Dynamic Data provider; the file will not show.
* When saving images to Dynamic Data consider the file size. You can reduce the file size in the [media-field](https://docs.jigx.com/examples/readme/components/media-field) by configuring the `imageQuality` property.
* Use `convertHeicToJpg` to ensure images are visible on iOS and Android devices. The property is available for REST and SQL functions, Dynamic Data and actions.

{% hint style="warning" %}
Jigx does not recommend storing images in Dynamic Data (via any conversion), as the max file size per record is 350K.
{% endhint %}

## Examples and code snippets

## Convert incoming data

### REST & SQL function

In the examples below, the file conversions are configured in the REST and SQL (GET) functions to convert the incoming files.

{% tabs %}
{% tab title="rest-function-in" %}

```yaml
provider: DATA_PROVIDER_REST
method: GET
# pdf indicates a generic binary type
format: pdf 
url: https://graph.microsoft.com/v1.0/me/photo/$value
# Add the email input to the output to identify image later in select
useLocalCall: true
outputTransform: $.{"data":$.data,"userId":$.inputs.userId.value} 
parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution.
    value: oauth.microsoft 
  userId:
    type: string
    location: path
    required: true
conversions:
  - property: data
    from: base64
    to: local-uri
```

{% endtab %}

{% tab title="sql-function-in" %}

```yaml
provider: DATA_PROVIDER_SQL
method: query
connection: test-db
query: SELECT TOP(@top) Id, FirstName, LastName, AvatarBase64, AvatarDataUri, AvatarBuffer FROM Employee
parameters:
  top:
    location: input
    required: false
    type: number
    value: 10
conversions:
  - property: AvatarBuffer
    from: buffer
    to: local-uri
  - property: AvatarBase64
    from: base64
    to: local-uri
  - property: AvatarDataUri
    from: data-uri
    to: local-uri
```

{% endtab %}
{% endtabs %}

## Convert outgoing data

### REST & SQL function

In the examples below, the file conversions are configured in the **REST** and **SQL** (SAVE/CREATE/UPDATE) **functions** to convert the files that are outgoing to REST and SQL.

{% tabs %}
{% tab title="rest-function-out" %}

```yaml
provider: DATA_PROVIDER_REST
method: PATCH
url: https://graph.microsoft.com/v1.0/me/photo/$value
useLocalCall: true
parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution.
    value: oauth.microsoft 
  Content-Type:
    location: header
    required: true
    type: string
    # set the content type of the body.
    value: image/jpeg 
  file:
    location: body
    required: true
    type: image
conversions:
  - property: file
    from: local-uri
    to: buffer
```

{% endtab %}

{% tab title="sql-function-out" %}

```yaml
provider: DATA_PROVIDER_SQL
method: execute
connection: test-db
procedure: AddWidget
parameters:
  firstname:
    location: input
    required: true
    type: string
  lastname:
    location: input
    required: true
    type: string
  avatarbase64:
    location: input
    required: true
    type: string
  avatardatauri:
    location: input
    required: true
    type: string
  avatarbuffer:
    location: input
    required: true
    type: file
    encoding: binary
conversions:
  - property: avatarbuffer
    from: local-uri
    to: buffer
  - property: avatarbase64
    from: local-uri
    to: base64
  - property: avatardatauri
    from: local-uri
    to: data-uri
```

{% endtab %}
{% endtabs %}

## Datasource conversion

In this example, the Dynamic Data image file conversion is configured in the datasource to convert the files to be used in the solution.

{% code title="datasource-conversion" %}

```yaml
type: datasource.sqlite
options:
  provider: DATA_PROVIDER_DYNAMIC
  entities:
    - default/category
  query: |
    SELECT id, '$.name', '$.description', '$.image'
    FROM [default/category]
    ORDER BY [name]
  conversions:
    - property: image
      from: base64
      to: local-uri
```

{% endcode %}

## Action image conversion

File conversions in actions can be configured with Dynamic Data, SQL, and REST providers. They can be set up as a static array of definitions or dynamically as an array returned by an expression. To set up dynamic conversions, use the expression `conversions: =@ctx.datasources.conversions`, applicable to both local and global actions.

{% tabs %}
{% tab title="execute-entity-action (static)" %}

```yaml
- type: action.execute-entity
    options:
      title: Save
      provider: DATA_PROVIDER_DYNAMIC
      entity: default/category
      method: save
      data:
        id: =@ctx.jig.inputs.categoryId
        name: =@ctx.components.name.state.value
        description: =@ctx.components.description.state.value
        # reference the image using an expression.
        image: =@ctx.components.image.state.value
      # Static conversion configuration.
      conversions:
        - property: image
          from: local-uri
          to: base64
```

{% endtab %}

{% tab title="execute-entity-action (dynamic)" %}

```yaml
- type: action.execute-entity
    options:
      title: Save
      provider: DATA_PROVIDER_DYNAMIC
      entity: default/category
      method: save
      data:
        id: =@ctx.jig.inputs.categoryId
        name: =@ctx.components.name.state.value
        description: =@ctx.components.description.state.value
        # reference the image using an expression.
        image: =@ctx.components.image.state.value
      # Dynamic conversion configuration.
      conversions: =@ctx.datasources.conversions
```

{% endtab %}

{% tab title="datasource" %}

```yaml
type: datasource.sqlite
options:
  provider: DATA_PROVIDER_DYNAMIC
  entities:
    - default/category
  query: |
    SELECT id, '$.name', '$.description', '$.image'
    FROM [default/category]
    ORDER BY [name]
  conversions:
    - property: image
      from: base64
      to: local-uri
```

{% endtab %}
{% endtabs %}

## Add multiple files with SQL data provider

This example uses the `text-field` with `mediaType: image` and `isMultiple: true` to add multiple images to SQL. The `conversion` of the files is done in the SQL function.

{% tabs %}
{% tab title="sql-add-widget-multiple-function.jigx" %}

```yaml
# Add under function folder
provider: DATA_PROVIDER_SQL
method: execute
connection: SportConnect
procedure: AddMultipleAvatar
parameters:
  avatarbuffer:
    encoding: binary
    location: input
    required: true
    type: file
  description:
    location: input
    required: true
    type: string

conversions:
  - from: local-uri
    property: avatar
    to: buffer
```

{% endtab %}

{% tab title="sql-get-widget-multiple-jigx" %}

```yaml
# Add under function folder
provider: DATA_PROVIDER_SQL
method: query
connection: SportConnect

query: |
  SELECT  
    Id, 
    description,
    Avatar
  FROM avatarMultiConversion

conversions:
  - property: Avatar
    from: buffer
    to: local-uri
```

{% endtab %}

{% tab title="add-widget-mutiple-sql.jigx" %}

```yaml
# Add under jig folder
title: Add Widget Multiple
type: jig.default

onFocus:
  type: action.sync-entities
  options:
    provider: DATA_PROVIDER_SQL
    entities:
      - entity: avatarMultiConversion
        function: sql-get-widget-multiple

datasources:
  allImages:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: avatarMultiConversion
      query: |
        SELECT
          '$.Id',
          '$.type',
          '$.Avatar'
        FROM [avatarMultiConversion]

children:
  - type: component.form
    instanceId: add-widget-multiple
    options:
      children:
        - instanceId: description
          options:
            label: Description
          type: component.text-field
        - instanceId: avatarbuffer
          options:
            # set for multiple files to be added
            isMultiple: true
            label: Avatar
            mediaType: image
          type: component.media-field
      isDiscardChangesAlertEnabled: false

  - type: component.list
    options:
      data: =@ctx.datasources.allImages
      maximumItemsToRender: 8
      item:
        type: component.list-item
        options:
          title: =@ctx.current.item.type
          leftElement:
            element: image
            text: ""
            uri: =@ctx.current.item.Avatar

actions:
  - children:
      # use execute entites for multiple files to be added
      - type: action.execute-entities
        # Options in error are expected as there are no parameters.
        options:
          title: Add Widget Multiple
          provider: DATA_PROVIDER_SQL
          entity: avatarMultiConversion
          data: |
            =@ctx.components.avatarbuffer.state.value.{
              "description" : @ctx.components.description.state.value 
            , "avatarbuffer" : $ }
          function: sql-add-widget-multiple
          goBack: stay
          method: functionCall
          onSuccess:
            title: Success
```

{% endtab %}
{% endtabs %}

## Convert HEIC to JPEG

In this example, the file conversion is configured in the REST function to convert the files that are outgoing via REST. `convertHeicToJpg` is configured to `true` to convert HEIC images to JPEG which ensures images are visible on iOS and Android devices. The property is available REST and SQL functions, Dynamic Data and actions.

```yaml
provider: DATA_PROVIDER_REST
method: PATCH
url: https://graph.microsoft.com/v1.0/me/photo/$value
useLocalCall: true
parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution.
    value: oauth.microsoft 
  Content-Type:
    location: header
    required: true
    type: string
    # set the content type of the body.
    value: image/jpeg 
  file:
    location: body
    required: true
    type: image
conversions:
  - property: file
    from: local-uri
    to: buffer
    convertHeicToJpg: true
```

### See Also

* [Example converting local-uri to buffer in SQL function](https://docs.jigx.com/examples/readme/components/media-field#convert-files-in-sql-function)


# Data Providers

Utilize the data providers available in Jigx to seamlessly integrate with data from diverse sources, including Jigx's dynamic data store. These providers efficiently handle data inputs and deliver accurate data outputs.

1. [Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data) is a Jigx-specific database that automatically syncs data between devices in real time. It is an excellent platform for disposable data, defining data that is not already available in existing systems and how to sync data in real time between users and their devices, regardless of where it is updated.
2. [Microsoft Azure SQL](https://docs.jigx.com/microsoft-azure-sql) is configured to allow secure access, and Jigx functions to read, update, and delete data with queries and stored procedures.
3. [Microsoft OneDrive](/building-apps-with-jigx/data/data-providers/microsoft-onedrive) integration allows you to create, update, and delete files in OneDrive. In a solution, you can list and download files from OneDrive onto your device.
4. [REST](/building-apps-with-jigx/data/data-providers/rest) provides an overview of working with REST services, including how data is returned, transformed, and used in the solution. This section explains selective data updates and how to configure security and more complex REST calls.
5. [Salesforce](/building-apps-with-jigx/data/data-providers/salesforce) allows you to integrate with your Salesforce instance, with access to share data about sales, customers, markets, and more.
6. LOCAL - Stores data locally inside your solution until the app closes.
7. SOAP - works with APIs based on SOAP protocols.


# Dynamic Data

Apps need data, while [static](https://docs.jigx.com/examples/readme/datasource/static) allows you to add static or testing data into a jig it is very limiting, and you will want access to a database for data. Jigx **Dynamic Data** is a built-in database used to create, read, update, and delete data in an app.

The underlying data store for Dynamic Data is a NoSQL store. This means that each record can have its own field structure, and you can add or remove any fields on a per-record basis. Only the id column is a system column and cannot be changed or removed from the record.

We can visualize how dynamic data works by following the steps below:

<figure><img src="/files/Ps4fngX6VF5OvXKLkRyX" alt="Dynamic Data Overview"><figcaption><p>Dynamic Data Overview</p></figcaption></figure>

1. Data is updated on the device (Device 1).
2. Data is immediately synced with the Dynamic Data database in the Jigx cloud.
3. These changes are immediately reflected on any other device that shares the same data (Device 2).

## Capabilities

* A Jigx cloud-hosted NoSQL database that syncs automatically with data on the device.
* A web-based [management](https://docs.jigx.com/data) interface for viewing the Dynamic data tables, browsing and editing data and setting [Data policies](/administration/solutions/row-level-security/data-policies) in these tables.
* Rapidly import your own data by uploading any JSON or CSV file to the [management](https://docs.jigx.com/data) interface.
* You can also export your data in JSON for reporting and other integration needs.
* Changes made on your device are stored locally and immediately reflected in the cloud-hosted database.
* Realtime data syncing between your device, Dynamic data in the cloud, and other devices.
* Devices continue to operate offline and any local changes will be synced to the database once the device established a connection.
* To understand how Dynamic Data functions when the app is offline see [Dynamic Data change tracking & queuing](/building-apps-with-jigx/data/offline-remote-data-handling#dynamic-data-change-tracking-and-queuing).

{% hint style="warning" %}
Jigx does not recommend storing images in Dynamic Data (via any conversion), as the max file size per record is 350K.
{% endhint %}

## How to create Dynamic Data

To create and use Dynamic data see the following:

1. [Creating tables](/building-apps-with-jigx/data/data-providers/dynamic-data/creating-tables)
2. [Creating columns & data records](/building-apps-with-jigx/data/data-providers/dynamic-data/creating-columns-data-records)
3. [Deleting tables](/building-apps-with-jigx/data/data-providers/dynamic-data/deleting-tables)
4. [Using Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data/using-dynamic-data)

{% columns %}
{% column %}
{% embed url="<https://vimeo.com/830296571?share=copy>" %}
{% endcolumn %}

{% column %}
{% embed url="<https://vimeo.com/829863168?share=copy>" %}
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
**Supporting file** for the *Working with Dynamic Data* video. You can use this CSV file if you want to follow the steps in the video.
{% endhint %}

## Examples and code snippets

The following examples with code snippets are provided:

* [Creating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/creating-dynamic-data)
* [Reading Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/reading-dynamic-data)
* [Updating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/updating-dynamic-data)
* [Deleting Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/deleting-dynamic-data)


# Creating tables

First step in creating Dynamic Data for a solution is to create the tables that the solution requires. Tables are created in a solution in Jigx Builder in the *default.jigx* file located in the *database* folder. All tables are created under the default database. Follow the steps below to create tables:

<figure><img src="/files/MFX4oJchJkMVycCwCxqL" alt="Tables in Dynamic Data"><figcaption><p>Tables in Dynamic Data</p></figcaption></figure>

1. Open an existing solution or [create a new solution](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/create-a-new-jigx-solution.md) in Jigx Builder.
2. Expand the database folder and click on the **default.jigx** file.
3. Use IntelliSense (ctrl+space) in the editor, select **tables**, and press enter.
4. Type the name of your table and provide a null value, for example, `employee: null`. Take note of the table name formats below:
   * Table names must be in lowercase
   * The first character must start with a letter
   * The name can contain alphanumeric or symbols '-' and '\\\_'
   * You can include "-" dash , "\_" underscore and digits as per the regex: "^\[a-z]\[a-z0-9\_-]{0,28}\[a-z0-9]$"
   * The name cannot contain spaces
   * The name cannot end with special characters
   * The length must be between 2-50 characters
5. Add multiple tables by adding the table names under each other in the default.jigx file.
6. [Publish](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/publishing-a-solution.md) the solution to create the tables.
7. In [Jigx Management](/administration/management-overview) browse to your solution and navigate to the [Data](https://docs.jigx.com/data) menu to view your tables. Note that only the tables have been created; next, you must create the [columns and data](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/data/data-providers/dynamic-data/creating-columns-_-data-records.md).

## Considerations

* If *default.jigx* does not exist, simply use the file / new capability to add a new file called *default.jigx* and place it within a folder called databases as per the VS Code folder layout shown in the image at the top of this page.
* If you remove a table in the default.jigx file and publish the solution, the table becomes *unused* in the solution. To include the table and it's records again in the solution, simply add the table back to the default.jigx file and republish the solution.
* A table must be *unused* before you can [delete ](/building-apps-with-jigx/data/data-providers/dynamic-data/deleting-tables)the entire table.

## Examples and code snippets

The following examples with code snippets are provided:

* [Creating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/creating-dynamic-data)
* [Reading Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/reading-dynamic-data)
* [Updating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/updating-dynamic-data)
* [Deleting Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/deleting-dynamic-data) (deletes records in the Dynamic Data table)

## See also

[Creating columns & data records](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/data/data-providers/dynamic-data/creating-columns-_-data-records.md)


# Creating columns & data records

There are three methods to create columns in Dynamic Data tables, and it all depends on where your data comes from if it is pre-existing or new data to be added while the app is in use.

1. Create a jig in Jigx Builder with the columns and save data to your table.
2. Create your columns and data manually in Jigx Management.
3. Import your data from a CSV or JSON file using the [Jigx Management](https://manage.jigx.com/).

{% hint style="warning" %}
Jigx does not recommend storing images in Dynamic Data (via any conversion), as the max file size per record is 350K.
{% endhint %}

## Creating columns and records via Jigx Builder

You can create columns in the table by creating a jig, then define the columns you require in the table by using the Dynamic Data provider's `create` or `save` method. Here are scenarios commonly used to create columns and data from a jig.

### Create a [**form**](https://docs.jigx.com/examples/readme/components/form) and use the [**submit form**](https://docs.jigx.com/examples/readme/actions/submit-form) action

In this scenario, the `formId` in the `component.form` is used in the `submit-form` action to get context to the property `instanceId`. Each value used in the `instanceId` becomes the column's name in the table. The `entity` property specifies the table to add the columns and data to.

{% hint style="info" %}
The columns and data records are created when the form is completed and submitted on the mobile device and not at the time of publishing the solution in Jigx Builder.
{% endhint %}

<figure><img src="/files/P6WW3RyJY6sqYmjqvhEk" alt="Form creates column and data record"><figcaption><p>Form creates column and data record</p></figcaption></figure>

1. Add a `component.form` to a jig and give it a `formId`.
2. Add any of the available form properties, such as [text-field](https://docs.jigx.com/examples/readme/components/text-field), [date-picker](https://docs.jigx.com/examples/readme/components/date-picker), [number-field](https://docs.jigx.com/examples/readme/components/number-field).
3. Add the `submit.form` action.
4. Specify the same `formId` used in the `component.form`.
5. Use the `DATA_PROVIDER_DYNAMIC` with the `create` or `save` method.
6. In the `entity` property, specify the table where the columns and data must be added.
7. Publish the solution.
8. Open the solution in Jigx App and complete the form, click the submit button.
9. Browse to Jigx Management> *solution* >data> *table* to see the new record and columns.

{% code title="employee-form.jigx" %}

```yaml
title: New employee form
description: Capture the new employee details
type: jig.default

header:
  type: component.jig-header
  options:
    height: medium
    children:
      type: component.image
      options:
        source:
          uri: https://unsplash.com/photos/black-smartphone-LNlzd-Y7orw

children:
  - type: component.form
  # used in the submit-form action to get context to the property instanceId.
    options:
    instanceId: form-employee 
      children:
        - type: component.text-field
          instanceId: first_name # becomes the name of the column in table
          options:
            label: First Name
        - type: component.text-field
          instanceId: last_name # becomes the name of the column in table
          options:
            label: Last Name
        - type: component.number-field
          instanceId: contact_number # becomes the name of the column in table
          options:
            label: Mobile number
        - type: component.date-picker
          instanceId: date_of_birth # becomes the name of the column in table
          options:
            label: Date of birth
        - type: component.avatar-field
          instanceId: photo # becomes the name of the column in table
          options:
            label: My profile
        - type: component.signature-field
          instanceId: signature # becomes the name of the column in table
          options:
            label: Sign
        - type: component.email-field
          instanceId: email # becomes the name of the column in table
          options:
            label: Email address

actions:
  - children:
      - type: action.submit-form
        options:
          # Used to get context to the property instanceIds.
          formId: form-employee 
          # Dynamic data provider
          provider: DATA_PROVIDER_DYNAMIC 
          # Creates data and the columns if they do not already exist.
          title: Create Record 
          # Specify the table to create the data and columns in.
          entity: default/employee 
          # Use create or save.
          method: create 
          onSuccess:
            type: action.go-back
```

{% endcode %}

### Use [execute-entity](https://docs.jigx.com/examples/readme/actions/execute-entity) or [execute-entities](https://docs.jigx.com/examples/execute-entities) action to create columns and data records

In this scenario you can use actions in a jig that interact with data to add columns and data records. The columns and data are configured in the `data:` property the action.Use the following actions with the Dynamic Data provider's `create` and `save` methods:

* `action.execute-entity` - used to add a **single** data record
* `action.execute.entities` - used to add **multiple** data

{% tabs %}
{% tab title="execute-entity-action" %}

```yaml
type: action.execute-entity
        options:
          provider: DATA_PROVIDER_DYNAMIC
          entity: default/department
          method: create
          data:
            department_name: =@ctx.current.item.department
            manager_name: =@ctx.current.item.manager
            email: =@ctx.datasources.company_contacts.email
```

{% endtab %}

{% tab title="execute-entities-action" %}

```yaml
type: action.execute-entities
        options:
          provider: DATA_PROVIDER_DYNAMIC
          entity: default/department
          method: create
          data:
            department_name: =@ctx.current.item.department
            manager_name: =@ctx.current.item.manager
            email: =@ctx.datasources.company_contacts.email
```

{% endtab %}
{% endtabs %}

## Creating columns in Jigx Management

### Manually create columns and data records

<figure><img src="/files/HxkFDXOBuhGze27qBWl8" alt="Creating columns"><figcaption><p>Creating columns</p></figcaption></figure>

1. Open [Jigx Management](/administration/management-overview), navigate to your solution and select the **Data** option.
2. Click on the table you want to add a record to in the right-hand **Tables** pane.
3. Click on the blue **New record** button. If you already have records in the table, you will see all existing columns of all records.
4. In the **New record** pane add the data values for each column.
5. **Add new columns** to your record by defining a column name and clicking on the **+** button next to the new column name. As you add data in the column the field displays the type under the entry, such as number, string or boolean.
6. Enter data values in the column fields and click **Save**.

{% hint style="info" %}
You do not need to specify an rid column. Dynamic Data will create a GUID based id column for you automatically. You can optionally view the rid column by selecting the settings button and checking the id column as a visible column.
{% endhint %}

### Importing data using a JSON or CSV file

If you have pre-existing data or a large data set with multiple records to add to a table you can import the data by uploading a CSV or JSON file that will create the columns and populate the data records.

<figure><img src="/files/NXvM9dpcqHp2U3NKr72j" alt="Add data with JSON file"><figcaption><p>Add data with JSON file</p></figcaption></figure>

1. Open [Jigx Management](/administration/management-overview), navigate to your solution and select the **Data** option.
2. Click on the table you want to add a record to in the right-hand **Tables** pane.
3. Click on the **Upload** button at the top of the screen.
4. By default the JSON upload window is shown. You can toggle to upload CSV using the **Switch to CSV** button in the top right. Provide the property name for the unique identifier, otherwise by default the rid (GUID based id) property will automatically be created for you. Drag and drop the file in the designated area.
5. Click **Save**.
6. For CSV uploads select the type of **comma-delimited** used in the **CSV file.** Drag and drop the file in the designated area.
7. Click **Add**.
8. Click **Save**.

## Examples and code snippets

The following examples with code snippets are provided:

* [Creating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/creating-dynamic-data)
* [Reading Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/reading-dynamic-data)
* [Updating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/updating-dynamic-data)
* [Deleting Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/deleting-dynamic-data)

## See Also

[Using Dynamic Data](/building-apps-with-jigx/data/data-providers/dynamic-data/using-dynamic-data)


# Deleting tables

Deleting a table is a critical operation that should be performed with caution. Before proceeding with the deletion, please back up the table data, as it cannot be recovered once deleted.

<figure><img src="/files/R0ucheUU7OPjJX7EV5rA" alt="Deleting tables"><figcaption><p>Deleting tables</p></figcaption></figure>

To delete a table, follow these steps:

1. In Jigx Builder remove a table from the **default.jigx** file and publish the solution.
2. In Jigx Management as the solution `owner` navigate to the solution and select the **Data** option.
3. The table is visible in the **Unused** tab.
4. Optional: make a table backup by clicking the **Download** button. A JSON file containing the data records is downloaded.
5. Click the **Delete Table** button at the top of the screen.
6. Confirm you want to delete the table.

### What you need to know about deleting tables

* You can only delete a table not currently used in a solution.
* Deleting tables will delete all data records in the table, which is not recoverable. Delete tables with caution.
* Only the solution `owner` can delete a table.
* The *Unused tab* is only visible to the solution `owner`.
* Removing a table from default.jigx file in Jigx Builder and publishing the solution means the table is no longer used in the solution. In Jigx Management under Data, the table moves to the *Unused tab*.
* If there are no unused tables the *Unused tab* is not visible in the Data option.
* [Row Level Security](/building-apps-with-jigx/data/data-providers/dynamic-data/deleting-tables) still applies to the data records in the unused table. Even as the solution owner, you will only see data records you are authorized to see. It is important to note that even though you cannot see all the data, deleting the table will delete *ALL* records and the table.
* You can choose to only delete the records in the unused table by selecting the checkbox in front of the record. The **Delete Selected** button appears at the top.
* Make a backup of the unused table's data by clicking the **Download** button at the top of the screen. The data is downloaded in a JSON file. If needed, you can reuse the data by importing (upload) data into a new table. *Important*: the data in the downloaded JSON file is the data you are authorized to see.
* Existing records in the unused table can be edited, but you cannot add new records.
* [Authorized Users (RLS)](/building-apps-with-jigx/data/data-providers/dynamic-data/deleting-tables) access can be applied to existing records in the unused table.
* You cannot apply [Data policies](/building-apps-with-jigx/data/data-providers/dynamic-data/deleting-tables) to unused tables.
* If you want to use the table in the solution again, simply add the table back to the *default.jigx* file and publish the solution. The table moves back to the **Available** tab in the Jigx Management>Data.


# Using Dynamic Data

Once you have created the Dynamic Data [tables](/building-apps-with-jigx/data/data-providers/dynamic-data/creating-tables) as well as, [columns and data records](/building-apps-with-jigx/data/data-providers/dynamic-data/creating-columns-data-records) the data can be used in multiple places in a solution.

Dynamic Data can be:

* **Protected** - add Row Level Security (RLS) through security policies and authorization. For more information, see [Row Level Security](/administration/solutions/row-level-security), [Data policies](/administration/solutions/row-level-security/data-policies) and [Authorized users](/administration/solutions/row-level-security/authorized-users).
* **Created** - create new records in Dynamic Data tables, for example, adding new employees. For code examples and snippets, see [Creating Dynamic Data](https://docs.jigx.com/examples/creating-dynamic-data).
* **Read** - Read the data to populate a [form](https://docs.jigx.com/examples/readme/components/form), [list](https://docs.jigx.com/examples/readme/components/list), show a [location](https://docs.jigx.com/examples/readme/components/location) and more. For code examples and snippets, see [Reading Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/reading-dynamic-data).
* **Updated** -update existing records in Dynamic Data tables, for example, updating an employee's address. For code examples and snippets, see [Updating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/updating-dynamic-data).
* **Deleted** - delete existing records in Dynamic Data tables, for example, remove old contacts or out-of-stock products. For code examples and snippets, see [Deleting Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/deleting-dynamic-data).

### As a datasource

The Dynamic Data provider is used in Jigx Builder in the SQLite datasource either inside a single jig (locally) or under the datasources folder structure (global), allowing the data to be called once and reused throughout the solution in multiple jigs. Write SQLite queries to return the exact data you need to work with.

{% code title="sqlite-datasource-dd" %}

```yaml
# Use the sqlite datasource with the dynamic data provider.
type: "datasource.sqlite"
options:
  provider: DATA_PROVIDER_DYNAMIC
  entities:
    - entity: default/employee
  # Write sqlite query syntax to return data needed in the jig/solution.
  query: |
    SELECT 
      id, 
      '$.firstname', 
      '$.lastname', 
      '$.photo', 
      '$.birthdate', 
      '$.gender', 
      '$.email', 
      '$.phone', 
      '$.street', 
      '$.city', 
      '$.state', 
      '$.country', 
      '$.category', 
      '$.modify' 
    FROM [default/employees] WHERE '$.category' = "employee-detail"
```

{% endcode %}

### In components

Once you have created the `datasource.sqlite` with the Dynamic Data provider as shown above, the data is referenced in components using [Expressions](/building-apps-with-jigx/logic/expressions), such as `=@ctx.datasources.employee`

```yaml
children:
  - type: component.form
    options:
      children:
        - type: component.dropdown
          instanceId: dropdown-in
          options:
            # use an expression to reference the dynamic data datasource to use 
            # in the form.
            data: =@ctx.datasources.employee
            label: Select employees
            isSearchable: true
            item:
              type: component.dropdown-item
              instanceId: =@ctx.current.item.firstname
              options:
                # use an expression to reference the exact data entry to use 
                # in the drop-down component on the form.
                value: =@ctx.current.item.firstname
                title: =@ctx.current.item.firstname
                subtitle: =@ctx.current.item.lastname
                leftElement:
                  element: avatar
                  text: ""
                  uri: =@ctx.current.item.photo
```

### In actions

**Execution** actions are designed to interact with specifically with data. The following actions can be used with the Dynamic Data provider either to create, update, delete, or sync data.

* [execute-entity](https://docs.jigx.com/examples/readme/actions/execute-entity)
* [execute-entities](https://docs.jigx.com/examples/readme/actions/execute-entities)
* [submit-form](https://docs.jigx.com/examples/readme/actions/submit-form)
* [sync-entities](https://docs.jigx.com/examples/readme/actions/sync-entities) for getting data to the device.

**Events** actions execute after an event is performed by a user or device. This event can be configured to use the Dynamic Data provider, for example, when refreshing a list jigby pulling down (onRefresh) use the `action.sync-entities` with the provider to refresh the data in the list. The following event actions are available.

* onRefresh
* onFocus
* onPress
* onLoad (only on index.jigx)
* onChange
* onDelete
* onButtonPress (only on calendar jigs)

For the complete list and code examples of available actions, see [actions](https://docs.jigx.com/examples/readme/actions).

### Examples and code snippets

The following examples with code snippets are provided:

* [Creating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/creating-dynamic-data)
* [Reading Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/reading-dynamic-data)
* [Updating Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/updating-dynamic-data)
* [Deleting Dynamic Data](https://docs.jigx.com/examples/readme/data-providers/dynamic-data/deleting-dynamic-data)


# Dynamic files

Dynamic Files extend Jigx's Dynamic Data entities to include file references, allowing files to be securely stored and associated with records. Files are physically stored in Amazon S3, offering a combination of simplicity, security, and portability.

For example:

* For an expense claim scenario, create an *Expense* record in Dynamic Data.
* Capture the expense detail and attach the receipt file to the *Expense* record.

## Key Functionalities

### Uploading Files

* The `create` method of the `Dynamic Provider` uploads files to Amazon S3.
* One file is linked/associated with one record, which means that the `execute-entity` action is used for the upload.
* Use the [media-field](https://docs.jigx.com/examples/readme/components/media-field) component to select files for upload or upload a file to the record in *Management>solution>data>table>record>file*.
* Specify a `localPath` for the file.
* Specify a `fileName` with the file extension. If a `fileName` is not provided, the system extracts it from the `localPath`.

{% code title="upload-files" %}

```yaml
actions:
  - children:
      - type: action.action-list
        options:
          title: Submit
          isSequential: true
          actions:
            - type: action.execute-entity
              options:
                provider: DATA_PROVIDER_DYNAMIC
                entity: default/expenses
                # Use the create method to upload files.
                method: create
                goBack: previous
                data:
                  expenseitem: =@ctx.jig.components.expenseitem.state.value
                  expenseamount: =@ctx.components.expenseamount.state.value
                # Specify the file to be uploaded.
                file: 
                  localPath: =@ctx.components.expenseimage.state.value
```

{% endcode %}

### Deleting Files

* Delete a file by executing the standard `delete` entity method in an `execute-entity` action.
* To delete a file from an entity record, you call `save` or `update` and set the `file` property to `null`, or `localPath` to `null`.

{% code title="delete-files" %}

```yaml
onPress: 
  type: action.execute-entity
  options:
     provider: DATA_PROVIDER_DYNAMIC
     entity: default/expenses
     # Use the update method to delete files.
     method: update
     goBack: stay
     data:
       id: =@ctx.current.item.id
     # Set the file to null which deletes the file.  
     file: null                                     
```

{% endcode %}

### Downloading Files

* Files can be downloaded via the `download` method using the entity `id` in an `execute-entity` action.
* The file is downloaded to a local cache on the device, and the entity record's `localPath` property updates to reflect the local download location.
* You will not be able to browse to it on the device.
* Use a `datasource` query to access the downloaded file using properties available on a downloaded file. See the available properties in the *datasource-query* code example below. The datasource allows you to use the thumbnail URI from the server, for faster loading and lower bandwidth.The full file for high-resolution, detailed viewing or editing. As well as storing the file in the cache (localPath) to cater for offline use, and repeated requests for the same file. Depending on your requirement will determine which properties to include in the datasource query.

{% tabs %}
{% tab title="download-files" %}

```yaml
actions:
  - type: action.execute-entity
    options:
      provider: DATA_PROVIDER_DYNAMIC
      entity: default/expenses
      # To download the file, you execute the download method,
      # and provide the entity id.
      method: download
      goBack: stay
      data:
       id: =@ctx.current.item.id              
```

{% endtab %}

{% tab title="datasource-query" %}

```yaml
# File properties available to query a downloaded file.
datasources:
  expenses-ds:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_DYNAMIC
      entities:
        - default/expenses
      query: |
        SELECT
          id,
          '$.expenseitem',
          json_extract(file, '$.localPath') as localPath,
          json_extract(file, '$.fileName')  as filename,
          json_extract(file, '$.uploadProgress')  as uploadProgress,
          json_extract(file, '$.downloadProgress')  as downloadProgress,
          json_extract(file, '$.hash'),
          json_extract(file, '$.status') as status,
          json_extract(file, '$.contentType'),
          json_extract(file, '$.contentLength'),
          json_extract(file, '$.thumbnail.base64') as thumbnail,
          json_extract(file, '$.thumbnail.contentType'),
          json_extract(file, '$.thumbnail.contentLength')
        FROM [default/expenses]
        ORDER BY '$.expenseitem'
```

{% endtab %}
{% endtabs %}

## File Status Tracking

* A system table, `_fileStatus`, tracks a file's upload or download progress.
* This can be used to `join` or `query` directly to check the status of a file operation.
* The progress column is updated as the file is uploaded/downloaded.
* Errors during operations update the status to `failed`, and these can be retried using `action.retry-queue-command` with the corresponding `commandId` from the `_fileStatus` table.

{% tabs %}
{% tab title="file-progress" %}

```yaml
title: File Progress
type: jig.list
icon: move-down
  
data: =@ctx.datasources.file-status-ds
item:
  type: component.list-item
  options:
    title: =@ctx.current.item.fileName
    color:
      - color: color11
        when: =(@ctx.current.item.progress >= 1)
      - color: color2
        when: =(@ctx.current.item.progress >= 75 and @ctx.current.item.progress < 100)
      - color: color1
        when: =(@ctx.current.item.progress < 75 and @ctx.current.item.progress > 30)
      - color: color8
        when: =(@ctx.current.item.progress <= 30)
    # Display the progress of uploading files.    
    description: =@ctx.current.item.progress & '%'
    label:
      title: =@ctx.current.item.uploadstatus
    progress: >
      =@ctx.current.item.progress != null ? (@ctx.current.item.progress / 100) :
      0
    swipeable:
      left:
        - color: primary
          icon: pencil-2
          label: Retry
          onPress:
            # Configure the retry action to process the files on the queue.
            type: action.action-list
            options:
              isSequential: true
              actions:
                - type: action.retry-queue-command
                  options:
                    id: =@ctx.current.item.commandId
```

{% endtab %}

{% tab title="datasource" %}

```yaml
datasources:
  file-status-ds:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      # Query the system _fileStatus properties to configure the progress of files. 
      entities:
        - _fileStatus
        - default/expenses
      query: |
        SELECT
          e.id,
          '$.expenseId',
          e.timestamp,
          json_extract(e.file, '$.localPath') as localPath,
          json_extract(e.file, '$.fileName')  as fileName,
          fs.commandId as commandId,
          fs.progress as progress,
          fs.state as uploadstatus
        FROM [_fileStatus] AS fs
        LEFT JOIN [default/expenses] AS e ON
        e.id = fs.id
        ORDER BY e.timestamp
      queryParameters:
        expenseId: =@ctx.jig.inputs.expenseId
```

{% endtab %}
{% endtabs %}

## File Permissions

Permissions are managed at the solution level in Jigx Management and Jigx Builder based on a records [Row Level Security](/administration/solutions/row-level-security):

* `Ownership` and `membership` are specified at the record level.
* Multiple `owners`/`groups` can be assigned.

{% hint style="info" %}
For optimal performance and security with Dynamic Files, enable **owner-only** policies on the **read** method for any tables containing dynamic files. This ensures that files are only downloaded to the devices of users who own the records, rather than syncing all files to every user's device.
{% endhint %}

See [Row Level Security](/administration/solutions/row-level-security) and [Data policies](/administration/solutions/row-level-security/data-policies) for more information.

**Permissions Configuration Example:**

```yaml
actions:
  - children:
    - type: action.execute-entity
      options:
        title: Submit Expense
        provider: DATA_PROVIDER_DYNAMIC
        entity: default/expenses
        # Use the create method to upload files.
        method: create
        goBack: previous
        data:
          expenseitem: =@ctx.jig.components.expenseitem.state.value
          expenseamount: =@ctx.components.expenseamount.state.value
        # Specify the file to be uploaded.
        file: 
          localPath: =@ctx.components.expenseimage.state.value  
          fileName: =@ctx.components.fileName.state.value 
        # Set the permissions (Row level security) on the record, 
        # the permissions will be applied to the file.    
        authorized:
          owners:
            - "frank@global.com"
          members: 
            - "finance"
```

## Thumbnails and File Display

Consider when and how the files are used in the app. Thumbnails are useful when displaying a preview or list view where speed matters more than quality and you want to minimize bandwidth and memory usage. The code snippet below uses the thumbnail (base64 string) if available, otherwise, it uses the local file path. If neither is available, it returns nothing (null). The datasource query includes the thumbnail and local path:

{% tabs %}
{% tab title="YAML" %}

```yaml
leftElement:
  element: avatar
  text: ""
  uri: |
    =@ctx.current.item.thumbnail != null ? 'data:image/png;base64,' & @ctx.current.item.thumbnail :
    @ctx.current.item.localPath != null ? @ctx.current.item.localPath
```

{% endtab %}

{% tab title="datasource" %}

```yaml
# File properties available to query to use in the expression file.
datasources:
  expenses-ds:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_DYNAMIC
      entities:
        - default/employees
      query: |
        SELECT
          id,
          '$.avatar',
          json_extract(file, '$.localPath') as localPath,
          json_extract(file, '$.fileName')  as filename,
          json_extract(file, '$.thumbnail.base64') as thumbnail
        FROM [default/employees]
```

{% endtab %}
{% endtabs %}

## Jigx Management

Files and their detail are visible in Management and are associated with a record.

<figure><img src="/files/7pFF4JCtfyoqZ2GACi56" alt="Dynamic Files" width="563"><figcaption><p>Dynamic Files</p></figcaption></figure>

1. Locate the [Data](/administration/solutions/data) tab.
2. Click on a record and select the **File** tab.
3. The file **status**, **thumbnail**, **name**, **content type** and **size** are displayed.
4. To download the file from Management, use the **Download file** link at the top of the record.
5. To delete a file, click the **X** next to the file preview.
6. To view the file thumbnail in the table, ensure **File** is checked in the **Column settings** pane.

## Examples and code snippets

1. [Upload a file](https://docs.jigx.com/examples/readme/data-providers/dynamic-files/upload-a-file)
2. [Download a file](https://docs.jigx.com/readme/data-providers/dynamic-files/download-a-file)
3. [Delete a file](https://docs.jigx.com/examples/readme/data-providers/dynamic-files/delete-a-file)
4. [Status of a file](https://docs.jigx.com/examples/readme/data-providers/dynamic-files/status-of-a-file)


# Microsoft Azure SQL

{% hint style="danger" %}
Best practice for production apps is to use REST as the data layer to access data and not directly integrate to SQL using the SQL data provider. The SQL data provider will be squiggled in blue to indicate it is not recommended, together with a message to use [REST](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql) instead. See [REST endpoints from Azure SQL](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql) for more information.
{% endhint %}

{% embed url="<https://vimeo.com/833354418?share=copy>" %}

Jigx integrates with Microsoft Azure SQL through the SQL data provider, allowing you to select or insert data from an Azure SQL database. This includes Microsoft Azure SQL and Microsoft SQL Server on-premise.

## Use the SQL data provider

To use the SQL data provider in Jigx , follow these high-level steps:

1. **Choose your Azure SQL database**
   * Identify the SQL table you will use as your data source. Ensure you understand its structure and data.
2. **Configure the SQL connection**
   * [Configure a new Azure SQL connection ](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql/configuring-the-sql-connection)for the solution in Jigx Management before adding the Jigx cloud IP addresses to the allowlist IP addresses in Azure SQL.
3. **Define the SQL query or stored procedure in a Jigx function in Jigx Builder**
   * Navigate to the [functions](/building-apps-with-jigx/data/data-providers/rest) folder in Jigx Builder.
   * Use [IntelliSense](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/editor.md) to configure the SQL data provider.
   * Enter the name of the connection set up in Jigx Management.
4. **Define data methods in the function**:
   * Configure a method to use to interact with the data. There are two options:
     * EXECUTE - used with stored procedures
     * QUERY - used to write SQL queries
   * For each method, create a new function file.
5. **Reference the Jigx functions in jigs:**
   * Reference the function in your jigs. This step is crucial for integrating the SQL data seamlessly into your Jigx solution.
6. **Publish your solution**:
   * [Publish your solution](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/publishing-a-solution.md) and use the app to interact with the SQL data provider.
7. **Test the Data Provider**:
   * Use Jigx Builder [developer tools](https://github.com/jigx-com/jigx-docs/blob/main/docs/building-apps-with-jigx/jigx-builder-code-editor/debugging.md) to test the data provider configurations. Check if the data provider can connect to SQL successfully and perform operations like SELECT, INSERT, UPDATE or DELETE data.

Following these steps, you can effectively integrate external Azure SQL data into your Jigx solutions, allowing you to enhance your apps with data and functionalities from diverse external sources.

## Connections

For security, all SQL calls from a Jigx App are routed through the Jigx cloud to the Microsoft Azure SQL instance. No data is stored in the Jigx cloud and is only used as a routing proxy for IP allowlisting in Microsoft Azure SQL. The [Configuring the SQL Connection](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql/configuring-the-sql-connection) section explains the steps to configure a connection for the Azure SQL database in Jigx cloud, as well as configuring the IP allowlisting in Azure SQL for Jigx cloud.

## Jigx functions

Data from remote data sources such as Azure SQL or REST web services are stored in a local SQLite database on the device from where it is used in the Jigx application.

To fetch data onto the device and into the local SQLite table, Jigx executes a function that sends an SQL command to Azure SQL. This command can include an SQL statement that will be executed or a stored procedure.

The function's result is returned to the Jigx app on the device as a JSON array. Each record in the array is stored as a row in the local SQLite database.

The Jigx solution uses SQL as a query language to access and manipulate data in the local SQLite database.

Once functions are published in a Jigx solution, you can preview the function in Jigx Management under the solution's SQL functions option. See [Viewing and testing SQL data using the Jigx Management](/administration/solutions/sql-functions) for more information.

## SQL function components

<table data-header-hidden><thead><tr><th width="156.984375"></th><th></th></tr></thead><tbody><tr><td><strong>Provider</strong></td><td><code>DATA_PROVIDER_SQL</code> for making calls to Microsoft Azure SQL.</td></tr><tr><td><strong>Connection</strong></td><td>Provide the name of the connection configured in for the Azure SQL database.</td></tr><tr><td><strong>Methods</strong></td><td><p>Jigx supports the following methods in the provider:</p><ul><li>EXECUTE - used to execute a stored procedure</li><li>QUERY - used to write a SQL statement such as SELECT, INSERT, DELETE, and UPDATE.</li></ul></td></tr></tbody></table>

The following describes the options available when configuring a SQL function call.

{% tabs %}
{% tab title="Javasql- function-queryScript" %}

```yaml
# Jigx SQL function executing a query to select all customers from a table.
provider: DATA_PROVIDER_SQL
# Use manage.jigx.com to configure a SQL connection.
connection: customer.azure
# Use SQL statements to interact with the data in SQL. 
method: query 
query: |
  SELECT
    id,
    first_name,
    last_name,
    email,
    phone_number,
    address_line1,
    address_line2,
    city,
    state,
    zip_code,
    country
  FROM
    customers
```

{% endtab %}

{% tab title="sql-function-execute" %}

```yaml
# Jigx SQL function executing a stored procedure to select all customers 
# from a table.
provider: DATA_PROVIDER_SQL
# Use manage.jigx.com to configure a SQL connection.
connection: customer.azure
# Provide the SQL stored procedure to execute.
method: execute 
procedure: sp_GetAllCustomers
```

{% endtab %}
{% endtabs %}

## Parameters

Function parameters are used to pass data into the function definition from the jig that uses the function. See the [Datasources](/building-apps-with-jigx/data/datasources) section of the documentation. Parameters are defined by naming them and describing the properties of that parameter. Parameter names are used when the parameters are referred to in the SQL query.

### Function parameter properties

### Location

The location determines how the parameter will be applied in the SQL call:

* **input:** the parameter is used as an input, for example when creating a record.
* **output:** the parameter is used as an output.
* **both:** the parameter is used as an input and output.

### Type

Type is specific to the SQL call being made. Most types are defined as strings.

### Required

The required value is either `true` or `false`. This determines whether the parameter needs to be set when the function is used in a jig's datasource. This determines if the SQL call requires this parameter. If so, set this property to `true`, alternatively if the parameter is optional, you can set it to `false`.

### forRowsWithValues

By default the return SQL call replaces previous data in the SQLite database. The `forRowsWithValues` property allows you to update specific values in the SQLite database instead of replacing all rows, providing a better user experience. The `forRowsWithValues` property specifies a key-value pair where the key is a json\_extract() column in the SQLite table that will be matched by the value. Only rows that match these criteria will be updated. The object will be added as a new row to the collection if a match isn't found. You can have multiple key-value pairs specified under `forRowsWithValues`. Think of this as a WHERE clause that Jigx uses when it adds the result of the SQL call to the SQLite table.

### forRowsInRange

Similar to `forRowsWithValue` but instead of matching rows by value the `forRowsInRange` specifies a key-value pair where the key is a json\_extract() column in the table that a value range will match. Only rows that match these criteria will be updated. The object will be added as a new row to the collection if a match isn't found. You can have multiple key-value pairs specified under `forRowsInRange`. Think of this as a WHERE clause with a BETWEEN that Jigx uses when it adds the result of the SQL call to the table.

### forRowsWithMatchingIds

Similar to `forRowsWithValue`, when `forRowsWithMatchingIds` is specified, Jigx will perform an upsert on a specific id. The `outputTransform` MUST contain a field called id. This id will be used to match the id column in the database; if a record with this id exists, it will be updated. If no match is found, the record will be inserted. No deletion is performed when `forRowsWithMatchingIds` is used.

### Conversions

Jigx stores files as local files on the device and only saves the file URI to the file in the datastore/state. When a component needs the binary data, it can read the local file from the file URI. To enable the handling of files, you can convert files from base64, data-uri, or buffer to local-uri. See [File handling](/building-apps-with-jigx/data/file-handling) for more information.

```yaml
provider: DATA_PROVIDER_SQL
method: query
connection: customer.azure
query: SELECT TOP(@top) Id, FirstName, LastName, AvatarBase64, AvatarDataUri, AvatarBuffer FROM Employee
parameters:
  top:
    location: input
    required: false
    type: number
    value: 10
conversions:
  - property: AvatarBuffer
    from: buffer
    to: local-uri
  - property: AvatarBase64
    from: base64
    to: local-uri
  - property: AvatarDataUri
    from: data-uri
    to: local-uri
```

## Referencing a Jigx function

Here is an example of a Jigx solution screen that calls the function in the `OnFocus` event with a `sync-entities` action to sync the data from SQL to the local SQLite database, which returns the customers' details.

{% code title="list-customers.jigx" %}

```yaml
# A sample list that uses a SQL function to return & display a list of customers from Azure SQL
title: List Customers
description: Show a list of all customers in a SQL database.
type: jig.list
icon: contact
# Header section displaying an image at the top of the screen
header:
  type: component.jig-header
  options:
    height: medium
    children:
      type: component.image
      options:
        source:
          uri: https://images.unsplash.com/photo-1553413077-190dd305871c?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1035&q=80

# onFocus is triggered whenever the jig is displayed. The sync-entities action
# calls the Jigx SQL function and populates the local SQLite tables on the
# device with the data returned from Azure SQL.
onFocus:
  type: action.sync-entities
  options:
    provider: DATA_PROVIDER_SQL
    entities:
      - entity: customers
        function: get-customers

# The mydata data source selects the data from the local SQLite database.
datasources:
  mydata:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL

      entities:
        - entity: customers

      query: |
        SELECT
          id,
          '$.first_name',
          '$.last_name',
          '$.email',
          '$.phone_number',
          '$.address_line1',
          '$.address_line2',
          '$.city',
          '$.state',
          '$.zip_code',
          '$.country'
        FROM
          [customers]

# The list and its list items are configured below. This is a list jig; 
# therefore, its properties, such as data and item, are top-level properties.
# The data property binds the list to a specific data source.
data: =@ctx.datasources.mydata
# The item property specifies the list item type and its attributes.
item:
  type: component.list-item
  options:
    title: =@ctx.current.item.first_name & ' ' & @ctx.current.item.last_name
    subtitle: =@ctx.current.item.email
    description: |
      =@ctx.current.item.address_line1 & ' ' & 
        @ctx.current.item.city & ' ' & 
        @ctx.current.item.state  & ' ' & 
        @ctx.current.item.zip_code
    label:
      title: =@ctx.current.item.country
    leftElement:
      element: avatar
      # The text property is specified using a JSONata expression 
      # that builds a two-letter string by concatenating the first letters 
      # of the customer's first and last names.
      text: =$substring(@ctx.current.item.first_name,0,1) & $substring(@ctx.current.item.last_name,0,1)
    divider: solid
```

{% endcode %}

We recommend navigating to the Management Console to test your function at this point. This allows you to ensure that the function is configured correctly, connected to SQL Server, and returns results. You can find out more about capabilities for viewing and testing SQL functions from the Management Console at this location. [Viewing and testing SQL data](https://docs.jigx.com/sql-functions) using the Jigx Management Console

## Examples and code snippets

The following examples with code snippets are provided:

1. A [SQL database script](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql) to create the tables and stored procedures used in the example. These scripts should be executed against an existing database in your Azure SQL environment.
2. [List customers (SELECT)](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql)
3. [List a single customer (SELECT)](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql)
4. [Create a customer (INSERT)](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql)
5. [Update a customer (UPDATE)](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql)

## See Also

* [File handling](/building-apps-with-jigx/data/file-handling)
* [Offline remote data handling](/building-apps-with-jigx/data/offline-remote-data-handling)


# Syncing SQL & loading local Data

<figure><img src="/files/XW6o6vZyhr3SxnwWXcjm" alt="" width="563"><figcaption></figcaption></figure>

Key:

1. **Sync data from the cloud** Use a `sync-entities` action to fetch data from the cloud and store it in the local SQLite database. Use the `onLoad`, `onFocus`, `onRefresh`, or any other event where actions are defined.
2. **Load data from SQLite to use on a jig** Use the `DATA_PROVIDER_LOCAL` in the datasource defined in the jig or a global datasource to execute an SQLite query.
3. **Save data to SQLite ONLY** To save data locally only and not sync to the cloud, use an `execute-entity` action with the `DATA_PROVIDER_LOCAL`.
4. **Save data to SQLite and sync data to the cloud** Update the local SQLite and sync to the cloud in a single action to ensure high-performing user experiences without lag. Use `execute-entity` or `execute-entities` actions with `DATA_PROVIDER_REST` or `DATA_PROVIDER_SQL`. Specify the function call to make, the local entity/table to update, and the method to perform on the local table. If the method is an update, delete, or save, specify the record's ID.
5. **Save data to the cloud ONLY** Use `execute-entity` or `execute-entities` actions with `DATA_PROVIDER_REST` or `DATA_PROVIDER_SQL`. Set the method to functionCall and specify the function to be called. The local tables will not be updated; you must sync the data from the cloud before it is available to display on a jig.

{% hint style="info" %}
Dynamic Data automatically syncs its data with the cloud when server-side or device-side updates are made to the tables, using `DATA_PROVIDER_DYNAMIC`.
{% endhint %}

## Using sync-entities action

1. Use the `sync-entities` action to sync data from the remote data store (REST and SQL) to the local SQLite data provider. Syncing data locally results in high performance with minimal lag and ensures that all data is available in the app when the device is offline.
2. Best practice is to configure a global action, the `sync-entities` action, with the REST or SQL data provider, allowing reuse throughout the solution.
3. Add the global sync action to the `onFocus` and `onLoad` events in the index.jigx file ensures data is synced to the local data provider as soon as the app loads or is focused on the device.
4. Add the global sync action to the `onRefresh` or `onFocus` events in a jig when data is changed, for example, on the list of customers, this ensures that when a new customer is created, the list is updated immediately when navigating to it or refreshing the list with a downward swipe.

## Using Execute-entity/entities action

There are two options when using the `execute-entity` and `execute-entities` actions with remote data such as REST or SQL.

1. **To update BOTH the local SQLite table and the remote data store (REST and SQL)**. To update the local table, specify CREATE, UPDATE, or DELETE methods in the `method` property of the data provider, then specify the function to use in the `function` property, and under `parameters` specify the exact data to be updated in the remote data store (REST/SQL). Under `data` specify the exact data to be updated in the local SQLite table. After execution, a tempId is created, and then it is synced to the local table.

<figure><img src="/files/wuCVSREIPPaRAPdxEcBy" alt="Update local and REST providers"><figcaption><p>Update local and REST providers</p></figcaption></figure>

1. **To ONLY update the remote data store (REST and SQL)**. To update the remote data store specify `functionCall` in the method property. Then specify the function to be called in the `function` property and under `parameters` specify the exact data to be updated. Note that the data will not be visible on the jig until a `sync-entities` action is executed.

<figure><img src="/files/fdqrjX2iYBgKorWVQcrK" alt="Only update REST Service"><figcaption><p>Only update REST Service</p></figcaption></figure>

### Consideration

* Using the `save` method in `execute-entity/entities` action will perform an upsert in the local SQLite table.
* Dealing with offline remote data is fundamental to ensuring data synchronization and consistency between the mobile app and the remote data source, allowing users to continue using the app and performing actions without interruption. [Offline remote data handling](/building-apps-with-jigx/data/offline-remote-data-handling) explains how to configure solutions to deal with data when the device is offline.

## Using local data provider in a jig's datasources

1. Once the data has been synced using the `sync-entities` action the data is available in the local data provider.
2. Reference the local data provider in the jig's `datasource` property to define the data required in the jig.
3. Write a SQLite query to define the exact data required.
4. Use Intellisense and expressions to reference the specific datasource values to use in each component, such as `data: =@ctx.datasources.customers`

<figure><img src="/files/RXPIwc1CZmrcjnTqoNda" alt="Local data provider"><figcaption><p>Local data provider</p></figcaption></figure>


# Configuring the SQL Connection

{% hint style="danger" %}
Best practice for production apps is to use REST as the data layer to access data and not directly integrate to SQL using the SQL data provider. The SQL data provider will be squiggled in blue to indicate it is not recommended, together with a message to use [REST](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql/configuring-the-sql-connection) instead. See [REST endpoints from Azure SQL](/building-apps-with-jigx/data/data-providers/microsoft-azure-sql/configuring-the-sql-connection) for more information.
{% endhint %}

Jigx will route all calls to Azure SQL Server from a Jigx mobile app through the Jigx cloud. No data is stored or cached in Jigx cloud. The encrypted SQL connection information is stored in non-user-readable secure storage in Jigx cloud and allows for IP allowlisting for Azure SQL database servers.

To complete these steps, the user will need Jigx credentials with **admin** privileges for the solution being configured and **Azure SQL administrative credentials** to configure the allowlisted IP addresses for the Azure SQL Server being used in the Jigx solution.

Following these steps to configure a new Azure SQL connection for the solution in Jigx cloud before adding the Jigx cloud IP addresses to the allowlisted IP addresses in Azure SQL.

## Creating an Azure SQL connection in Jigx Cloud

1. Sign in to Jigx management at <https://manage.jigx.com> and navigate to the solution being configured.
2. Click on the **Connections** menu option on the left of the solution screen.

<figure><img src="/files/0lZjamYVj6ca4jNyFQ4c" alt="Connections in Jigx Management"><figcaption><p>Connections in Jigx Management</p></figcaption></figure>

3\. Click **Add Connection** on the top right of the Connections screen.

<figure><img src="/files/bLtMIttmERBVDx0qxz97" alt="Add a new connection" width="375"><figcaption><p>Add a new connection</p></figcaption></figure>

4\. Enter the connection information for the new Azure SQL Connection.

<figure><img src="/files/vU7lQ30wRCQ0W6bP1WUV" alt="Azure SQL connection" width="356"><figcaption><p>Azure SQL connection</p></figcaption></figure>

* In the **Name** field, enter your server's name, which will be the connection name Jigx functions will refer to when you create SQL functions. We recommend that this be the same as your SQL instance, for example, jigx1.database.windows.net.
* In **Type** – Select Azure SQL for both Azure SQL and on-premise SQL Servers.
* Optionally enter any descriptive text in the **Description** field.
* In **Server** enter the name of Azure SQL or SQL on-premise database server. The Azure administrator or database administrator will assist with this name.
* In **Database** enter the name of the SQL Server database you want to connect to.&#x20;
* In **User** enter the user name that will connect to SQL Server.
* In **Password** enter a valid password for the SQL Server.
* In **Options** configure other connection options such as non-standard ports or other specific connection information that the database server may need.&#x20;

5\. Before saving or testing the connection, click the **IP allowlist** link in the middle of the new connection screen. Note the two IP addresses listed. The calls from Jigx Cloud to Azure SQL will always originate from one of these IP addresses. These IP addresses will be added to the Azure SQL Server.

{% hint style="info" %}
These IP addresses will vary depending on the Jigx cloud region being used.
{% endhint %}

<figure><img src="/files/qz7lyOLKb6Z0Z6Za05tc" alt="Jigx IP address" width="342"><figcaption><p>Jigx IP address</p></figcaption></figure>

6\. Navigate to the administrative portal for the Azure SQL Server instance hosting the database used in the Jigx solution. Under the Security section, select **Networking**. Please refer to [Azure SQL firewall connection documentation](https://learn.microsoft.com/en-us/azure/azure-sql/database/firewall-configure?view=azuresql) for detailed instructions.

<figure><img src="/files/oLhbkpJaJGYPOBNM5WHC" alt="Azure administrative portal" width="188"><figcaption><p>Azure administrative portal</p></figcaption></figure>

7\. Add the two Jigx IP addresses to the IP addresses allowlist for this Azure SQL instance.

<figure><img src="/files/UL1iCgVBIJEMpz5ye1t5" alt="Adding IP addresses"><figcaption><p>Adding IP addresses</p></figcaption></figure>

8\. In Jigx Management, click **Test connection**. If all the settings are configured correctly, the connection will succeed. Click **Save**.

<figure><img src="/files/u7hpcFmQpet8jM1aP7eE" alt="Testing SQL connection" width="375"><figcaption><p>Testing SQL connection</p></figcaption></figure>

9\. The connection can now be used in your Jigx project to execute SQL queries or stored procedures to read and write data to Azure SQL.


# REST endpoints from Azure SQL

Best practice for production apps is to use REST as the data layer to access data and not directly integrate to SQL using the SQL data provider. The SQL data provider will be squiggled in blue to indicate it is not recommended, together with a message to use [REST](/building-apps-with-jigx/data/data-providers/rest) instead.

1. Configure your Azure SQL database to call external REST endpoints. To learn how to call external REST endpoints from Azure SQL databases, read:
   * Microsoft Learn: [sp\_invoke\_external\_rest\_endpoint (Transact-SQL)](https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-invoke-external-rest-endpoint-transact-sql?view=azuresqldb-current\&tabs=request-headers)
   * GitHub sample: [azure-sql-db-invoke-external-rest-endpoints](https://github.com/Azure-Samples/azure-sql-db-invoke-external-rest-endpoints)
2. Now use the [REST data provider ](/building-apps-with-jigx/data/data-providers/rest)to configure your Jigx solution to integrate with your Azure SQL data.


# Microsoft OneDrive

Microsoft OneDrive connects you to all your files by storing and protecting your files, sharing them with others, and getting to them from all your devices. Jigx app solutions integrate with OneDrive allowing you to interact with your existing files or add new files. No files are stored in the Jigx cloud as they are routed to OneDrive.

### **Authorization requirements**

A Graph OAuth token is required for a solution to integrate with OneDrive. Set the Graph OAuth token in the [Credentials](/administration/solutions/credentials) tab in Jigx Management. The Graph OAuth token must have the following permissions:

* Files.ReadWrite.All (My Files)
* Sites.ReadWrite.All (Shared Folders)

The *Shared* folder operations rely on permissions granted by the person who shared the folder.

### Integration support includes:

* **Folder sync** - syncs metadata and not file contents
* **Location paths** - shared and my files (root)
* **Methods** - create, update, save, delete, and download
* **Download to documents folder** (private to Jigx app) - depends on the device's operating system. See [device storage location](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/download-a-file#device-storage-location) for the exact location

### Specifying the file path

When working with the OneDrive data provider use `entity` to specify the file path, for example, `entity: myfiles/Finance/Invoices`. The specified file path with the folders must already exist in OneDrive.

There are two supported base entities myfiles and shared.

1. `entity: myfiles`, and `myfiles` with additional paths e.g. `entity: myfiles/Finance/Invoices`
2. `entity: shared/path`, a `shared` entity always requires a path e.g. `entity: shared/HR/Global/Forms`

### Supported methods:

* [Create](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/create-a-file)
* [Update](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/update_save-a-file)
* **Save** - Using the `method: save` will create a new file if the filename does not exist, otherwise, the save will function as an update method.
* [Delete](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/delete-a-file)
* [List](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/list-files)
* [Download](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/download-a-file)

### Properties:

* `file` - reference the physical file
* `fileName` - add the file name with the extension, e.g. Invoice.pdf
* `tokenType` - OAuth token credentials name
* `method` - the CRUD method to use

### Examples and code snippets

The following examples with code snippets are provided

* [Create a file](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/create-a-file)
* [Update/Save a file](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/updatesave-a-file)
* [Delete a file](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/delete-a-file)
* [List files](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/list-files)
* [Download a file](https://docs.jigx.com/examples/readme/data-providers/microsoft-onedrive/download-a-file)


# REST

This section explains how to configure the REST data provider to call external REST API endpoints. Use it to fetch data, send updates, or trigger external services in response to user interaction. The REST data provider is one of the most commonly used in Jigx solutions, enabling data exchange with REST services that accept or return JSON, XML, or binary data.

## REST Data Provider Architecture

When a REST call returns data to Jigx, the processed format, such as JSON, is inserted into a local SQLite database. The Jigx mobile application then queries the database, displaying the data on the device. This architecture supports offline scenarios. Data is stored in a document database format. Jigx provides a shorthand SQL parser to select using logical column names. Alternatively, you can use the native json\_extract() function to manipulate the data from SQLite. When the result of the output transform is an array of JSON objects, Jigx will insert each item in the array in its row. Note that SQL is case-insensitive while JSON is case-sensitive.

{% embed url="<https://vimeo.com/848055698>" %}

## Examples and code snippets

The following examples with code snippets are provided:

<table><thead><tr><th width="130.22265625">Example</th><th></th></tr></thead><tbody><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/rest/create-an-app-using-rest-apis">Hello REST</a></td><td>In this section, a REST API is used to create a customers Jigx app, allowing you to add new customers and update and view customer details, location, and images.</td></tr><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/rest/ms-graph">MS Graph</a></td><td>The MS Graph examples use the User, Calendar, Mail, Insights, and To-do tasks to create a powerful Jigx apps with everything you need in one app.</td></tr></tbody></table>

## Building a REST based app video resources

{% columns %}
{% column %}
{% embed url="<https://vimeo.com/848412406?fe=sh&fl=pl>" %}

1. Introduction to REST API\
   6:59 min
   {% endcolumn %}

{% column %}
{% embed url="<https://vimeo.com/848059289?fe=sh&fl=pl>" %}

2. Exploring REST and JSONata 6:17 min
   {% endcolumn %}
   {% endcolumns %}

{% columns %}
{% column %}
{% embed url="<https://vimeo.com/848062137?fe=sh&fl=pl>" %}

3. Building a REST based App\
   9:14 min
   {% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}


# REST Overview

## Configuring the REST data provider

To use the REST data provider in Jigx , follow these high-level steps:

1. **Choose your datasource**
   * Identify the REST API you will use as your datasource. Ensure you understand its endpoint structure, request requirements (like headers and query parameters), and the format of the data it returns.
2. **Define a REST Service in a Jigx function in Jigx Builder**
   * Navigate to the [functions](/building-apps-with-jigx/data/data-providers/rest/functions) folder in Jigx Builder.
   * Use [IntelliSense](/building-apps-with-jigx/jigx-builder-code-editor/editor#intellisense) to configure the REST data provider.
   * Enter the base URL, method, parameters of the REST API.
3. **Configure REST Authentication**:
   * If the API requires [authentication](/building-apps-with-jigx/data/data-providers/rest/rest-authentication) (such as OAuth, API keys, etc.), configure these settings. This might involve adding headers, query parameters, or setting up OAuth tokens.
4. **Define data methods in the function**:
   * Set up different methods your application can perform using this API, such as GET, POST, PUT, DELETE, etc.
   * For each method, create a new function to specify the endpoint, required headers, URL parameters, input and output transforms, continuation, and body content if applicable.
5. Configure properties to handle API limits, errors and file storage.
   * In the function configure the REST provider to cater for [errors](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling), such as 403, 404 or 500.
   * [Convert](/building-apps-with-jigx/data/data-providers/rest/functions/conversions) images and files from local-uri to an acceptable storage format, such as base64 or buffer.
   * Add [Continuation](/building-apps-with-jigx/data/data-providers/rest/functions/continuation) if the REST services limit the number of items to be returned. Jigx REST calls can automatically repeat calls by specifying a continuation block.
6. **Bind data to the UI by referencing the local data and functions in jig﻿s**
   * Use the data from the local database in [datasources](/building-apps-with-jigx/data/datasources) in jigs and components\
     [components](/building-apps-with-jigx/ui/components-_controls_) to build the required UI.
   * Reference the function﻿ in your jig﻿s in [actions](/building-apps-with-jigx/ui/actions). This step is crucial for integrating the API data seamlessly into your Jigx﻿ solution.
7. **Publish your solution**:
   * [Publish your solution](/building-apps-with-jigx/jigx-builder-code-editor/publishing-a-solution) and use the app to interact with the REST data provider.&#x20;
8. **Test the Data Provider**:
   * Use Jigx Builder [developer tools](/building-apps-with-jigx/jigx-builder-code-editor/debugging) to test the data provider configurations. Check if the data provider can connect to the API successfully and perform operations like GET (fetch), PUT (create), POST (update), or DELETE data.

Following these steps, you can effectively integrate external REST APIs into your Jigx solutions, allowing you to enhance your apps with data and functionalities from diverse external sources.

### See Also

* [REST examples](https://docs.jigx.com/examples/readme/data-providers/rest)
* [Offline remote data handling](/building-apps-with-jigx/data/offline-remote-data-handling)


# REST syncing & loading local Data

<figure><img src="/files/itsQ2reoZ2w3v7MHjhI0" alt="" width="563"><figcaption></figcaption></figure>

**Key:**

1. **Sync data from the cloud** Use a `sync-entities` action to fetch data from the cloud and store it in the local SQLite database. Use the `onLoad`, `onFocus`, `onRefresh`, or any other event where actions are defined.
2. **Load data from SQLite to use on a jig** Use the `DATA_PROVIDER_LOCAL` in the datasource defined in the jig or a global datasource to execute an SQLite query.
3. **Save data to SQLite ONLY** To save data locally only and not sync to the cloud, use an `execute-entity` action with the `DATA_PROVIDER_LOCAL`.
4. **Save data to SQLite and sync data to the cloud** Update the local SQLite and sync to the cloud in a single action to ensure high-performing user experiences without lag. Use `execute-entity` or `execute-entities` actions with `DATA_PROVIDER_REST`. Specify the function to make on the REST server, the local entity/table to update, and the method to perform on the local table. If the method is an update, delete, or save, specify the record's ID.
5. **Save data to the cloud ONLY** Use `execute-entity` or `execute-entities` actions with `DATA_PROVIDER_REST`. Set the method to the `functionCall` and specify the function to be called. The local tables will not be updated; you must sync the data from the cloud before it is available to display on a jig.

## Using sync-entities action

1. Use the `sync-entities` action to sync data from the REST data store to the local SQLite data provider. Syncing data locally results in high performance with minimal lag and ensures all data is available in the app when the device is offline.
2. Best practice is to configure a global action, the `sync-entities` action, with the REST data provider, allowing reuse throughout the solution.
3. Add the global sync action to the `onFocus` and `onLoad` events in the index.jigx file ensures data is synced to the local data provider as soon as the app loads or is focused on the device.
4. Add the global sync action to the `onRefresh` or `onFocus` events in a jig when data is changed, for example, on the list of customers, this ensures that when a new customer is created, the list is updated immediately when navigating to it or refreshing the list with a downward swipe.

## Using Execute-entity/entities action

There are two options when using the `execute-entity` and `execute-entities` actions with remote data such as REST.

1. **To update BOTH the local SQLite table and the remote data store (REST and SQL)**. To update the local table, specify CREATE, UPDATE, or DELETE methods in the `method` property of the data provider, then specify the function to use in the `function` property, and under `parameters` specify the exact data to be updated in the remote REST service. Under `data` specify the exact data to be updated in the local SQLite table.. After execution, a tempId is created, and then it is synced to the local table.

<figure><img src="/files/wuCVSREIPPaRAPdxEcBy" alt="Update local and REST providers"><figcaption><p>Update local and REST providers</p></figcaption></figure>

1. **To ONLY update the REST data store**. To update the remote data store specify `functionCall` in the method property. Then specify the function to be called in the `function` property and under `parameters` specify the exact data to be updated. Note that the data will not be visible on the jig until a `sync-entities` action is executed.

<figure><img src="/files/fdqrjX2iYBgKorWVQcrK" alt="Only update REST Service"><figcaption><p>Only update REST Service</p></figcaption></figure>

### Consideration

* Using the `save` method in `execute-entity/entities` actions will perform an upsert in the local SQLite table.
* Dealing with offline remote data is fundamental to ensuring data synchronization and consistency between the mobile app and the remote data source, allowing users to continue using the app and performing actions without interruption. [Offline remote data handling](/building-apps-with-jigx/data/offline-remote-data-handling) explains how to configure solutions to deal with data when the device is offline.

## Using local data provider in a jig's datasources

1. Once the data has been synced using the `sync-entities` action the data is available in the local data provider.
2. Reference the local data provider in the jig's `datasource` property to define the data required in the jig.
3. Write a SQLite query to define the exact data required.
4. Use Intellisence and expressions to reference the specific datasource values to use in each component, such as `data: =@ctx.datasources.customers`

<figure><img src="/files/RXPIwc1CZmrcjnTqoNda" alt="Local data provider"><figcaption><p>Local data provider</p></figcaption></figure>

## Example

See the [REST](https://docs.jigx.com/examples/readme/data-providers/rest) code examples that show how to use remote data store with local data provider.


# REST Authentication

Jigx supports OAuth, tokens, Basic Auth credentials, secrets, and API keys as authentication methods. These result in entries added to the request's header unless the authentication parameters' location is specified differently. We **do not recommend** building solutions with Jigx where credentials are stored in the YAML of the Jigx solutions. Jigx provides a secure mechanism for defining, storing, and retrieving authentication information during runtime.

## Setting up Jigx Management to securely store credentials

Credentials, including OAuth configurations, are stored in Jigx Management under the [credentials](/administration/solutions/credentials) section for a solution. Each authentication type entry has the fields required for Jigx to add the credentials to the request when it executes the function on the device. These entries are stored in the Jigx Cloud-using AWS amplifies encryption that Jigx cannot decrypt. Entries containing secrets are not visible once they are stored. During runtime, when Jigx comes across a parameter it recognizes as an authentication parameter, it will retrieve the configuration from the Jigx cloud and stores it in the device's keychain. Only the Jigx application can access and retrieve the information once stored on the device. This is protected by on-device encryption and can only be accessed by the native application signed with the Jigx certificate for the signed-in user.

## OAuth and Bearer Tokens

The result of a successful OAuth loop is a token that is stored on the user's device in the keychain secure storage. When the token expires, Jigx uses a refresh token to get an updated token. If the OAuth loop provides no refresh token, the user will be prompted for their OAuth credentials by the REST call.

The `accessToken` must be specified as a parameter in the YAML. Jigx only retrieves the values from the cloud if specified in the YAML. If this parameter is omitted, the OAuth loop will not be initiated.

## Authentication examples

### OAuth Example

Jigx Management Configuration. See [Credentials](/administration/solutions/credentials) for more information.

<figure><img src="/files/YcBpY4KNpNcQwteoCIBX" alt="Credentials configuration"><figcaption><p>Crendentials configuration</p></figcaption></figure>

Jigx Function example:

```yaml
provider: DATA_PROVIDER_REST
url: https://www.googleapis.com/calendar/v3/calendars/{calendarId}/events?
method: GET
outputTransform: $.items
parameters:
  accessToken:
    location: header
    required: true
    type: google.oauth
    value: google.oauth
  calendarId:
    type: string
    location: path
    required: true
  maxResults:
    type: string
    location: query
    required: true
    value: "100"
  timeMin:
    type: string
    location: query
    required: true
```

Jig YAML example:

```yaml
title: View Calendar
type: jig.calendar

datasources:
  mydata:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: calendar-entries
          function: get-google-calendar-entries
          functionParameters:
            accessToken: google.oauth
            calendarId: =@ctx.jig.inputs.calendarId
            maxResults: "100"
            timeMin: =$now()

      query: |
        SELECT id, 
        datetime(json_extract(Data, '$.start.dateTime')) as startDateTime,
        datetime(json_extract(Data, '$.start.date')) as startDate,
        datetime(json_extract(Data, '$.end.dateTime')) as endDateTime,
        datetime(json_extract(Data, '$.end.date')) as endDate,
        '$.summary'
        FROM [calendar-entries]

data: =@ctx.datasources.mydata
item:
  type: component.event
  options:
    from: "=(@ctx.current.item.startDateTime = null ? @ctx.current.item.startDate : @ctx.current.item.startDateTime)"
    to: "=(@ctx.current.item.endDateTime= null ? @ctx.current.item.endDate : @ctx.current.item.endDateTime)"
    title: =@ctx.current.item.summary
placeholders:
  - title: Fetching Data
    icon: loading-data
    when: =$count(@ctx.datasources.mydata) < 1
```

### API Key Example

Jigx Management Configuration. See [Credentials](/administration/solutions/credentials) for more information.

<figure><img src="/files/UGs6NP3CZFweyrapTCxP" alt="Crendentials configuration"><figcaption><p>Credentials configuration</p></figcaption></figure>

Jigx Function example:

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://api.weather.example/gridpoints/SEW/131,69/forecast/hourly

parameters:
  x-api-key:
    location: header
    required: true
    type: secret
    # Use manage.jigx.com to define credentials for your solution
    value: synatic.weather
```

jig YAML example:

```yaml
title: ="Hourly Weather for " & $fromMillis($toMillis($now()),'[M01]-[D01]-[Y0001]')
type: jig.list
icon: contact

datasources:
  mydata:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: forecast
          function: get-weather-api-key
          functionParameters:
            x-api-key: synatic.weather
      query: |
        SELECT id, '$.startTime', 
        '$.endTime', '$.temperature', 
        '$.temperatureUnit', '$.windSpeed', 
        '$.windDirection', '$.icon',
        '$.shortForecast'
        FROM [forecast]

data: =@ctx.datasources.mydata
item:
  type: component.list-item
  options:
    title: |
      ="from " & $fromMillis($toMillis(@ctx.current.item.startTime),'[h#1]:[m01][P]')
      & " to " & $fromMillis($toMillis(@ctx.current.item.endTime),'[h#1]:[m01][P]')
    subtitle: |
      ="Temp " & @ctx.current.item.temperature & @ctx.current.item.temperatureUnit & 
      " with wind at " & @ctx.current.item.windSpeed & 
      " from " & @ctx.current.item.windDirection
    leftElement:
      element: image
      text: =@ctx.current.item.shortForecast
      uri: =@ctx.current.item.icon
      resizeMode: contain
```

### Basic Authentication

A username and password for basic authentication are stored in Jigx Management with a specific key. The key is referenced in the Jigx function definition using a header parameter called basicAuth.

Jigx Management Configuration. See [Credentials](/administration/solutions/credentials) for more information.

<figure><img src="/files/GTNliHdKdlL8IyA5rse1" alt="Credentials configuration"><figcaption><p>Credentials configuration</p></figcaption></figure>

Jigx Function example:

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://api.weather.example/gridpoints/SEW/131,69/forecast/hourly

parameters:
  basicAuth:
    location: header
    required: true
    type: secret
    # Use manage.jigx.com to define credentials for your solution
    value: weather.basicAuth
```

Jig YAML example:

```yaml
title: ="Hourly Weather for " & $fromMillis($toMillis($now()),'[M01]-[D01]-[Y0001]')
type: jig.list
icon: contact

datasources:
  mydata:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_REST

      entities:
        - entity: forecast
          function: get-weather-basic-auth
          functionParameters:
            basicAuth: weather.basicAuth
      query: |
        SELECT id, '$.startTime', 
        '$.endTime', '$.temperature', 
        '$.temperatureUnit', '$.windSpeed', 
        '$.windDirection', '$.icon',
        '$.shortForecast'
        FROM [forecast]

data: =@ctx.datasources.mydata
item:
  type: component.list-item
  options:
    title: |
      ="from " & $fromMillis($toMillis(@ctx.current.item.startTime),'[h#1]:[m01][P]')
      & " to " & $fromMillis($toMillis(@ctx.current.item.endTime),'[h#1]:[m01][P]')
    subtitle: |
      ="Temp " & @ctx.current.item.temperature & @ctx.current.item.temperatureUnit & 
      " with wind at " & @ctx.current.item.windSpeed & 
      " from " & @ctx.current.item.windDirection
    leftElement:
      element: image
      text: =@ctx.current.item.shortForecast
      uri: =@ctx.current.item.icon
      resizeMode: contain
```

### Secret

A secret is stored in Jigx Management with a specific key. The key is referenced in the Jigx function definition using a path, header, query, or body parameter with the name expected by the request.

Jigx Management Configuration. See [Credentials](/administration/solutions/credentials) for more information.

<figure><img src="/files/qEqstnLgSchxENpZ705H" alt="Credentials configuration"><figcaption><p>Credentials configuration</p></figcaption></figure>

Jigx function example:

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://api.weather.example/gridpoints/SEW/131,69/forecast/hourly

parameters:
  service-secret: #name of the header property you want to populate with the secret
    location: header
    required: true
    type: secret
    value: weather.secret #Use manage.jigx.com to define credentials for your solution
```

jig YAML example:

```yaml
title: ="Hourly Weather for " & $fromMillis($toMillis($now()),'[M01]-[D01]-[Y0001]')
type: jig.list
icon: contact

datasources:
  mydata:
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_REST

      entities:
        - entity: forecast
          function: get-weather-secret-auth
          functionParameters:
            service-secret: weather.secret
      query: |
        SELECT id, '$.startTime', 
        '$.endTime', '$.temperature', 
        '$.temperatureUnit', '$.windSpeed', 
        '$.windDirection', '$.icon',
        '$.shortForecast'
        FROM [forecast]

data: =@ctx.datasources.mydata
item:
  type: component.list-item
  options:
    title: |
      ="from " & $fromMillis($toMillis(@ctx.current.item.startTime),'[h#1]:[m01][P]')
      & " to " & $fromMillis($toMillis(@ctx.current.item.endTime),'[h#1]:[m01][P]')
    subtitle: |
      ="Temp " & @ctx.current.item.temperature & @ctx.current.item.temperatureUnit & 
      " with wind at " & @ctx.current.item.windSpeed & 
      " from " & @ctx.current.item.windDirection
    leftElement:
      element: image
      text: =@ctx.current.item.shortForecast
      uri: =@ctx.current.item.icon
      resizeMode: contain
```

### Local REST Calls

A local REST function call allows the mobile app to perform all the processing locally and call the third-party service directly. As a result, data is only transferred between the mobile app and the third-party REST service. Only OAuth authentication can be used with Local REST calls. For more information see [Local REST Calls](/building-apps-with-jigx/data/data-providers/rest/local-rest-calls).

### See Also

* [REST examples](https://docs.jigx.com/examples/readme/data-providers/rest)


# Functions

The Jigx function contains the URL of the REST service, details of the required parameters, and the ability to map your Jigx parameters to complex JSON for either input or output purposes. In the sections below, we will explain each part of the function definition and how you can define any REST service and use it within your Jigx application.

## Functions structure

<table><thead><tr><th width="215.734375">Structure </th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/ci4mORWiE6C9T0I5oFX7">Continuation</a></td><td>Use when REST services limit the number of items to be returned. Jigx function calls can automatically repeat calls by specifying a continuation block. This overwrites the parameters in the original function call.</td></tr><tr><td><a href="/pages/Enfff9mdj1bsD1KbJknS">Conversions</a></td><td>Handles file format conversions between local-uris and base64, data-uri, or buffer when sending to or receiving from a REST datasource.</td></tr><tr><td><code>disableTokenRefresh</code></td><td>Disables the auto-handling of 401 errors that refresh tokens twice.</td></tr><tr><td><a href="/pages/o27kz7cMvSlXvT1Y7y8t">error</a></td><td>Customize REST endpoint error messages to suppress or customize default error messages, log error details for more effective debugging, configure retries, and track errors through error logging.</td></tr><tr><td><code>format</code></td><td>Specifies the format of the data returned from the REST server. Supported formats include json, text, pdf, and xml. This setting determines how the response is processed by the function.</td></tr><tr><td><a href="/pages/LvofsPKraMX4cCDFlyT2">forRowsInRange</a></td><td>This function's results are for a specific range in the data - all rows matching the specified column name and parameter value ranges (inclusive) will be removed and replaced with the results from the function. If not specified, the whole table is replaced with the function results, unless either for <code>RowsWithValues</code> is specified.</td></tr><tr><td><a href="/pages/VtHdGUnU6eS5ziiEvm4p">forRowsWithMatchingId</a>s</td><td>This function's results are for specific rows with matching IDs, and other rows are not changed or removed. If not specified, the whole table is replaced with the function results, unless either <code>forRowsWithValues</code> and/or <code>forRowsInRange</code> is specified.</td></tr><tr><td><a href="/pages/vhNrBXxWUicBGl4ZDcV8">forRowsWithValues</a></td><td>This function's results are for specific rows in the data - all rows matching the specified column name and parameter value pairs will be removed and replaced with the results from the function. If not specified, the whole table is replaced with the function results, unless for<code>RowsInRange</code> is specified.</td></tr><tr><td><code>functionId</code></td><td><p>Used to override the name of the function. Expected value is a string that respects the following rules:</p><p>The first character has to start with a letter.</p><p>The name can contain alphanumeric or symbols '-' and '_'.</p><p>The name cannot contain spaces.</p><p>The name cannot end with special characters.</p><p>The length must be between 2-50 characters.</p></td></tr><tr><td><a href="/pages/e8TmJTNd3fHKAK8VowLy">guard</a></td><td>Guard functions allow you to control what happens after a query runs by conditionally executing additional logic. These functions are called after a query completes and can invoke any other function.</td></tr><tr><td><a href="/pages/mx3Fyf2tG22ZshnVgFN2">inputTransform</a></td><td>When the function format is JSON, the request body is generated using the inputTransform, a JSONata expression that can reference parameters defined in the function.</td></tr><tr><td><code>keepTempIds</code></td><td>If set to true, temporary Ids in local data will not be deleted on sync. This does not apply when forRowsWithMatchingIds is set to true.</td></tr><tr><td><code>method</code></td><td><p>Jigx supports the following methods when making REST calls:</p><p>DELETE</p><p>GET</p><p>HEAD</p><p>PUT</p><p>PATCH</p><p>POST</p></td></tr><tr><td><a href="/pages/htfriCQTAbMWrvlrjmxO">operations</a></td><td>A function can specify zero or multiple table operations to perform on the solution's local SQLite database.</td></tr><tr><td><code>output</code></td><td>The function’s output is returned to calling actions or functions. If an <code>outputTransform</code> is defined, its result is returned; otherwise, the full response from the REST provider is used by default.</td></tr><tr><td><a href="/pages/giuUA22dn7hsdOPYy3rx">outputTransform</a></td><td>The <code>outputTransform</code> is a JSONata expression that converts the REST response into JSON for local SQLite insertion.</td></tr><tr><td><a href="/pages/caOZ4k1O9ynvaP5U9sK2">parameters</a></td><td>Function parameters are used to pass data into the function definition from the jig that uses the function. It can be used in body, query, path, and also as input parameters for procedures and views.</td></tr><tr><td><code>provider</code></td><td>DATA_PROVIDER_REST for making REST service calls.</td></tr><tr><td><a href="/pages/jQJ5xlT8yfmcPvAW6pDV">queries</a></td><td>Queries in functions provide Just-In-Time (JIT) access to the latest local data, evaluated during function execution. The results can be used in function expressions.</td></tr><tr><td><code>url</code></td><td><p>The URL of the service that must be called. Jigx</p><p>supports path and query parameters in the URL. Path parameters are tagged with curly brackets {}. Jigx</p><p>will replace the path parameters with the values of the parameters defined in the parameter section of the function definition. Query parameters specified in the URL will be removed by Jigx</p><p>and replaced by parameters defined in the parameters section of the function definition with a location property of type <code>query</code>.</p></td></tr><tr><td><a href="/pages/jeLjcz5FgFE4857tBsrQ">when</a></td><td>Specify a condition for when to execute a function (default) and when to skip and not execute a function based on the local state of the database. The <code>when</code> expression is evaluated after the <code>parameters</code> and <code>queries</code> are evaluated. The <code>when</code> expression is evaluated before token credentials are checked and <code>inputTransforms</code> are evaluated. The when expression is re-evaluated on each <code>continuation</code>.</td></tr></tbody></table>

## Creating Function Definitions

{% columns %}
{% column %}
Function definitions are stored in the functions folder in a Jigx project with a .jigx file extension. The Jigx Builder IntelliSense code completion provides all the available code completion options relevant to REST functions.

{% endcolumn %}

{% column %}

<figure><img src="/files/DD9JAlDSnSClUJzqQFFd" alt="Jigx functions" width="375"><figcaption><p>Jigx functions</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

To add a new function, create a file in the functions folder. The .jigx extension is added automatically. Function file names must be lowercase and cannot contain special characters.  Using a clear naming convention is recommended to help identify the purpose of each function, e.g. rest-get-customer or rest-update-customer.

Once functions are published in a Jigx solution you can preview the function in Jigx Management under the solution's REST functions option. See [REST Functions](/administration/solutions/rest-functions) for more information.

{% code title="" %}

```yaml
provider: DATA_PROVIDER_REST
method: POST
url: "https://api.sendgrid.com/v3/mail/send"

parameters:
  Authorization:
    location: header
    type: string
    value: Bearer XXXXXX
    required: true
  emailfrom:
    location: body
    type: string
    required: true
  emailto:
    location: body
    type: string
    required: true
  name:
    location: body
    type: string
    required: true
  subject:
    location: body
    type: string
    required: true
  content:
    location: body
    type: string
    required: true
    
inputTransform: |
  $.{
    "personalizations": [{
      "to": [ { "email": emailto, "name": name }]}],
      "from": {"email": emailfrom, "name": name}, 
      "reply to": {"email": emailfrom, "name": name },
      "subject": subject, 
      "content": [{ "type": "text/html", "value": content}
      ]}          
```

{% endcode %}

## Referencing a function in a jig

Functions can be used in a jig to access and manage data in your app. You can either query the local SQLite database, populated from REST using configured functions, or use actions to trigger functions that update both the local and remote (REST) data.

{% tabs %}
{% tab title="local-datasource" %}

```yaml
datasources:
  customers: 
    type: datasource.sqlite
    options:
      provider: DATA_PROVIDER_LOCAL
      entities:
        - entity: customers
      query: |
        SELECT 
          cus.id AS id, 
          json_extract(cus.data, '$.firstName') AS firstName, 
          json_extract(cus.data, '$.lastName') AS lastName,
          json_extract(cus.data, '$.companyName') AS companyName,
          json_extract(cus.data, '$.address') AS address,
          json_extract(cus.data, '$.city') AS city,
          json_extract(cus.data, '$.state') AS state,
          json_extract(cus.data, '$.zip') AS zip,
          json_extract(cus.data, '$.phone1') AS phone
        FROM 
          [customers] AS cus
        -- ORDER BY 
        --  json_extract(cus.data, '$.companyName')
```

{% endtab %}

{% tab title="action" %}

```python
actions:
  - children:
        # Action to update the record.
      - type: action.execute-entity 
        options:
          title: Update Customer
          provider: DATA_PROVIDER_REST
          entity: customers
          # Update the record in the local SQLite table. 
          method: update
          # Update the record in the REST service. 
          function: rest-update-customer  
          # Define the data to be updated for the record.
          functionParameters: 
            id: =@ctx.jig.inputs.customer.id
            firstName: =@ctx.components.firstName.state.value
            lastName: =@ctx.components.lastName.state.value
            companyName: =@ctx.components.companyName.state.value
            address: =@ctx.components.address.state.value
            city: =@ctx.components.city.state.value
            state: =@ctx.components.state.state.value
            phone: =@ctx.components.phone.state.value
            zip: =@ctx.components.zip.state.value
          onSuccess: 
            type: action.go-back  
```

{% endtab %}
{% endtabs %}

## Supporting JSON

REST services typically have simple or complex JSON structures which enable you to provide them with suitable input data as well as return complex data structures. Jigx has built-in capabilities to deal with these structures. These are achieved using:

* [InputTransform](/building-apps-with-jigx/data/data-providers/rest/functions/inputtransform)
* [OutputTransform](/building-apps-with-jigx/data/data-providers/rest/functions/outputtransform)

## Authentication Support

All REST functions support header, path, query, and body parameters. In addition, including calling services with no authentication, Jigx supports OAuth, API Key, and Basic Auth or Secrets for authentication. See [Authentication](/building-apps-with-jigx/data/data-providers/rest/rest-authentication) for configuration steps. &#x20;

<figure><img src="/files/WgXd6HgKQOimVrPekNiy" alt="Functions code completion options" width="563"><figcaption><p>Functions code completion options</p></figcaption></figure>

The code completion will display the available template options when adding a new function. Creating a new function using one of these code options adds the skeleton code to the function definition, making it easier to configure functions for specific providers with their authentication configuration. These options are:

* **REST**: A REST service call with no authentication that returns JSON by default.
* **REST (API Key)**: A REST service call that includes `x-API-key` in the header for authentication.
* **REST (Basic Auth)**: A REST service call that includes `basicAuth` in the header populated with the credential's information.
* **REST (OAuth)**: A REST service call that includes `accessToken` (Authorization) in the header populated with the OAuth Token returned during the OAuth loop.
* **REST (Secret)**: A REST service call that includes a `secret` that can be added to the header or query string parameters for authentication.

## Function execution order

Function properties are evaluated and executed in the following order:

* Check if function exists.
* Check and execute the `parameters`.
* Then execute `queries`, `dependencies` first.
* Then execute the `when` in the main function.
* Then the `guard` function is executed.
* Then the `when` in the guard function is executed.
* Then execute `operations`.
* Execute `inputTransform`.
* Then execute `conversions`.
* Return the `output` of the function.

## Examples and code snippets

The following examples with code snippets are provided:

<table><thead><tr><th width="153.64453125">Example</th><th></th></tr></thead><tbody><tr><td><a href="/pages/Aw4YknvY7KlPtFwxYzM9">Hello REST</a></td><td>In this section, a REST API is used to create a customers Jigx app, allowing you to add new customers and update and view customer details, location, and images.</td></tr><tr><td><a href="https://docs.jigx.com/examples/readme/data-providers/rest/ms-graph">MS Graph</a></td><td>The MS Graph examples use the User, Calendar, Mail, Insights, and To-do tasks to create a powerful Jigx apps with everything you need in one app.</td></tr></tbody></table>


# Swagger parser

The Swagger parser function allows you to convert Swagger, open API, and Postman collection data to Jigx functions in the Jigx Builder.

## How to use the Swagger parser

The command to start the Swagger parser function is (command + shift + p): Generate Jigx Functions

<figure><img src="/files/pw3sJJjLffmSHNGR1FfU" alt="Generate Jigx functions" width="563"><figcaption><p>Generate Jigx functions</p></figcaption></figure>

Both remote and local files can be used, and only JSON format is allowed.

<figure><img src="/files/VDCONLGLuk9PhzkwsMqa" alt="File options" width="563"><figcaption><p>File options</p></figcaption></figure>

All files created by the Swagger parser function saves in your functions folder.

### Variable replacement

You can replace variables in your Postman collection, for example, replacing the baseUrl. As you add the value 'google.com' to the variable all functions requiring this variable will be updated.

<figure><img src="/files/laq8CDsjDf4MUGDmYR9U" alt="" width="563"><figcaption></figcaption></figure>


# Parameters

Function parameters pass data into the function from the jig that calls it. They make the function dynamic and reusable by allowing context-specific values, like user input, selected records, or settings, to be used during execution.

Parameters are defined by a name and a set of properties (such as type, location, and whether they are required). These names are then referenced throughout the function, for example, in REST paths, query strings, and input transforms.

## Configuration options

<table><thead><tr><th width="139.3515625">Options</th><th>Description</th></tr></thead><tbody><tr><td><code>location</code></td><td><p>The location determines where the parameter will be applied in the REST call as follows:</p><ul><li><code>path</code> - The parameter is available as a token in the URL's path.</li><li><code>query</code> - A query string parameter will be added to the URL, using the function parameter's name as the key and its value as the query parameter value.</li><li><code>header</code> - A header will be added to the request using the function parameter’s name as the key and its value as the header value.</li><li><code>body</code> - When body is specified as the location, the function parameter is available in the function’s <code>inputTransform</code>. Any token matching the parameter’s name will be replaced with its value during execution.</li><li><code>credential</code> - Specifies the type of authentication required for REST API calls. It ensures secure communication between the app and the external API by attaching the appropriate authentication tokens or headers, as configured in <a href="/pages/Jei75c9ChZEDJDz0hHPE">Jigx Management</a>.</li><li><code>secret</code> - Securely references the client secret. Instead of hardcoding credentials directly into the function, you reference secret values that are stored securely in the solution's credentials in <a href="/pages/Jei75c9ChZEDJDz0hHPE#adding-credentials">Jigx Management</a>.</li></ul></td></tr><tr><td><code>type</code></td><td><p>Type is specific to the REST call being made. Most types are defined as strings when they are used in path, query, or body locations. The available types are <code>string</code>, <code>number</code>, <code>array</code>, and <code>object</code>.</p><p>When types are declared in authentication header parameters, they are specific to the authentication type being configured.</p></td></tr><tr><td><code>required</code></td><td>The <code>required</code> value can be either <code>true</code> or <code>false</code>, indicating whether the parameter must be provided when the function is used in a jig’s datasource. Parameters used in URL paths must be set to <code>required: true</code>; otherwise, the function will generate an error. Set this property to <code>true</code> if the REST call requires the parameter, or <code>false</code> if the parameter is optional.</td></tr><tr><td><code>value</code></td><td>Provide a value for the parameter based on its defined <code>location</code> (e.g., query, header, path, or body) and <code>type</code> (e.g., string, number, boolean).</td></tr></tbody></table>

### Example and code snippets

{% tabs %}
{% tab title="function-parameters (header, body)" %}

```yaml
provider: DATA_PROVIDER_REST
# Updates data in the REST Service 
# PATCH modifies only the specified fields or properties of the resource.
method: PATCH 
# Use your REST service URL
url: https://[your_rest_service]/api/customers  
format: text
# Use local execution between the device and the REST service.
useLocalCall: true 
# Define parameters with header and body location.
parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution
    value: service.oauth 
  id:
    type: int
    location: body
    required: true
  firstName:
    type: string
    location: body
    required: true
  lastName:
    type: string
    location: body
    required: true
  companyName:
    type: string
    location: body
    required: true
  address:
    type: string
    location: body
    required: false
  city:
    type: string
    location: body
    required: false
  state:
    type: string
    location: body
    required: false
  zip:
    type: string
    location: body
    required: false
  phone:
    type: string
    location: body
    required: false
 
```

{% endtab %}

{% tab title="function-parameters (query, path)" %}

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://{RESTURL}
useLocalCall: true
# Define parameters with query and path location.
parameters:
  $expand:
    location: query
    required: false
    type: string
    value: Details,Logs,Settings,Staff
  $filter:
    location: query
    required: true
    type: string
  $select:
    location: query
    required: false
    type: string
    value: Staff/StaffMember,Staff/StaffType,Staff/StaffMemberName,Details
  accessToken:
    location: header
    required: true
    type: authname
    value: authname
  RESTURL:
    location: path
    required: true
    type: string
```

{% endtab %}
{% endtabs %}


# Continuation

Many REST services limit the number of items that can be retrieved from the service in a single call. To retrieve all items associated with a query, additional calls must be made to the service using a URL or additional data passed to the caller. The caller then makes repeated calls to the service using these continuation parameters to retrieve all records.

Jigx REST functions can be configured to automatically repeat calls to `continuation` functions by specifying a continuation block in the function YAML.

{% hint style="warning" %}
The continuation URL and parameters overwrite the parameters in the original function call; therefore, all parameters, including OAuth tokens and API keys, must be replicated in the continuation function.

Since the continuation URL or parameters are outside of the data returned by the function (at a higher level), the **outputTransform** of the function will need to be changed to return the **records** in their own property, and the records property specified in the function YAML to locate the output records.
{% endhint %}

## Configuration options

<table><thead><tr><th width="149.296875">Options</th><th>Description</th></tr></thead><tbody><tr><td><code>when</code></td><td>This condition determines when pagination continuation should occur. The continuation will execute only when the value exists in the API response.</td></tr><tr><td><code>url</code></td><td>This specifies the complete URL for the next page of results. Certain APIs, such as  Microsoft Graph, provide the full continuation URL in the <code>@odata.nextLink</code> response field, which includes the base endpoint plus any necessary query parameters (like skip tokens or cursors) to retrieve the subsequent batch of data. This eliminates the need to manually construct pagination URLs. Other APIs require the full <code>url</code> to be specified.</td></tr><tr><td><code>parameters</code></td><td>These are the parameters required for continuation requests. Unlike the initial request, which included the optional <code>$top</code> query parameter, continuation requests only need the authentication token. </td></tr></tbody></table>

## Example and code snippets

### Continuation using @odata.nextlink

Microsoft Graph API uses continuation URLs to request the next page of items from their services. If there are more items in the response than can be handled in a single call, or the caller has limited the number of items per page, the service will return the `@odata.nextLink` parameter specifying the URL to call to fetch the next page of results.

```json
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('bb13f9b6-d289-485f-9ae6-76be00f5bab3')/drive/root/children",
    "@odata.nextLink": "https://graph.microsoft.com/v1.0/me/drive/root/children?$top=2&$skiptoken=UGFnZWQ9VFJVRSZwX1NvcnRCZWhhdmlvcj0xJnBfRmlsZUxlYWZSZWY9TWljcm9zb2Z0K1RlYW1zK0NoYXQrRmlsZXMmc",
    "value": [
        {
	   ...
	}
    ]
}
```

All data has been returned when the `@odata.nextLink` parameter is no longer present in the results. Note, in this case, that the `nextUrl` expression is used to both check for continuation data as well as the URL to fetch the next page of data.

```yaml
provider: DATA_PROVIDER_REST
url: https://graph.microsoft.com/v1.0/me/drive/root/children
method: GET

parameters:
  $top:
    location: query
    type: number
    required: false
  accessToken:
    location: header
    type: microsoft
    value: jigx.microsoft.oauth
    required: true

operations:
  - type: operation.upsert-merge
    records: =$.items
    
outputTransform: >-
  $.{"nextLink":`@odata.nextLink`,"items":value.{"id":id,"name":name,"size":size,"lastModifiedDateTime":lastModifiedDateTime,"type":$exists(folder) ? "Folder" : "File"}}

continuation:
  when: =$.nextLink
  url: =$.nextLink
  parameters:
    accessToken:
      location: header
      type: microsoft
      value: jigx.microsoft.oauth
      required: true
```

### Continuation using URL

This code defines a REST API configuration for fetching tasks from ClickUp with automatic pagination handling. The `when`  property checks if the current response contains exactly 100 tasks (ClickUp's page limit). If true, it assumes there are more pages to fetch. Then the same URL and parameters as the original request is used, and the `page` number is incremented.

* **First call:** Fetches page 0 with up to 100 tasks
* **If 100 tasks returned:** Automatically makes another call for page 1
* **Continues:** Until a response has fewer than 100 tasks (indicating the last page)
* **Result:** All pages are automatically fetched and combined into a single dataset

{% code title="REST function" %}

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://api.clickup.com/api/v2/list/{listId}/task
parameters:
  accessToken:
    location: header
    required: true
    type: string
    value: cuapi
  listId:
    location: path
    required: true
    type: number
  page:
    location: query
    required: false
    type: number
    value: 0
outputTransform: |
  $.tasks.{
    "id": id,
    "name": name,
    "status": status.status,
    "statusColor": status.color,
    "statusType": status.type,
    "orderIndex": orderindex,
    "priority": priority.priority,
    "priorityColor": priority.color,
    "assignees": assignees,
    "dueDate": due_date,
    "startDate": start_date,
    "dateCreated": date_created,
    "dateUpdated": date_updated,
    "url": url,
    "creator": creator,
    "parent": parent,
    "tags": tags,
    "list": list,
    "project": project,
    "space": space
  }
# Configure the Continution using the full URL and when it should continue  
continuation:
  url: https://api.clickup.com/api/v2/list/{listId}/task
  when: =$count($.tasks) = 100
  parameters:
    accessToken:
      location: header
      required: true
      type: string
      value: cuapi
    listId:
      location: path
      required: true
      type: number
    page:
      location: query
      required: false
      type: number
      value: =$number(@ctx.parameters.page) + 1

```

{% endcode %}


# Conversions

Jigx stores uploaded files as local files on the device and returns their file paths as `local-uri`. However, most REST APIs do not accept files in this format. To send files to a REST endpoint, you must convert the `local-uri` to a compatible format, such as `base64`, `data-uri`, or `buffer`, before including them in the request body.

Likewise, when retrieving files from a REST endpoint, they are often returned in a non-local format (e.g., `base64` or `buffer`). To use or display these files in the app, you must convert them back to `local-uri`.

This is achieved by using `conversions` in functions. See [File handling](/building-apps-with-jigx/data/file-handling) for detailed information on working with files and converting them into the correct format.

{% hint style="warning" %}
Operations are not aware of `conversions` configured at the function level. Each operation must define its own `conversions` property to handle file format transformations. Function-level conversions do not cascade to individual operations.
{% endhint %}

## Example and code snippet

### Incoming and outgoing conversions

In the examples below, the file conversions are configured:

1. In the **REST (GET) functions** to convert the incoming files to local-uri.
2. The file conversions are configured in the **REST (SAVE/CREATE/UPDATE) functions** to convert the files that are outgoing to REST.

{% tabs %}
{% tab title="rest-function-incoming" %}

```javascript
provider: DATA_PROVIDER_REST
method: GET
# Pdf indicates a generic binary type
format: pdf 
url: https://graph.microsoft.com/v1.0/me/photo/$value
outputTransform: $.{"data":$.data,"userId":$.inputs.userId.value} 
useLocalCall: true

parameters:
  accessToken:
    location: header
    required: true
    type: string
    value: oauth.microsoft 
  userId:
    type: string
    location: path
    required: true
# Add a conversion to ensure the file can be viewed in the app.    
conversions:
  - property: data
    from: base64
    to: local-uri
```

{% endtab %}

{% tab title="rest-function-outgoing" %}

```yaml
provider: DATA_PROVIDER_REST
method: PATCH
url: https://graph.microsoft.com/v1.0/me/photo/$value
useLocalCall: true
parameters:
  accessToken:
    location: header
    required: true
    type: string
    value: oauth.microsoft 
  Content-Type:
    location: header
    required: true
    type: string
    # Set the content type of the body.
    value: image/jpeg 
  file:
    location: body
    required: true
    type: image
# Convert the file from local-uri to an acceptable format
# to store in the remote database.     
conversions:
  - property: file
    from: local-uri
    to: buffer
```

{% endtab %}
{% endtabs %}

## Convert device specific formats

In this example, the file conversion is configured in the REST function to convert the files that are outgoing via REST. `convertHeicToJpg` is configured to true to convert HEIC images to JPEG which ensures images are visible on iOS and Android devices.

{% code title="YAML" %}

```yaml
provider: DATA_PROVIDER_REST
method: PATCH
url: https://graph.microsoft.com/v1.0/me/photo/$value
useLocalCall: true
parameters:
  accessToken:
    location: header
    required: true
    type: string
    # Use manage.jigx.com to define credentials for your solution
    value: oauth.microsoft 
  Content-Type:
    location: header
    required: true
    type: string
    # set the content type of the body
    value: image/jpeg 
  file:
    location: body
    required: true
    type: image
conversions:
  - property: file
    from: local-uri
    to: buffer
    convertHeicToJpg: true
```

{% endcode %}


# Guard

Guard functions control whether the main function should execute, based on runtime conditions such as query results, server responses, or business logic rules.

A guard function runs after any defined queries and before the main REST call is executed. It can call another function to validate the current app state, perform a check against local or remote data, and return a result that determines whether to proceed with the main function or not.

The outcome of the guard function, whether it succeeds or fails, determines the next steps in your app's flow.

## What guard functions do

* Act as a **pre-check** before executing the main function.
* Help prevent actions under incorrect conditions (e.g., stale data, duplicate submissions).
* Evaluate dynamic conditions based on **local queries**, **app parameters**, or **API responses**.
* Optionally trigger fallback operations if the check fails.

## When to use guard functions

**Technical issues** - Prevent REST calls when a condition already exists—for example, checking if a record already exists on the server to avoid duplicate entries.

**Business Logic** - Verify preconditions, like checking if an appointment is still open before allowing status updates, especially useful in offline-first or multi-device environments.

**Example:** When completing an appointment, a guard function can check if the appointment’s status is still open. If the status has changed to closed on the server, the guard function returns false and shows an error message, preventing invalid updates.

## Execution flow

When used in a function:

1. The guard function is executed first (if enabled for initial/continuation/retry).
2. If the guard succeeds, the main function proceeds as normal.
3. If the guard fails, the main function is skipped, and any defined `operations` in the guard are executed instead.
4. The guard’s output is available using `=@ctx.guard.output`.

## Execution timing options

<table><thead><tr><th width="163.55078125">Property</th><th>Purpose</th></tr></thead><tbody><tr><td><code>onInitial</code></td><td>Runs guard before the initial REST call.</td></tr><tr><td><code>onContinuation</code></td><td>Re-evaluates guard on function continuation.</td></tr><tr><td><code>onRetry</code></td><td>Runs guard before retrying a failed function.</td></tr></tbody></table>

## Guard Output

* Use the `=@ctx.guard.output` expression to get the output from the guard function.
*
* The output is never saved to a table.
* The output can be used when chaining function calls.
* If the output is not explicitly used, the default provider's output is used, and in the case of the REST provider, that would be the body.

## Configuration options

<table><thead><tr><th width="161.26171875">Properties</th><th>Description</th></tr></thead><tbody><tr><td><code>function</code></td><td>The name or <code>functionId</code> of the function to execute as the guard, before the main function, to determine whether the main function should be executed.</td></tr><tr><td><code>Parameters</code></td><td><code>parameters</code> passed to the guard function from the specified <code>function</code>.</td></tr><tr><td><code>onContinuation</code></td><td>Determine if the guard function should be executed on a <code>continuation</code> call. Defaults to <code>true</code>.</td></tr><tr><td><code>onInitial</code></td><td>Determines whether the guard function executes before the first call to the REST function. Default is <code>true</code>. If set to <code>false</code>, the guard function will execute in the defined <a href="/pages/W46YAaM9oZn3O0x57M9p#function-execution-order">execution order</a>.</td></tr><tr><td><code>onRetry</code></td><td>Determines whether the function should execute a retry call.<br>Defaults to <code>true</code>.</td></tr><tr><td><code>operations</code></td><td>Operations to run if the guard function <em>fails</em>. Used to update local data, show messages, or log state.</td></tr><tr><td><code>result</code></td><td>The result of the guard function is evaluated to determine whether the main function should be executed. If the guard function fails or the result of the expression is falsy, the main function is not executed. The output of the guard function is available to expressions and scripts using <code>=@ctx.guard.output</code></td></tr><tr><td><code>when</code></td><td>Condition to determine if the guard function itself should execute.</td></tr></tbody></table>

## Expressions

<table><thead><tr><th width="100.25390625"></th><th width="179.015625">Expression</th><th>Description</th></tr></thead><tbody><tr><td>output</td><td><code>=@ctx.guard.output</code></td><td>Output of the guard function is returned to the function as actions. If specified, the output of the function is the result of the expression; otherwise, the output is defined as the default output of the REST provider.</td></tr></tbody></table>

## Example code

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: url
useLocalCall: true

guard:
  # NOTE: the main function when is checked before the guard function is evaluated,
  # the guard when checks whether to call the guard function.
  # the guard result expression determines if the main function should be executed or not.
  # the guard operations are executed if the guard function fails or returns a falsy value.
  function: check-book-title-local-rest
  parameters:
    title: =@ctx.parameters.title
  # Should the guard function be executed at all (default: true)
  when: true
  # Should the guard function be executer before the first (initial) call of the main function (default: true)
  onInitial: true
  # Should the guard function be executed before each continuation of the main function (default: true)
  onContinuation: true
  # Should the guard function be executed before each retry of the main function (default: true)
  onRetry: true
  # The result expression is evaluated in the context of the guard function to determine if the main function should be executed (true) or not (false).
  result: "=@ctx.guard.output.id ? true : false"
  operations:
    - type: operation.execute-sql
      statements:
        - statement: |
            UPDATE _commandQueue
            SET payload = REPLACE(payload, @tempId, @id)
            WHERE payload LIKE '%' || @tempId || '%'
          parameters:
            tempId: ='_tmp_' & $string(@.commandId) & '_'
            id: =@ctx.guard.output.id
        - statement: |
            ="UPDATE [" & @.entity & "]\nSET [id] = REPLACE([id], @tempId, @id),\n[data] = REPLACE([data], @tempID, @id)\nWHERE ([data] LIKE '%' || @tempId || '%') OR ([id] = @tempId)"
          parameters:
            tempId: ='_tmp_' & $string(@.commandId) & '_'
            id: =@ctx.guard.output.id
        - statement: |
            DELETE FROM _commandQueue
            WHERE [id] = @commandId
          parameters:
            commandId: =@.commandId
      tables:
        - _commandQueue
        - =@ctx.entity
 
```


# InputTransform

When integrating with external REST APIs using a function in Jigx, the `inputTransform` property defines how input parameters are mapped to the body of the HTTP request. This is essential when the function’s `format` is set to `json`.

The `inputTransform` is written using [JSONata](https://jsonata.org/), a lightweight query and transformation language for JSON. It allows you to dynamically construct the JSON payload by referencing the parameters defined in the `parameters` section of the function.

Use `inputTransform` to:

* Map parameters into a structured JSON object.
* Build a request body that matches the target API’s requirements.
* Dynamically generate values based on user input or context.

## Simple Parameter Mapping

In this example:

* Two parameters are defined: `orderNumberParameter` and `orderDescriptionParameter`.
* Inside the `inputTransform`, these are referenced directly (without quotes).
* The resulting JSON object maps these values to the expected keys for the API call.

{% code title="inputTransform" %}

```yaml
parameters:
  orderNumberParameter:
    type: string
    location: body
    required: true
  orderDescriptionParameter:
    type: string
    location: body
    required: true

inputTransform: |
  $.{
    "orderNumber": orderNumberParameter,
    "orderDescription": orderDescriptionParameter
  }
```

{% endcode %}

## Multi-line YAML Strings

The `|` character in YAML indicates a multi-line string. This is useful for formatting complex transformations like JSONata expressions over multiple lines for better readability.

{% code title="YAML" %}

```yaml
inputTransform: |
  $.{
    "field1": value1,
    "field2": value2
  }
```

{% endcode %}

## Example and code snippet

Below is a more advanced example showing how to send an email using the SendGrid API. The URL for the service is `https://api.sendgrid.com/v3/mail/send`

The JSON body for this service is:

{% code title="JSON" %}

```json
{
  "personalizations": [
    {
      "to": [
        {
          "email": "anemail@com"
        }
      ]
    }
  ],
  "from": {
    "email": "youremail.com"
  },
  "subject": "Sending with SendGrid is Fun",
  "content": [
    {
      "type": "text/plain",
      "value": "and easy to do anywhere, even with cURL"
    }
  ]
}
```

{% endcode %}

In this configuration:

* `parameters` are defined for values like `emailto`, `name`, `subject`, and `content`.
* The `inputTransform` builds a JSON structure required by the SendGrid API using those parameters.
* The function constructs the request body at runtime, ensuring it dynamically reflects user or system inputs.

{% code title="YAML" %}

```yaml
provider: DATA_PROVIDER_REST
method: POST
url: https://api.sendgrid.com/v3/mail/send

parameters:
  Authorization:
    location: header
    type: string
    value: Bearer xxxxxxxxxxxxxxxxxxxx
    required: true
  emailfrom:
    location: body
    type: string
    required: true
  emailto:
    location: body
    type: string
    required: true
  name:
    location: body
    type: string
    required: true
  subject:
    location: body
    type: string
    required: true
  content:
    location: body
    type: string
    required: true
    
inputTransform: |
  $.{
    "personalizations": [{
      "to": [ { "email": emailto, "name": name }]}],
      "from": {"email": emailfrom, "name": name}, 
      "reply to": {"email": emailfrom, "name": name },
      "subject": subject, 
      "content": [{ "type": "text/html", "value": content}
      ]}    
```

{% endcode %}


# OutputTransform

The `outputTransform` property defines how the response from a REST API is transformed into a format suitable for insertion into a local SQLite table. The transform is written using [JSONata](https://jsonata.org/) and allows for both structural mapping and logic-based processing.

Use `outputTransform` to:

* Extract and reformat data from an API response.
* Return a single object or an array of objects.
* Map data into a structure that can be inserted into local tables.

## How Output Transform Works

* When the result of the `outputTransform` is an **array of objects**, each item in the array is inserted as a separate row in the local SQLite table.
* Each key-value pair in the resulting object becomes a column-value pair in the SQLite row.
* The insertion is performed using SQLite’s `json_extract()` function to map JSON fields to database columns.

### Extracting Orders from a Customer Record

This transform extracts the `orders` array from the response. Each order object is inserted into the SQLite table as a separate row.

{% code title="API Response (JSON)" %}

```json
{
  "customerId": "1432",
  "customerName": "Johson Shipping",
  "shippingAddress1": "7645 1st Street",
  "shippingCity": "Nashville",
  "shippingState": "TN",
  "shippingZip": "78654",
  "orders":[
    {
      "orderNumber": "1234",
      "orderDescription": "Printer Refil",
      "orderTotal": 345.67,
      "customerId": "1432",
      "orderDate": "1-29-2022"
    },
    {
      "orderNumber": "654",
      "orderDescription": "Printer Paper",
      "orderTotal": 185.27,
      "customerId": "1432",
      "orderDate": "1-29-2022"
    },
    {
      "orderNumber": "8934",
      "orderDescription": "Envelopes",
      "orderTotal": 25.88,
      "customerId": "1432",
      "orderDate": "1-29-2022"
    }
  ]
}
```

{% endcode %}

Output transform to get an array of orders: `$.orders`. `$` is the root of the document and orders the array with the collection of orders.

{% code title="outputTransform" %}

```yaml
outputTransform: |
  $.orders
```

{% endcode %}

The result of the transform is:

{% code title="outputTransform (JSON result)" %}

```json
[
  {
    "orderNumber": "1234",
    "orderDescription": "Printer Refil",
    "orderTotal": 345.67,
    "customerId": "1432",
    "orderDate": "1-29-2022"
  },
  {
    "orderNumber": "654",
    "orderDescription": "Printer Paper",
    "orderTotal": 185.27,
    "customerId": "1432",
    "orderDate": "1-29-2022"
  },
  {
    "orderNumber": "8934",
    "orderDescription": "Envelopes",
    "orderTotal": 25.88,
    "customerId": "1432",
    "orderDate": "1-29-2022"
  }
]
```

{% endcode %}

## JSONata in Output Transforms

You can enhance output transforms using built-in JSONata functions such as `$trim()`, `$substring()`, `$map()`, and `$exists()`.

#### Example: YouTube Playlist Items

This example shows how to transform complex nested data. It uses logic and helper functions to clean up fields and format dates.

This example shows how to transform complex nested data. It uses logic and helper functions to clean up fields and format dates.

{% code title="YAML" %}

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://www.googleapis.com/youtube/v3/playlistItems

outputTransform: |
  $.items[].{
    "id": id,
    "videoid": snippet.resourceId.videoId,
    "publishedat": $toMillis(snippet.publishedAt),
    "title": $contains(snippet.title, "]") ?
      $trim($substringAfter(snippet.title, "]")) :
      $trim(snippet.title),
    "description": snippet.description,
    "thumbnail": $exists(snippet.thumbnails.maxres) ?
      snippet.thumbnails.maxres.url :
      snippet.thumbnails.high.url
  }

parameters:
  key:
    location: query
    type: string
    value: xyBaQF3E1qxxxxQGl99q5Kkpa--xxx
    required: true
  playlistId:
    location: query
    type: string
    value: PL_500m6Wb0wjTjKDoM_G7MkIqLWtvCm0o
    required: true
  part:
    location: query
    type: string
    value: snippet
    required: true
  maxResults:
    location: query
    type: string
    value: "500"
    required: true
```

{% endcode %}

## Mapping Nested Arrays

You can also use `$map()` to transform nested arrays into structured fields within a single object. This example returns a single row with structured ingredients and instructions arrays. Use this pattern when you want to store related subitems within a single SQLite row, e.g., for display in a list jig using `$.eval()`.

{% tabs %}
{% tab title="YAML" %}

```yaml
outputTransform: >-
  {
    "id": $.recipes.id,
    "name": $.recipes.title,
    "image": $.recipes.image,
    "desc": $.recipes.summary,
    "ingredients": $map($.recipes.extendedIngredients, function($ingredient, $idx, $arr) {
      {
        "name": $ingredient.name
      }
    }),
    "instructions": $map($.recipes.analyzedInstructions.steps, function($instruction, $idx, $arr) {
      {
        "step": $instruction.step
      }
    })
  }
```

{% endtab %}

{% tab title="list-jig.jigx" %}

```yaml
 - type: component.section
    options:
      title: Ingredients
      children:
        - type: component.list
          options:
            data: =$eval(@ctx.datasources.randomRecipeData.ingredients)
            item: 
              type: component.list-item
              options:
                title: =@ctx.current.item.name
#         {"name": $ingredient.name}
#       })
```

{% endtab %}
{% endtabs %}


# forRowsinRange

By default, the JSON payload returned from the REST call replaces the existing data in the SQLite database. The `forRowsInRange` property specifies one or more key-value pairs, where the key is a json\_extract() column in the table, and the value defines the range to match. Only rows that match these criteria will be updated. If no match is found, the object is added as a new row in the collection.

You can specify multiple key-value pairs under `forRowsInRange`, which effectively acts like a WHERE ... BETWEEN clause. Jigx uses this to determine which rows to update or insert when applying the `outputTransform` result from the REST call to the table.

Before inserting the new data, Jigx deletes all rows from the table that match the `forRowsInRange` criteria. The user interface is updated only after the data operation completes, preventing flickering or partial updates. UI updates occur as the final step.

{% hint style="info" %}
Pass the values you want to test as input parameters. In this example, minmag and maxmag. The property to test is **mag**. This property (**mag**) must appear in the `outputTransform`. Then set the range you are testing for in the input parameters (**minmag**) and (**maxmag**).
{% endhint %}

<figure><img src="/files/foPIW8jUIrZ5vDE2l2VC" alt="forRowsInRange" width="563"><figcaption><p>forRowsInRange</p></figcaption></figure>

{% hint style="info" %}

* You can combine `forRowswithValues` and `forRowsInRange` as per the example below.
* You cannot combine `forRowsWithMatchingIds` with any other range or value check.
  {% endhint %}

<figure><img src="/files/gMT8xVAH2l3IGPs7aha8" alt="Combined properties" width="375"><figcaption><p>Combined properties</p></figcaption></figure>

Example code

{% code title="Get-earthquake-data" %}

```yaml
# REST Data Provider with forRowsInRange function example
# This example fetches earthquake data and updates only rows within a magnitude range
provider: DATA_PROVIDER_REST
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson
useLocalCall: true      
# Input parameters for the range values
parameters:
  mag:
    type: number
    location: query
    required: false
    value: 2.0
  dmin:  
    type: number
    location: query
    required: false
    value: 5.0

# Transform the earthquake data
outputTransform: |
  {
    "earthquakes": features[].{
      "id": id,
      "place": properties.place,
      "mag": properties.mag,
      "time": properties.time,
      "coordinates": geometry.coordinates,
      "depth": geometry.coordinates[2]
    }
  }
operations:
  - type: operation.delete-insert
    table: earthquake_data
    records: |
      =$.earthquakes.{
      "id": id,
      "place": place,
      "mag": mag,
      "time": time,
      "longitude": coordinates[0],
      "latitude": coordinates[1],
      "depth": depth
      }
    # Only update rows where magnitude falls within the specified range
    forRowsInRange:
      mag: 
        from: mag
        to: dmin
        
    # Optional: Can combine with forRowsWithValues for additional filtering
    # forRowsWithValues:
    #   status: "active"
```

{% endcode %}


# forRowsWithMatchingids

By default, the JSON payload returned from the REST call replaces all existing data in the SQLite database. However, the `forRowsWithMatchingIds` property controls how data from REST API responses is synchronized with the local SQLite database.&#x20;

This approach is useful for incrementally syncing data without affecting unrelated records, making it ideal for scenarios where partial updates or record-level inserts are required.

### Understanding data sync behavior

The behavior of data synchronization depends on whether `forRowsWithMatchingIds` and explicit `operations` are specified. When using explicit `operations`, you lose the automatic upsert-merge behavior provided with the `forRowsWithMatchingIds` and must define all desired operations yourself. The `id` field in your `outputTransform` is critical for matching records. \
There are three scenarios:

<table><thead><tr><th width="123.12109375">Scenario</th><th width="401.5">Combinations</th><th>Results</th></tr></thead><tbody><tr><td>Scenario 1 <br>(Default)</td><td>No <code>forRowsWithMatchingIds</code> + no <code>operations</code></td><td>Wipe and sync</td></tr><tr><td>Scenario 2 (Automatic)</td><td><code>forRowsWithMatchingIds: true</code> + no <code>operations</code> </td><td> Automatic upsert-merge</td></tr><tr><td>Scenario 3 (Manual)</td><td><code>forRowsWithMatchingIds</code> + explicit <code>operations</code> </td><td>You control the behavior</td></tr></tbody></table>

<details>

<summary><strong>Scenario 1</strong>: No <code>forRowsWithMatchingIds</code>, no <code>operations</code> (Default behavior)</summary>

**Use case:** When you want to completely refresh the table contents.

When neither `forRowsWithMatchingIds` nor explicit `operations` are specified, Jigx performs a **wipe and sync**:

* **Deletes** all existing records in the table
* **Inserts** all new records from the API response

This is the standard default operation that completely replaces the table contents.

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://api.example.com/data
useLocalCall: true
outputTransform: |
  {
    "data": $.items
  }
# No forRowsWithMatchingIds specified
# No operations specified
# Result: Complete table replacement (wipe and sync)
```

</details>

<details>

<summary><strong>Scenario 2</strong>: <code>forRowsWithMatchingIds</code> specified, no <code>operations</code></summary>

**Use case**: Use for simple incremental syncing without deletions.

When `forRowsWithMatchingIds: true` is specified **without** any explicit `operations`, Jigx automatically performs an **upsert-merge** operation:

* **Updates** existing records where the `id` matches
* **Inserts** new records where no matching `id` exists
* **Preserves** existing records that are not in the API response (no deletion)

The `outputTransform` must include a field named `id`, which Jigx uses to match against the `id` column in the target table.

```yaml
provider: DATA_PROVIDER_REST
method: GET
url: https://{api.example.com}/data
useLocalCall: true
# Automatically performs upsert-merge when no operations are specified
forRowsWithMatchingIds: true

outputTransform: |
  {
    "earthquakes": features[].{
      "id": id,
      "place": properties.place,
      "mag": properties.mag,
      "time": properties.time,
      "coordinates": geometry.coordinates,
      "depth": geometry.coordinates[2]
    }
  }
# No operations specified - automatic upsert-merge behavior applies.
```

</details>

<details>

<summary><strong>Scenario 3:</strong> <code>forRowsWithMatchingIds</code> with explicit <code>operations</code></summary>

**Use case**: When you need custom logic, such as handling server-side deletions or complex synchronization.

<mark style="color:red;">**IMPORTANT:**</mark> When you specify explicit `operations`, `forRowsWithMatchingIds` loses its automatic upsert-merge behavior. You must explicitly define the `operations` you want to perform.

This scenario is useful when you need custom synchronization logic, such as:

* Deleting records that no longer exist on the server
* Combining upsert with cleanup operations

```yaml
provider: DATA_PROVIDER_REST
method: GET
useLocalCall: true
url: https://{api.example.com}/ExpenseReceipt
records: =$.data
# forRowsWithMatchingIds is used with explicit operations.
forRowsWithMatchingIds: true

outputTransform: >-
  ={
    "top": @ctx.parameters."$top",
    "skip": @ctx.parameters."$skip",
    "data": @ctx.response.body ? $map(@ctx.response.body, function($item){
      $merge([$item, { "Remote": true }])
    }) : []
  }

operations:
  # First operation: 
  # Delete local records that no longer exist on the server.
  - type: operation.execute-sql
    statements:
      - statement: |
          ="DELETE FROM [expense-receipts] WHERE [id] NOT IN (" & 
          $join($map(@ctx.response.body.id, function($v) { "'" & $v & "'" }), ", ") & 
          ")"
    tables:
      - expense-receipts
  
  # Second operation: 
  # Explicitly define upsert-merge for matching records.
  - type: operation.upsert-merge
    table: expense-receipts
    records: |
      =@ctx.response.body ? $map(@ctx.response.body, function($item){
        $merge([$item, { "Remote": true }])
      }) : []
```

</details>

### Considerations

* Always ensure your `outputTransform` includes an `id` field when using `forRowsWithMatchingIds`.
* When using explicit `operations` ([Scenario 3](#scenario-3-forrowswithmatchingids-with-explicit-operations)), carefully plan your operation sequence.
* Test your synchronization logic thoroughly, especially when handling deletions.


# forRowsWithValues

By default, the JSON payload returned from a REST call replaces all existing data in the SQLite database. The `forRowsWithValues` property allows you to update only specific rows, instead of replacing all records, which results in a smoother user experience.

`forRowsWithValues` defines one or more key-value pairs, where each key is a json\_extract() column in the SQLite table, and the value is the criteria used for matching. Only rows that meet these conditions will be updated. If no match is found, the object is added as a new row.

You can specify multiple key-value pairs under `forRowsWithValues`, which effectively acts as a WHERE clause. Jigx uses this condition when applying the result of the outputTransform to the SQLite table.

Before inserting new data, Jigx deletes all rows that match the `forRowsWithValues` criteria. The user interface is updated only after the data action completes, preventing flickering or intermediate updates. UI refresh occurs as the final step.

{% hint style="info" %}
The property should be passed as a parameter and be referenced in the `outputTransform`.
{% endhint %}

<figure><img src="/files/Ao4YLlvczLcYOxekFVuH" alt="forRowsWithValues" width="563"><figcaption><p>forRowsWithValues</p></figcaption></figure>

## Example code

```yaml
# REST Data Provider with forRowsInRange function example
# This example fetches earthquake data and updates only rows with the value active.
provider: DATA_PROVIDER_REST
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson
useLocalCall: true      
# Input parameters for the range values
parameters:
  mag:
    type: number
    location: query
    required: false
    value: 2.0
  dmin:  
    type: number
    location: query
    required: false
    value: 5.0

# Transform the earthquake data
outputTransform: |
  {
    "earthquakes": features[].{
      "id": id,
      "place": properties.place,
      "mag": properties.mag,
      "time": properties.time,
      "coordinates": geometry.coordinates,
      "depth": geometry.coordinates[2]
    }
  }
operations:
  - type: operation.delete-insert
    table: earthquake_data
    records: |
      =$.earthquakes.{
      "id": id,
      "place": place,
      "mag": mag,
      "time": time,
      "longitude": coordinates[0],
      "latitude": coordinates[1],
      "depth": depth
      } 
    # Only update rows for the specified value.
    forRowsWithValues:
      status: "active"
```


# Operations

Operations in a Jigx function allow you to manipulate data after a REST call completes. They are used to process the response and store it across one or more local SQLite tables. Operations run automatically after the REST function executes and can be defined for both success and error scenarios.

## When and where to use operations

`operations` can be defined in the following places:

* Under the `operations` property in the main function.
* Within `guard` functions.
* Inside the `error` block for error-specific handling.

`operations` are particularly useful when:

* The REST response must be split and inserted into multiple tables.
* You need to control how data is stored in the local SQLite tables, e.g., merge, replace, or delete-insert.
* You want to run custom SQL after a function executes.

## Multi-table operations

Specify multiple output tables and operations for both success and error scenarios.

* Use the operations property to specify an array of operations (executed in sequence) at the top level of the function or under an error handler.
* Each operation specifies an operation `type`, target `table`, and the `records` to use for the operation on the table.
* If the type is `execute_sql` you can specify an array of `statements`, similar to the [action.execute-sql](https://docs.jigx.com/examples/readme/actions/execute-sql) in a jig.
* If you've prepared data using `outputTransform`, you must reference the output in your `operations` or adjust your records to account for the transformed structure. In this case, `operations` will use `ctx.output`, the result of `outputTransform` becomes `ctx.output`.
* Each `operation` targets a `table` and specifies what `records` to insert or update. The `records` property can use JSONata expressions to transform the response data.

{% code title="Operations" %}

```yaml
operations:
  - table: =@.entity
    type: operation.upsert-merge
    records: |
      =$each($.response.body, function($v, $k) {
        $merge([{ "id": $k}, $v])
      })
  - table: local-flags
    type: operation.delete-insert
    records: |
      =$each(response.body, function($v, $k) {
          {
              "id": $k,
              "name": $v.name,
              "flag": $v.emoji
          }
      })
  - table: local-counts
    type: operation.upsert-replace
    records: |
      ={
        'id': 'local-countries',
        'count': $count(@ctx.queries.existing-countries)
      }
```

{% endcode %}

## Operation Property

{% hint style="warning" %}
Operations are not aware of `conversions` configured at the function level. Each operation must define its own `conversions` property to handle file format transformations. Function-level conversions do not cascade to individual operations.
{% endhint %}

<table><thead><tr><th width="193.921875">Property</th><th>Description</th></tr></thead><tbody><tr><td><code>conversions</code></td><td><p>Converting files runs per operation. This holds an array of properties that should be converted. The following properties control the conversion:</p><ul><li><code>property</code>: The name of the property to convert.</li><li><code>from</code>: Format of the input data. It can be buffer, base64, data-uri, or local-uri.</li><li><code>to</code>: Format of the converted data. It can be base64, data-uri, buffer, or local-uri.</li><li><code>convertHeicToJpg</code>: When set to true, and the file being converted is HEIC, it is converted to JPG. </li></ul><p>Conversions can be set up as a static array of definitions or dynamically as an array returned by an expression. To set up dynamic conversions, use the expression:<br> <code>conversions: =@ctx.datasources.conversions</code>, applicable to both local and global actions. See <a href="/pages/AD07IeRxjAQgVvi5AtoX">File handling</a> for details on using conversions in REST functions.</p></td></tr><tr><td><code>forRowsWithValues</code></td><td>Only applies to <code>operation.delete-insert</code></td></tr><tr><td><code>forRowsInRange</code></td><td>Only applies to <code>operation.delete-insert</code></td></tr><tr><td><code>parameters</code></td><td>Only applies to <code>operation.execute_sql</code>. The parameters used in the above statement.</td></tr><tr><td><code>primaryKey</code></td><td>Specify the remote data column that must be used as the primary key in the local data, such as Customer ID. This allows you to specify an expression (<code>=@ctx.record.CustomerID</code>) to define the primary key, including the ability to reference the whole record. This enables the building of dynamic keys, for example, by concatenating multiple fields from the record to construct an ID, timestamp, or GUID.</td></tr><tr><td><code>records</code></td><td>What records to use for the table operation, can manipulate data. Evaluates the expression against the function inputs and result to construct the records for the specified table. The constructed data will be stored in the table.</td></tr><tr><td><code>statements</code></td><td>Only applies to <code>operation.execute_sql</code>. List of statements to execute in sequence. Multiple statements can be configured to execute in sequence.<br><code>statement</code> - the SQL statement to execute against the solution database.</td></tr><tr><td><code>tables</code></td><td>Only applies to <code>operation.execute_sql</code>. The tables affected by the <code>statements</code>. Before executing the statements, a check ensures that the tables exist. After execution any datasources that use these entities will be notified that the database was changed.</td></tr><tr><td><code>timeStamp</code></td><td>Use a timestamp such as last <em>modified</em> from the remote data that must be used as the timestamp in the local table.</td></tr><tr><td><code>type</code></td><td>See the table operations types in the table below.</td></tr><tr><td><code>when</code></td><td>Specify the condition under which the function should execute (default) and when it should be skipped.</td></tr></tbody></table>

## Table Operation Types

Applies to the operations that are performed on the local data from the remote data.

<table><thead><tr><th width="185.54296875">Type</th><th width="230.5703125">Property</th><th>Description</th></tr></thead><tbody><tr><td>DELETE_INSERT<br>(used to sync data)</td><td><code>operation.delete_insert</code></td><td>Deletes old records that match a specified range and rows with matching values and inserts new records.<br>Deletion runs at the beginning of the function.<br>The table is only cleared on non-continuation operations on the first call.<br>Uses this to overwrite the local data with the remote data.</td></tr><tr><td>UPSERT_REPLACE</td><td><code>operation.upsert_replace</code></td><td>Appends new records and replaces matching existing records. (Continuous update).<br>The data of any existing record is replaced with the data from the matched new record.<br>Records are matched by id (primary key).<br>Use this type to append records to the local data and replace any existing records with the same id,<br>leaving unmatched records unchanged and undeleted.</td></tr><tr><td>FIND-REPLACE</td><td><code>operation.find-replace</code></td><td>Executes an operation to find and replace values in local tables. You can also decide whether to find and replace records in the CommandQueue.</td></tr><tr><td>UPSERT_MERGE<br>(used on CRUD methods and output transform)</td><td><code>operation.upsert_merge</code></td><td>Appends new records and merges matching existing records.<br>The data of any existing record is merged with the data from the matched new record.<br>Only top-level properties are copied, overwriting any existing top-level properties.<br>Records are matched by id (primary key).<br>Use this to append records to the local data and merge any existing records with the same id,<br>leaving unmatched records unchanged and undeleted.</td></tr><tr><td>EXECUTE_SQL</td><td><code>operation.execute_sql</code></td><td>Executes a custom SQL operation specified with the SQL statement and parameters. This is the same functionality as the <a href="https://docs.jigx.com/examples/readme/actions/execute-sql">execute-sql</a> action, which runs when a button is tapped; here, it runs when the function finishes or on continuation.</td></tr></tbody></table>

## Expressions

<table><thead><tr><th width="115.1015625"></th><th></th><th></th></tr></thead><tbody><tr><td>records</td><td><code>=@ctx.record.{primaryKey}</code></td><td>Defines the primary key, including the ability to reference the full record.</td></tr></tbody></table>

## Example code

The example code below defines a series of database operations that process and store folder data from the ClickUp REST API.

<pre class="language-yaml"><code class="lang-yaml">operations:
# Only when there's NO X-opsPrimaryKey parameter (bulk processing mode) then,
<strong># Deletes all existing records from folders-split-queries table
</strong># Inserts new records by transforming each folder from $.folders array.
<strong># Maps folder data to a flattened structure with space information included.
</strong>  - type: operation.delete-insert
    table: folders-split-queries
    when: =$not($boolean(@ctx.parameters.X-opsPrimaryKey))
    records: |
      =$.folders.{
        "id": id,
        "name": name,
        "orderIndex": orderindex,
        "overrideStatuses": override_statuses,
        "hidden": hidden,
        "archived": archived,
        "task_count": task_count,
        "spaceId": space.id,
        "spaceName": space.name
      }
   # Store Specific Folder (Primary Key Mode)
   # Only when X-opsPrimaryKey parameter exists (single record mode), then
   # Uses either the provided primary key OR the output name as the primary key.
   # Targets a specific record for update rather than bulk processing.
   # Same data transformation as above but for targeted updates.  
  - primaryKey: >
      =$boolean(@ctx.parameters.X-opsPrimaryKey) ?
      @ctx.parameters.X-opsPrimaryKey:@ctx.output.name
    type: operation.delete-insert
    table: folders-split-queries-primary
    when: =$boolean(@ctx.parameters.X-opsPrimaryKey)
    records: |
      =$.folders.{
        "id": id,
        "name": name,
        "orderIndex": orderindex,
        "overrideStatuses": override_statuses,
        "hidden": hidden,
        "archived": archived,
        "task_count": task_count,
        "spaceId": space.id,
        "spaceName": space.name
      }
  # Iterate through each folder,
<strong>  # for each list within a folder, creates a record linking the list to its 
</strong><strong>  # parent folder. Processes lists that don't belong to any folder.
</strong>  # Sets folderId and folderName to null
  # Uses $append() to merge folder-based lists and folderless lists into a single array.
  - type: operation.delete-insert
    table: lists-split-queries
    # Convert list thumbnails from buffer to local-uri for efficient storage
    # Operations are not aware of conversions configured at the function level. 
    # Each operation must define its own conversions property to handle file 
    # format transformations. 
    # Function-level conversions do not cascade to individual operations.
    conversions:
      - property: listThumbnail
        from: buffer
        to: local-uri
        convertHeicToJpg: true
    records: |
      =$append(
        $reduce(folders, [], function($acc, $folder) {
          $append($acc,
            $map($folder.lists, function($list) {
              {
                "listId": $list.id,
                "listName": $list.name,
                "listThumbnail": $list.thumbnail,
                "folderId": $folder.id,
                "folderName": $folder.name
              }
            })
          )
        }),
        $map(@ctx.queries.folderless-lists, function($list) {
          {
            "listId": $list.listId,
            "listName": $list.listName,
            "listThumbnail": $list.thumbnail,
            "folderId": null,
            "folderName": null
          }
        })
      )
</code></pre>

## Chaining two execute calls

In complex scenarios where multiple `execute-entity` calls must be chained, for example, when the result of a local write must be reconciled with a server-generated ID returned by a subsequent REST call the `operations` block requires specific configuration to ensure records are correctly matched and updated without duplicates. This includes the order in which `operation.find-replace` and `operation.upsert-merge` are declared, and when to set `includeCommandQueue: true`. See [Chaining execute-entity calls](https://docs.jigx.com/building-apps-with-jigx/data/data-providers/rest/functions/pages/fARsK2tCXjiKjZFLiDAg#chaining-calls-vs.-automatic-temp-id-replacement) in REST Best Practices for the full pattern and explanation.


# Queries

The `queries` property allows you to define Just-In-Time (JIT) queries that are executed when a function runs. These queries retrieve local data from the SQLite database at the moment the function executes, ensuring that decisions and operations are based on the most current information available.

## Purpose and benefits

* Ensures accuracy by querying local tables at runtime.
* Reduces stale data by removing the need to store older data in the Command Queue.
* Supports offline use by relying on local data, not remote API calls.
* Improves flexibility by allowing conditional logic or table operations to be based on the current state.

## How queries work

* Queries are **evaluated** at the time the function executes (when it comes off the command queue).
* They are **re-evaluated** on continuation unless `onContinuation: false` is explicitly set.
* Results of the queries are available in expressions using:\
  `=@ctx.queries.{query-name}`

## Result types

The `resultType` property lets you control the format of the returned data:

<table><thead><tr><th width="182.44921875">Type</th><th>Description</th><th>Returned value</th></tr></thead><tbody><tr><td><code>records</code> (default)</td><td>Returns all matching records</td><td>Array of objects</td></tr><tr><td><code>record</code></td><td>Returns the first matching record</td><td>Single object</td></tr><tr><td><code>scalar</code></td><td>Returns a single value from the first column of the first record</td><td>Single value (string, number, etc.)</td></tr></tbody></table>

If no records match the query:

* records returns an empty array \[]
* record and scalar return null

In this example:

* current-record uses a parameter to fetch a specific country from the local table.
* existing-countries fetches all records from the local/countries table.

{% code title="Queries" %}

```yaml
# In the function definition.
queries:
  current-record:
    statement: SELECT * FROM [local/countries] WHERE [id] = @id
    parameters:
      id: =@.parameters.countryId
  existing-countries:
    statement: SELECT * FROM [local/countries]
```

{% endcode %}

You can access the results in other parts of the function like this:

{% code title="YAML" %}

```yaml
records: =@ctx.queries.existing-countries
```

{% endcode %}

## Queries properties

<table><thead><tr><th width="162.85546875">Properties</th><th>Description</th></tr></thead><tbody><tr><td><code>dependencies</code></td><td>The queries that this query depends on. They will be executed before this query. Dependencies allow you to stop recursive queries, because queries can be inputs to each other.</td></tr><tr><td><code>jsonColumns</code></td><td>The columns that are automatically parsed as JSON string.<br>Defaults to no JSON columns to parse.</td></tr><tr><td><code>onContinuation</code></td><td>Set to false re-runs the query on each continuation of the function. Defaults to true, so the query only runs initially by default and not again on each continuation.</td></tr><tr><td><code>parameters</code></td><td>Named parameters used in the query statement. They are referenced using the @ prefix (e.g., @id). If not prefixed manually, the @ is automatically added. Defaults to no parameters.</td></tr><tr><td><code>resultType</code></td><td>Defines the expected result format. Can be one of: records (default), record, or scalar.</td></tr><tr><td><code>statement</code></td><td>The SQL query statement to execute.</td></tr><tr><td><code>tables</code></td><td>The tables to use in the query. Defaults to none. These tables are validated to exist before the query is executed.</td></tr></tbody></table>


# When

The when property allows you to control when a function, operation, guard, or error handler should execute. It uses a condition, typically based on the local state of the database. This makes functions more dynamic by ensuring they only run when certain conditions are met, helping to optimize performance, avoid redundant calls, and manage conditional logic efficiently.

* Conditionally skip function execution based on local state or query results.
* Prevent unnecessary API calls by checking if a condition has already been met.
* Dynamically execute operations or error handlers only under certain circumstances.
* Evaluate conditions on continuation unless configured otherwise.

## Where to use the when property

<table><thead><tr><th width="154.95703125">Where</th><th>When</th></tr></thead><tbody><tr><td><code>Main function</code></td><td>Determines whether the function should be executed. The when expression is evaluated after the parameters and queries are evaluated. The <code>when</code> expression is evaluated before token credentials are checked and <code>inputTransforms</code> are evaluated. The <code>when</code> expression is re-evaluated on each <code>continuation</code>.</td></tr><tr><td><code>Operations</code></td><td>Determines whether the operation should execute. Useful for selectively inserting, updating, or transforming data.</td></tr><tr><td><code>Error handler</code></td><td>Determines the conditions under which the error should be executed. Specify one or more error handling definitions. The first rule that matches the <code>when</code> condition will be used. A rule without a <code>when</code> condition will become the default error handler. If no rules are specified, default error handling will be used, i.e., checking for actual errors or using HTTP status codes and messages for REST providers.</td></tr><tr><td><code>Guard function</code></td><td>Evaluates whether the guard function should run, allowing conditional validation or control.</td></tr></tbody></table>

{% code title="when" %}

```yaml
provider: DATA_PROVIDER_REST
method: DELETE
url: https://rest-data-service.net/api/v0.1/collections/books/items/{id}
when: =@ctx.solution.settings.custom.fiction
```

{% endcode %}

## Examples and code snippets

### Conditional Function Execution

{% code title="main-when-function" %}

```yaml
provider: DATA_PROVIDER_REST
url: https://graph.microsoft.com/v1.0/me/drive/root/children
method: GET
# Determine conditions when the main function executes.
when: =@ctx.queries.current-record ? false:true 
useLocalCall: true

parameters:
  $top:
    location: query
    type: number
    required: false
  accessToken:
    location: header
    type: microsoft
    value: jigx.microsoft.oauth
    required: true
    
# In the function definition.
queries: 
  current-record: 
    statement: SELECT * FROM [local-countries] WHERE [id] = @id
    parameters:
      id: =@.parameters.countryId
  existing-countries:
    statement: SELECT * FROM [local-countries]
    jsonColumns: =@ctx.entity
```

{% endcode %}

### Custom error handling error

This custom error message is shown only when the response status of 503 is recieved from the server.

{% code title="when-error" %}

```yaml
error: 
  - title: Server is temporarily unavailable
    description: |
      The server is currently unavailable, please try again in a few minutes.
    details: =@ctx.response.body
    icon: on-error-sad
    notification: true
    operations:
      - type: operation.delete-insert
        table: =@ctx.entity & "_error"
    # Condition that determines when a 503 custom error message executes.    
    when: =@ctx.response.status = 503
```

{% endcode %}


# JavaScript in functions

Use custom JavaScript in REST function expressions to define complex logic directly within parameters, headers, errors, and transformations. JavaScript enables advanced data manipulation, conditional logic, and formatting beyond the capabilities of standard expressions, offering greater flexibility and control when integrating with external REST APIs.

## Configuration

1. Create the JavaScript file in Jigx Builder in the *scripts/expressions* folder.
2. Reference the expression in the function file. Use IntelliSense to select the required JavaScript expression.

## Example and code snippets

The `coalesce` export function in the JavaScript code below returns the first non-null, non-undefined, and non-empty-string value from the list of candidates provided. If none of the candidates are valid (i.e., all are null, undefined, or empty string), it returns undefined.

```javascript
// scripts/expressions/utils.js
export function coalesce(...candidates) {
    console.log('coalesce', JSON.stringify({ candidates }));
    for (let candidate of candidates) {
        if (candidate !== null && candidate !== undefined && candidate !== '') {
            return candidate;
        }
    }
    return undefined;
}
```

The JavaScript file is used as expressions in the function's:

1. Header parameter - Use the configured API key or a default.
2. Input transform - Use the user's name or email or defaults to unknown.
3. Error handling - Extract the most relevant error message for display and condition check.

{% code title="Function" %}

```yaml
provider: DATA_PROVIDER_REST
method: POST
url: https://[your_rest_service]/api/customers  
useLocalCall: true

parameters:
  x-api-key:
    type: string
    location: header
    required: false
    value: =$utils.coalesce(@ctx.solution.settings.custom.restStorageApiKeyx, 'abc123')
  title:
    type: string
    location: body
  description:
    type: string
    location: body
    required: false
  authors:
    type: string
    location: body
    required: false

inputTransform: |
  ={
    "title": @ctx.parameters.title,
    "description": @ctx.parameters.description,
    "authors": @ctx.parameters.authors,
    "createdBy": {
      "id": @ctx.user.id,
      "name": $utils.coalesce(@ctx.user.displayName1, @ctx.user.email2, 'unknown')
    }
  }

outputTransform: |
  {
      "id": $substringAfter($$.headers.location, '/items/')
  }

error:
  - when: =$contains($utils.coalesce(@ctx.error.message, @ctx.error.title, @ctx.error.description), 'no access')
    notification: true
    title: "='Access denied: ' & @ctx.error.message"
    description: "='Access denied: ' & @ctx.error.message"
    table: sync_error
    transform: =@ctx.error
```

{% endcode %}


# REST error handling

REST errors returned by the endpoints in an app are often too technical for end-users to comprehend. Jigx allows you to customize these error messages to improve user experience, communicate more effectively, and ensure users understand that errors are not their fault. By configuring custom error handling, you can:

* Suppress or customize default error messages. See [Configuring error alerts](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/configuring-error-alerts).
* Log error details for more effective debugging. See [Error logging and debugging](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/error-logging-and-debugging).
* Create more robust and user-friendly error solutions. See [Working with commandQueue](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/working-with-commandqueue).

## Key features

* **Custom error messages**: Control the message shown to users when a REST error occurs.
* **User-friendly retry options**: Allow users to retry an action when an error occurs.
* By default, Jigx automatically catches any **429 error responses** and retries the request up to three times, with a five-second delay between each attempt.
* By default, Jigx automatically catches any 401 error responses and retries the request up to three times.
* **Error logging**: Automatically log error details for debugging.
* **Dynamic responses**: Build logic to respond to specific errors flexibly.

{% columns %}
{% column %}

<figure><img src="/files/5cydYyxulqeCNGW1BYyh" alt="Standard error handling"><figcaption><p>Standard error handling</p></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/cnv74NHlmdiqkE6xsLll" alt="Customized error handling with alert"><figcaption><p>Customized error handling with alert</p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### Common Error Scenarios

* Network failures
* Authentication/authorization errors
* Rate limiting
* Server errors vs client errors

## How does it work

In Jigx, REST error handling is configured through an `error` section in the REST function. This allows the system to catch various error responses and act accordingly:

* Multiple error responses can be defined and are evaluated in sequence.
* Error responses can trigger notifications, [log errors](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/error-logging-and-debugging), or provide retry options for users.
* The app supports customized [alert messaging](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/configuring-error-alerts) as a toast or modal for each error type.
* Expressions are supported in functions.

### **High level steps**

Before diving into details, here's what you need:

1. Configure the `error` section in the REST **function**&#x20;
2. Define error conditions with `when`
3. Create a **datasource** for the error table.
4. Configure user [alerts](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/configuring-error-alerts) and/or logging
5. (Optional) - Create a **UI** (jig) for error management, to process the errors in the queue using the [commandQueue](/building-apps-with-jigx/data/data-providers/rest/rest-error-handling/working-with-commandqueue) actions.

## Considerations

* By default, Jigx automatically handles `429` (Too Many Requests) error responses for CRUD and sync methods by retrying the request up to three times, with a five-second delay between each attempt. If the request still fails after the third retry, the error is raised in the app. You can customize this behavior by configuring the handling of the 429 status in the `error` property.
* When configuring error handling with `alerts`, ensure that HTTP 200 (success) responses are excluded. If not, the app may treat successful responses as errors, preventing data from loading.
* Errors are automatically grouped by default to prevent alert overload, unless a custom error handler is explicitly configured.&#x20;

## REST Function

In the [Jigx function file](/building-apps-with-jigx/jigx-builder-code-editor/editor#solution-scaffolding), configure the `error` section to cater for:

* Customizing the error message.
* Determining if a toast or modal alert notification is required or not.
* Group related alerts to prevent multiple alerts from stacking one after another.
* Writing the context of the error to a table for debugging and configuring actions to fix the error.

Multiple error handlers can be added in the function, which are executed from the top to bottom until one matches. The error section needs to be configured in each of the individual REST function files.

<figure><img src="/files/rn7SaziBflS8ya1mykua" alt="Error function alert properties"><figcaption><p>Error function alert properties</p></figcaption></figure>

## Configuration properties

The following properties are available for configuration when handling REST errors:

<table><thead><tr><th width="121.34375">Property</th><th>Description</th></tr></thead><tbody><tr><td><code>alert</code></td><td>See <a href="/pages/98kONBD4ibhCYJzNJIaY">Configuring error alerts</a>.</td></tr><tr><td><code>description</code></td><td><p>Description of the error for logging purposes.</p><p>Provide a detailed message of the error to write to the logs. Defaults to the provider's description if absent. For example, the REST provider uses the HTTP status code and message. The description property supports <a href="/pages/pYaYhC972Spa5bOYXsGg">localization</a>. </p></td></tr><tr><td><code>details</code></td><td>Add additional error details for logging purposes. Defaults to the provider's details if absent.</td></tr><tr><td><code>notification</code></td><td>Determines whether the error alert message notification should be shown on the device. (true/false)</td></tr><tr><td><code>operations</code></td><td><p>Additional table operations for the error table. See <a data-mention href="/pages/htfriCQTAbMWrvlrjmxO">/pages/htfriCQTAbMWrvlrjmxO</a> for more details.</p><ul><li>Specify none or more conditional table operations/transforms. </li><li>Each operation is evaluated in the order specified, if the <code>when</code> condition is met it is executed.</li><li>If a table is not specified, the default table will be used ("{entity}_error").</li><li>If the same table is specified multiple times, then each operation will be executed in order.</li><li><code>table</code>: Define a table where the error information specified in the <code>transform</code> property will be logged to, for example: <code>table: =@ctx.entity &#x26; "_error"</code></li><li><code>records</code>: Specifies the details to log in the table for the error, such as the request, response, and user context, for example: <br><code>'={ "id": @ctx.commandId, "type": "System Offline", "response": @ctx.response, "request": @ctx.request, "user": @ctx.user, "solution": @ctx.solution, "entity": @ctx.entity, "correlationId": @ctx.correlationId}'</code></li></ul></td></tr><tr><td><code>retry</code></td><td>Provides the ability to configure an automatic retry, set a <code>delay</code> time before the retry is executed, and specify the <code>maximum</code> number of retries allowed. By default, Jigx automatically handles <strong>429</strong> (Too Many Requests) error responses for CRUD and sync methods by retrying the request up to three times, with a five-second delay between each attempt. If the request still fails after the third retry, the error is raised in the app. You can customize this behavior by configuring the handling of the 429 status in the <code>error</code> property.</td></tr><tr><td><code>title</code></td><td>Title of the error for logging purposes. Defaults to the provider's title if not provided. The title property supports <a href="/pages/pYaYhC972Spa5bOYXsGg">localization</a>.</td></tr><tr><td><code>when</code></td><td><p>Checks if the result of the function is an error, the first one that resolves to true is used. </p><ul><li>The REST provider uses a combination of actual errors encountered and the HTTP status code and message. </li><li>Configure different types of actions depending on the error received, by using multiple <code>when</code> statements. </li><li>If the property is not configured it defaults to the REST provider's default error check.</li></ul></td></tr></tbody></table>

## Basic configuration example

{% code title="rest-function" %}

```yaml
# Configure an error section in each function file for REST endpoint,
# where errors can occur.
error:
  # Configure details for each error status code.
  - when: =@ctx.response.status = 403
    # Determine if an alert should be shown to the user.
    notification: true
    # Configure the type, details, and style of the alert to be shown to the user.
    alert:
      title: System Offline
      description: 
        It looks like our system is temporarily unavailable.
        We're working hard to fix this and get things back on
        track. Please try again in a little while. Thank you
        for your patience!
      icon: server-error-403-hand-forbidden
      style:
        isNegative: true
      # Presentation style (overlays the current screen), can be modal or toast.   
      presentAs: toast
      # Grouping allows you to manage multiple alerts under a shared identifier. 
      # This ensures that only one alert from a group is visible at a time
      group:
        id: code403
    # Configure information to be logged in the datasync-error table.  
    title: System Offline
    description: System is temporarily unavailable.
    details: =@ctx.response.body
    # Configure the data operation to be performed on the error table.
    operations:
      - type: operation.upsert-merge
        table: datasync-error
        records: 
          '={ "id": @ctx.parameters.syncId, "type": "System Offline",
          "response": @ctx.response, "request": @ctx.request, "user": @ctx.user, "solution": @ctx.solution,
          "entity": @ctx.entity, "correlationId": @ctx.correlationId}'
    # Set an automatic retry, specify the delay before the retry is actioned,
    # Set the number of retries allowed.
    retry:
      delay: "=(@.response.headers.'retry-after' ? $number(@.response.headers.'retry-after') : 5)*1000"
      maxRetries: 3
```

{% endcode %}

## Configuring OAuth error messages

* When `useLocalCall: true` is set, functions that rely on secrets or other authentication mechanisms not available locally will not execute.
* For full details on configuring OAuth error messages, see [Configuring OAuth error messages](#configuring-oauth-error-messages).

## Examples and code snippets

* See [REST error example](/building-apps-with-jigx/data/data-providers/rest/rest-overview) to understand how to configure error responses in a REST function, create a error table and use the commandQueue with actions to process the error.
* See [Configuring OAuth error messages](#configuring-oauth-error-messages) for an example of customizing OAuth error messages.


# Configuring error alerts

Configure a user-friendly message of the error to be sent to users, for example, "*It looks like our system is unavailable*."

## Alert configuration properties

<table><thead><tr><th width="182.37890625">Properties</th><th>Description</th></tr></thead><tbody><tr><td><code>actions</code></td><td>Interactive buttons or controls displayed within the alert let users respond or take specific actions. Use IntelliSense to see the list of available <a href="/pages/CvGD1xFf2OBCbuTYlFuf">actions</a>.</td></tr><tr><td><code>title</code></td><td>The main heading text is displayed at the top of the alert.</td></tr><tr><td><code>description</code></td><td>The detailed message content that explains the alert’s purpose, provides instructions, or delivers additional information to the user.</td></tr><tr><td><code>dismiss</code></td><td><p>Configures how users can dismiss the alert. You can enable a gesture dismissal and set an automatic dismissal time.</p><ul><li><code>autoAfter</code> - specify the number of seconds after which the alert is automatically dismissed. Has no effect when <code>dismiss</code> is disabled.</li><li><code>isEnabled</code> - When set to <code>true</code> (default), allowing manual dismissal by swiping down. When set to <code>false</code>, the alert cannot be dismissed manually.</li></ul></td></tr><tr><td><code>icon</code></td><td>The icon displayed alongside the alert content provides visual context and helps users recognize the alert’s type or purpose. The alert’s <code>style</code> property determines the icon color. If no style is set, the default <code>isWarning</code> style is applied.</td></tr><tr><td><code>group</code></td><td>Grouping allows you to manage multiple alerts under a shared identifier. This ensures that only one alert from a group is visible at a time, preventing alert overload and improving the user experience.</td></tr><tr><td><code>group</code></td><td><p><code>id</code> - Identifier for the alert group. Only one alert per group can be visible at a time. If a new alert with the same group ID is triggered while another is active, it will be skipped.</p><p>Use <code>groupId</code> to manage multiple alerts for the same issue. When using <code>modal</code> presentation, alerts with the same <code>groupId</code> are grouped so that only the first alert appears and subsequent ones are automatically skipped. When using <code>toast</code> presentation, alerts are also grouped, preventing duplicates. Users can tap the <code>toast</code> to view details — if multiple alerts exist, they stack and display a count at the top. Swiping left lets users view each alert’s details within the stack.</p></td></tr><tr><td><code>group</code></td><td><p><code>presentAs</code>: Specifies how the alert is presented to the user. Options include:</p><ul><li> <code>toast</code> (default):  For brief, lightweight notifications. </li><li><code>modal</code>: For important messages that require attention and may include additional information. Modal alerts are more disruptive since they block the UI and are typically used for critical information.</li></ul></td></tr><tr><td><code>style</code></td><td><p>Visual styling options let you set the tone of the alert:</p><ul><li><code>isPositive</code> (success/confirmation)</li><li><code>isNegative</code> (error) styling to convey the appropriate tone and urgency. </li><li><code>isWarning</code> (warning) styling is used by default.</li></ul></td></tr><tr><td><code>subtitle</code></td><td>Secondary text that appears below the <code>title</code>, providing additional context or supplementary information.</td></tr></tbody></table>

## Alert presentation types

When an error occurs, Jigx can present alerts to users in two ways:&#x20;

* As a **toast**&#x20;
* As a **modal**

Choosing the right presentation type depends on the severity of the error and how disruptive you need the notification to be.

## Automatic vs custom error grouping

### Automatic error grouping

Errors are automatically grouped by default to prevent alert overload, unless a custom error handler is explicitly configured.<br>

* Errors are auto-grouped using the following key:

```yaml
{solutionId}/{hostUrl}/{errorCode}
```

* If the hostUrl cannot be resolved, grouping falls back to:

```yaml
{functionId}
```

* When multiple functions encounter the same error on the same host, only one alert is shown, the first failure triggers the alert.
* Custom error handlers that specify a different `groupId` are not auto-grouped and will display as separate alerts.
* To reduce user frustration in edge cases where not all errors are grouped, the **Close All** option is available. You can further refine grouping behavior by explicitly defining `groupId` values in your error handler configuration.

### Custom error grouping

You can explicitly control how errors and alerts are grouped by assigning a `groupId`. Grouping ensures that only one alert per group is shown at a time, helping to reduce duplicate or repetitive messages.

When an alert is triggered with a `groupId` that matches an active alert, subsequent alerts in the same group are skipped.

* **Modal alerts**: Alerts with the same `groupId` are grouped so that only the first alert is displayed.
* **Toast alerts**: Alerts are grouped to prevent duplicates. If multiple alerts exist, they stack and display a count indicator. Users can tap the toast to view details and swipe left to navigate between alerts in the stack.

Use custom error grouping when you want precise control over how related errors are presented to users, especially when handling recurring or function-specific failures.

## Examples and code snippets

```yaml
 alert:
      title: System Offline
      description: 
        It looks like our system is temporarily unavailable.
        Please try again in a little while. Thank you for your patience!
      icon: server-error-403-hand-forbidden
      style:
        isNegative: true
      # Presentation style (overlays the current screen), can be modal or toast.   
      presentAs: toast
      # Grouping allows you to manage multiple alerts under a shared identifier. 
      # This ensures that only one alert from a group of errors is visible.
      group:
        id: code403
    # Configure information to be logged in the datasync-error table.  
    title: System Offline
    description: System is temporarily unavailable.
    details: =@ctx.response.body
```


# Error logging and debugging

Logging errors is a crucial part of the error handling mechanism. Errors are logged into a dedicated error `table` defined by you, capturing key information for debugging and analysis. Take the information that you currently have in the context of the function and log it using the `operations` properties to the table by defining the data to be logged in the `records` property.&#x20;

* The full error coming back from the backend system should be logged.
* Expose error tables in Jigx Builder to help with troubleshooting.
* Define a datasource against the error tables.

## **Error logging configuration**

When configuring REST errors, several system expressions and variables can be used. These variables allow you to dynamically log and handle errors based on the context of the function call. The following context is available to write to the error table, using `=@ctx.variable.value`:

<table><thead><tr><th width="141.3203125">Variables</th><th>Value</th></tr></thead><tbody><tr><td>commandId</td><td>Unique id logged for the item on the commandQueue. The id matches the id in the entity table.</td></tr><tr><td>correlationId</td><td>The unique identifier that appears in the app. It is used in <a href="/pages/1KabNyxZYAZJKrcRXHME">troubleshooting</a> to help identify specific entries in the logs and to follow the user's journey while using the solution in the app. By filtering logs using this ID, you can troubleshoot issues more effectively.</td></tr><tr><td>entity</td><td>The specified table where the error context is logged</td></tr><tr><td>error</td><td><ul><li>message: string</li><li>title: string</li><li>description: string</li><li>details: string</li><li>icon: string</li><li>table: string</li><li>notification: boolean</li></ul></td></tr><tr><td>parameters</td><td>Specify any of the parameters in the function to be logged to the error table.</td></tr><tr><td>request</td><td><ul><li>method: string</li><li>url: string</li><li>headers: Record&#x3C;string, string></li><li>body:string</li><li>Buffer</li></ul></td></tr><tr><td>response</td><td><ul><li>ok: boolean</li><li>status: number</li><li>statusText: string</li><li>headers: Record&#x3C;string, string></li><li>body: any</li></ul></td></tr><tr><td>solution</td><td><ul><li>id: SolutionId</li><li>name: SolutionName</li><li>organizationId: OrganizationId</li><li><p>settings:</p><ul><li>custom: Record&#x3C;string, unknown></li></ul></li></ul></td></tr><tr><td>user</td><td><ul><li>id: string</li><li>email: string</li><li>displayName: string</li><li>avatarUrl: string</li><li>phone: string</li><li>isVerified: boolean</li><li>settings: Record&#x3C;string, unknown></li></ul></td></tr></tbody></table>

{% tabs %}
{% tab title="function-error-table" %}

```yaml
error:
  # Configure details for each erro status code.
  - when: =@ctx.response.status = 403   
    # Configure the error table and the data to log to the table,
    # in the error section of the function. 
    operations:
      - type: operation.upsert-merge
        table: =@ctx.entity & "_error"
        records: 
          '={ "id": @ctx.commandId, "type": "System Offline", "response": @ctx.response,
          "request": @ctx.request, "user": @ctx.user, "solution": @ctx.solution,
          "entity": @ctx.entity, "correlationId": @ctx.correlationId}'  
        timestamp: remoteSystemTimestamp          
```

{% endtab %}

{% tab title="error-datasource" %}

```yaml
# Call the error details from the dedicated error table in a datasource.
# Use the datasource to configure jigs to action the error, e.g. retry.
type: datasource.sqlite
options:
  provider: DATA_PROVIDER_LOCAL
  entities:
    - entity: datasync-error
  query: SELECT
    id,
    json_extract(err.data, '$.response.ok') as ok,
    json_extract(err.data, '$.response.status') as status,
    json_extract(err.data, '$.response.statusText') as statusText,
    json_extract(err.data, '$.response.headers') as headers,
    json_extract(err.data, '$.response.body') as body,
    json_extract(err.data, '$.screen') as screen,
    json_extract(err.data, '$.type') as type
    FROM
    [datasync-error] AS err
```

{% endtab %}
{% endtabs %}




---

[Next Page](/llms-full.txt/1)

