# 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;


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.form.io/userguide/form.io-reporting-module.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
