# Form.io Reporting Module

## Overview

### How It Works&#xD;

The Reporting Module uses MongoDB's Aggregation Pipeline, a framework for transforming and combining data from multiple sources. This allows you to:

* Join data from multiple forms
* Perform calculations on field values
* Group and summarize data
* Filter and sort results

You don't need MongoDB expertise to use basic reporting features. However, understanding aggregation concepts helps when creating advanced reports.

Learn More: See [MongoDB Aggregation Pipeline](https://www.mongodb.com/docs/manual/core/aggregation-pipeline/) for detailed information.

### Prerequisites <a href="#knowledge-prerequisites" id="knowledge-prerequisites"></a>

{% hint style="info" %}
A [Form.io Library License](https://help.form.io/deployments/licenses/library-licenses) with Reporting Module enabled is **required** to use the *@formio/reporting* module. Contact <sales@form.io> to acquire or upgrade your license.
{% endhint %}

#### Technical Requirements <a href="#technical-requirements" id="technical-requirements"></a>

* &#x20;*formio-enterprise* v8.4.1 or greater

#### Access Requirements <a href="#access-requirements" id="access-requirements"></a>

Your users need these permissions to view reports:

| Access Context        | Permission Required                |
| --------------------- | ---------------------------------- |
| Project Level         | Read All: Authenticated            |
| Reporting UI Resource | Read All Submission: Authenticated |
| Source Forms          | Read All Submission: Authenticated |

## Getting Started <a href="#getting-started" id="getting-started"></a>

This section walks you through creating and embedding your first report.

#### Step 1: Enable Reports in Your Project <a href="#step-1-enable-reports-in-your-project" id="step-1-enable-reports-in-your-project"></a>

Once the Reporting Module is enabled on your license, a **Reports** section appears in your project's navigation sidebar.

> **Note for Existing Projects:** Projects created before Reporting Module activation may lack the Reporting UI resource. See [Troubleshooting](#troubleshooting) to resolve this.

#### Step 2: Create Your First Report <a href="#step-2-create-your-first-report" id="step-2-create-your-first-report"></a>

1. Navigate to your project in the Form.io portal
2. Click **Reports** in the left sidebar
3. Click **New Report**
4. Enter a **Report Title**
5. Click the **Source Forms** tab
6. Select one or more forms from the dropdown
7. Click the **Columns** tab
8. Select the columns you want to display
9. Click **Submit Form** to save

Your report now appears in the Reports list. Click **Preview** to see the report structure.

> **Note:** The portal preview doesn't fetch live data. To see actual submission data, embed the report in an application.

#### Step 3: Embed the Report <a href="#step-3-embed-the-report" id="step-3-embed-the-report"></a>

Install the reporting module in your application:

```bash
npm install --save @formio/reporting
```

Or with yarn:

```bash
yarn add @formio/reporting
```

Add the report to your application:

```javascript
import { Formio } from '@formio/js';
import { Reporting } from '@formio/reporting';
import '@formio/reporting/reporting.css';

// Register the Reporting module
Formio.use(Reporting);

// Set your license key
Formio.setLicense('YOUR_LICENSE_KEY');

// Create the report
const reportElement = document.getElementById('report-container');
const reportUrl = 'https://your-project.form.io/report/employee-overview';

Formio.Report.create(reportElement, reportUrl)
  .then((report) => {
    console.log('Report loaded successfully');
  })
  .catch((error) => {
    console.error('Failed to load report:', error);
  });
```

**Expected Result:** The report grid displays in your `#report-container` element with your form's submission data.

## Report Structure <a href="#report-structure" id="report-structure"></a>

An embedded report consists of two main components:

#### Reporting Grid <a href="#reporting-grid" id="reporting-grid"></a>

The main data display area. It provides:

* **Pagination** - Navigate through large data sets
* **Sorting** - Click column headers to sort ascending/descending
* **Row Selection** - Select rows for bulk actions
* **Column Filtering** - Filter data within specific columns (when Controls are disabled)
* **Column Visibility** - Show/hide columns from the grid header menu

#### Reporting Controls (Optional) <a href="#reporting-controls-optional" id="reporting-controls-optional"></a>

A collapsible panel above the grid for data management:

* **Filters** - Apply custom filters to the data
* **Column Visibility** - Toggle which columns display
* **Actions** - Execute operations on selected rows (export, custom actions)

You can enable or disable the Controls panel in the report settings.

***

## Guides <a href="#guides" id="guides"></a>

### **Prerequisites**

To follow along with the guides, import the example Forms into a project using the following embed URLs.

1. **Import** the [**Department**](#user-content-fn-1)[^1] Resource using the embed URL below into your project\
   <https://documentation.form.io/department>
2. Import the **Salary Resource** using the embed URL below into your project\
   <https://documentation.form.io/salary>
   * Edit the Department select component and navigate to the **Data** tab.&#x20;
   * Click the **Resource** dropdown and select the **Department** Resource.&#x20;
   * Click the **Value** **Property** field and select **Department**
3. **Import** the **Employee** form into your project\
   <https://documentation.form.io/employee>
   * Edit the Department select component and navigate to the **Data** tab.&#x20;
   * Click the **Resource** dropdown and select the **Department** Resource.&#x20;
   * Click the **Value** **Property** field and select **Department**
4. **Import** the **Employee Evaluation** form into your Project\
   <https://documentation.form.io/employeeevaluation>
   * Edit the Department select component and navigate to the **Data** tab.&#x20;
   * Click the **Resource** dropdown and select the **Department** Resource.&#x20;
   * Click the **Value** **Property** field and select **Department**

### Create a Single-Form Report <a href="#create-a-single-form-report" id="create-a-single-form-report"></a>

Use this approach when reporting on data from one form.

{% embed url="<https://www.loom.com/share/54ea29e4718146cdb3af2d46c5e24304>" %}

**Scenario:** Create an Employee Overview report showing employee names, departments, and start dates.

1. Go to **Reports** > **New Report**
2. Set **Report Title** to "Employee Overview"
3. Click **Source Forms** tab
4. Select **Employee** from the dropdown
5. Click **Columns** tab
6. Select columns: Employee ID, First Name, Last Name, Department, Start Date
7. Click **Submit Form**

**Result:** A report displaying all Employee submissions with the selected columns.

***

### Create Calculated Columns <a href="#create-calculated-columns" id="create-calculated-columns"></a>

Use calculated columns to derive new values from existing fields.

**Scenario:** Combine First Name and Last Name into a single "Full Name" column.

1. Open your report for editing
2. Click the **Calculated Columns** tab
3. Click **+ Add Column**
4. Set **Column Title** to "Full Name"
5. Set **Column Key** to "fullName"
6. Select **Concatenate Strings** from the Operator dropdown
7. In Arguments, click **+ Add Another** and select:
   * First argument: **First Name**
   * Second argument: (space character or add another field)
   * Third argument: **Last Name**
8. Click **Save**
9. Go to **Columns** tab and add "Full Name" to your selected columns
10. Click **Submit Form**

**Available Operators:**

| Operator               | Description                  | Example Use               |
| ---------------------- | ---------------------------- | ------------------------- |
| Array Size             | Count items in an array      | Count languages spoken    |
| Concatenate Strings    | Join text values             | Combine first + last name |
| Date Difference        | Calculate time between dates | Employee tenure           |
| Day of Month/Week/Year | Extract date parts           | Group by day              |
| Month Number           | Extract month (1-12)         | Monthly reports           |
| Week Number            | Extract week (0-53)          | Weekly reports            |
| Year                   | Extract year                 | Annual reports            |
| Divide                 | Divide two numbers           | Calculate ratios          |
| Multiply               | Multiply numbers             | Calculate totals          |
| Summarize (Sum)        | Add numbers together         | Sum values                |

> **Reference:** See MongoDB documentation for each operator: [Aggregation Operators](https://www.mongodb.com/docs/manual/reference/operator/aggregation/)

***

### Join Multiple Forms <a href="#join-multiple-forms" id="join-multiple-forms"></a>

Use this approach when you need data from multiple related forms.

{% embed url="<https://www.loom.com/share/5d62ea65f5014e159150d7802f2998d8>" %}

**Scenario:** Create a report joining Employee data with Salary data, where both forms share a Department field.

**Prerequisites:**

* Two or more forms with at least one common field
* The common field must contain matching values (e.g., same Department IDs)

**Steps:**

1. Go to **Reports** > **New Report**
2. Set **Report Title** to "Employee Salary Report"
3. Click **Source Forms** tab
4. Select **Employee** from the dropdown
5. Select **Salary** from the dropdown (you now have 2 forms selected)
6. In **Forms Connections**, click **+ Add Connection**
7. Configure the connection:
   * **Base Form:** Employee
   * **Connecting Field of Base Form:** Department
   * **Joining Form:** Salary
   * **Connecting Field of Joining Form:** Department
8. Click **Save** on the connection
9. Go to **Columns** tab—you now see fields from both forms
10. Select your desired columns
11. Click **Submit Form**

**Path to Connecting Value:**

If your field stores an object (e.g., the entire Department submission), specify the path to the ID:

* **Base Form Path:** `_id` or `data.departmentId`
* **Joining Form Path:** `_id` or `data.departmentId`

***

### Create Aggregated Reports <a href="#create-aggregated-reports" id="create-aggregated-reports"></a>

Use aggregation to group data and calculate summaries.

{% embed url="<https://www.loom.com/share/e65e36ca952747a4977a8c83707ed659>" %}

**Scenario:** Show total employees and average salary per department.

1. Create a multi-form report with Employee and Salary forms (see above)
2. Click the **Aggregation** tab
3. In **Fields to group by**, select **Department Name**
4. In **Group Calculated Columns**, click **+ Add Column**
5. Add first aggregation:
   * **Column Title:** Total Employees
   * **Column Key:** totalEmployees
   * **Operator:** Count
6. Click **+ Add Column** again
7. Add second aggregation:
   * **Column Title:** Average Salary
   * **Column Key:** avgSalary
   * **Operator:** Average
   * **Argument:** Salary Amount
   * **Decimal Places:** 2
8. Go to **Columns** tab and select: Department Name, Total Employees, Average Salary
9. Click **Submit Form**

**Available Aggregation Operators:**

| Operator | Description                 |
| -------- | --------------------------- |
| Average  | Mean value of numeric field |
| Count    | Number of records in group  |
| Max      | Highest value in group      |
| Min      | Lowest value in group       |
| Sum      | Total of numeric values     |

***

### Configure Filters <a href="#configure-filters" id="configure-filters"></a>

Allow report viewers to filter data interactively.

**Prerequisites:** Reporting Controls must be enabled.

1. Click the **Reporting Controls** tab
2. Check **Enable Control Panel**
3. Click the **Filters** tab
4. Set **Number of Filters Per Row** (e.g., 3)
5. Set **Filter Label Position** (Top, Left, or Right)
6. In **Control Panel Filters**, click **+ Add Filter**
7. Configure the filter:
   * **Field:** Select the field to filter (e.g., Department)
   * **Filter Type:** Select operator (Contains, Equals, Greater Than, etc.)
   * **Filter Title:** Label shown to users (optional)
8. Add additional filters as needed
9. Click **Submit Form**

**Filter Types by Field Type:**

| Field Type | Available Filters                                  |
| ---------- | -------------------------------------------------- |
| Text       | Contains, Equals, Starts With, Ends With, Is Empty |
| Number     | Equals, Greater Than, Less Than, Between, Is Empty |
| Date       | Equals, Before, After, Between, Is Empty           |
| Select     | Equals, Is Empty                                   |

***

### Add Export Actions <a href="#add-export-actions" id="add-export-actions"></a>

Let users export selected rows to CSV or PDF.

1. Ensure **Reporting Controls** is enabled
2. Click the **Controls Actions** tab
3. Click **+ Add Action**
4. Configure the action:
   * **Title:** Export to CSV
   * **Type:** Export CSV
   * **Columns:** Visible Columns Only (or All Available)
5. Add another action for PDF if needed:
   * **Title:** Download PDF
   * **Type:** Download PDF
6. Click **Submit Form**

**Custom Actions:**

For advanced workflows, use Custom actions with JavaScript:

```javascript
// Custom action example: Send selected rows to an API
promise = new Promise((resolve, reject) => {
  const selectedData = rows.map(row => ({
    id: row._id,
    name: row.data.fullName
  }));

  fetch('/api/process-employees', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(selectedData)
  })
  .then(response => response.json())
  .then(result => {
    alert(`Processed ${result.count} employees`);
    resolve(true); // Return true to refresh the grid
  })
  .catch(error => {
    alert('Error: ' + error.message);
    resolve(false);
  });
});
```

***

### Configure Permissions <a href="#configure-permissions" id="configure-permissions"></a>

Ensure users can access reports and underlying data.

**Project Level:**

1. Go to **Project Settings** > **Access**
2. Find your Authenticated role
3. Enable **Read All**

**Reporting UI Resource:**

1. Go to **Resources** > **Reporting UI**
2. Click the **Access** tab
3. Enable **Read All Submission** for the Authenticated role

**Source Forms:**

1. Go to each form used in your report
2. Click the **Access** tab
3. Enable **Read All Submission** for the Authenticated role

> **Important:** Users need Read All Submission on ALL source forms to see data in the report.

***

## Reference <a href="#reference" id="reference"></a>

#### Report Configuration Options <a href="#report-configuration-options" id="report-configuration-options"></a>

**Basic Settings**

| Option         | Required | Description                                                 |
| -------------- | -------- | ----------------------------------------------------------- |
| Report Title   | Yes      | Display name for the report                                 |
| Report Name    | Yes      | Unique identifier (alphanumeric, underscores, dots, dashes) |
| Items per page | No       | Records per page (default: 10)                              |
| Cache requests | No       | Store results in cache for performance                      |
| Cell max width | No       | Maximum width of grid cells in pixels                       |

**Reporting Controls Settings**

| Option               | Description                                       |
| -------------------- | ------------------------------------------------- |
| Enable Control Panel | Show/hide the controls panel                      |
| Control Panel Title  | Header text for the panel                         |
| Controls Panel Theme | Bootstrap theme (default, primary, success, etc.) |
| Initially Collapsed  | Start with panel collapsed                        |

#### Embedding Options <a href="#embedding-options" id="embedding-options"></a>

**Using Report URL:**

```javascript
Formio.Report.create(element, 'https://your-project.form.io/report/report-name');
```

**Using Report JSON:**

```javascript
const reportSchema = { /* your report JSON */ };
Formio.Report.create(element, reportSchema, {
  projectEndpoint: 'https://your-project.form.io'
});
```

#### Report Events <a href="#report-events" id="report-events"></a>

Subscribe to events for custom behavior:

```javascript
Formio.Report.create(element, reportUrl).then((report) => {

  // Row clicked
  report.on('rowClick', (rowData, rowIndex) => {
    console.log('Clicked row:', rowIndex, rowData);
  });

  // Row selection changed
  report.on('rowSelectChange', (selectedRows, gridInstance) => {
    console.log('Selected:', selectedRows.length, 'rows');
  });

  // Data fetch error
  report.on('fetchDataErrors', (error, gridInstance) => {
    console.error('Failed to fetch data:', error);
  });

  // Page changed
  report.on('page', (currentPage, gridInstance) => {
    console.log('Now on page:', currentPage);
  });

  // Items per page changed
  report.on('changeItemsPerPage', (itemsPerPage) => {
    console.log('Showing', itemsPerPage, 'items per page');
  });

});
```

| Event              | Arguments                  | Description            |
| ------------------ | -------------------------- | ---------------------- |
| rowClick           | rowData, rowIndex          | User clicked a row     |
| rowSelectChange    | selectedRows, gridInstance | Selection changed      |
| fetchDataErrors    | error, gridInstance        | Data fetch failed      |
| page               | currentPage, gridInstance  | Page navigation        |
| changeItemsPerPage | itemsPerPage               | Items per page changed |

#### Data Persistence <a href="#data-persistence" id="data-persistence"></a>

Report settings (filters, column visibility, sorting) persist in the browser's local storage.

**To reset settings programmatically:**

```javascript
// Clear all report settings
localStorage.removeItem('formio-report-settings');

// Or clear settings for a specific report
const reportKey = 'formio-report-' + reportName;
localStorage.removeItem(reportKey);
```

***

## Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

#### Reports Loading Error <a href="#reports-loading-error" id="reports-loading-error"></a>

**Symptom:** Error when accessing the Reports tab in projects created before Reporting Module activation.

**Cause:** The project lacks the Reporting UI configuration resource.

**Solution:**

1. Go to **Resources** in your project
2. Click **Import**
3. Enter this embed URL: `{{ yourServerUrl }}/reportingui/config`
4. Ensure the resource is titled **Reporting UI**
5. Ensure the resource name and path is **reportingui** (exact spelling)

***

#### Unauthorized Error <a href="#unauthorized-error" id="unauthorized-error"></a>

**Symptom:** "Unauthorized" error when viewing an embedded report.

**Cause:** User lacks required permissions.

**Solution:** Verify these permissions are configured:

1. **Project Level Access**
   * Navigate to Project Settings > Access
   * Add "Read All" for your user role
2. **Reporting UI Resource**
   * Navigate to Resources > Reporting UI > Access
   * Add "Read All Submission" for your user role
3. **Source Forms**
   * Navigate to each source form > Access tab
   * Add "Read All Submission" for your user role

***

#### Module Not Found <a href="#module-not-found" id="module-not-found"></a>

**Symptom:** `Cannot find module '@formio/reporting'`

**Cause:** Module not installed correctly.

**Solution:**

```bash
# Verify installation
npm list @formio/reporting

# Reinstall if needed
npm install --save @formio/reporting
```

***

#### Report.create is Not a Function <a href="#reportcreate-is-not-a-function" id="reportcreate-is-not-a-function"></a>

**Symptom:** `Formio.Report.create is not a function` or `Formio.Report is undefined`

**Cause:** Reporting module not registered before use.

**Solution:** Call `Formio.use(Reporting)` before creating reports:

```javascript
import { Formio } from '@formio/js';
import { Reporting } from '@formio/reporting';

// Must register BEFORE creating reports
Formio.use(Reporting);
Formio.setLicense('yourLicenseKey');

// Now create reports
Formio.Report.create(element, reportUrl);
```

***

#### Changes Not Appearing <a href="#changes-not-appearing" id="changes-not-appearing"></a>

**Symptom:** Report updates in the portal don't appear in your application.

**Cause:** Browser caching report settings in local storage.

**Solution:**

1. Clear local storage: Open browser DevTools > Application > Local Storage > Clear
2. Hard refresh: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)

Or programmatically:

```javascript
localStorage.clear();
location.reload(true);
```

***

#### Date Operators Not Available <a href="#date-operators-not-available" id="date-operators-not-available"></a>

**Symptom:** Date operators (Date Difference, Day of Month, etc.) unavailable for some date fields.

**Cause:** Different date components save data in different formats.

**Details:**

* **Date/Time component:** Saves as ISO format (works with date operators)
* **Textfield with Calendar:** Saves as string (limited operator support)

**Solution:** Use the Date/Time component for fields you want to use with date operators.

***

#### Report Displays Incorrect Order <a href="#report-displays-incorrect-order" id="report-displays-incorrect-order"></a>

**Symptom:** Data appears in unexpected order.

**Cause:** Database updates can temporarily affect sort order.

**Solution:**

1. Click a column header to re-sort
2. Refresh the page
3. If persistent, check your default sort configuration

[^1]: This Resource will be used as a connection between the Employee Form and Evaluation form.&#x20;
