Querying, Searching, and Displaying Form Submissions
Querying, Searching, and Displaying Form Submissions
Once users start submitting forms in your portal, you'll likely need to fetch and display those submissions, whether it's for managers reviewing requests, admins auditing data, or users viewing submission history.
Kinetic's React SDK gives you full control to search for and display submissions using the searchSubmissions
function and the defineKqlQuery
builder.
Using searchSubmissions
to Retrieve Form Data
searchSubmissions
to Retrieve Form DataThe searchSubmissions
is a helper function for querying submissions. You can also make a call to our API directly following our API docs here: https://docs.kineticdata.com/v6.1/reference/listformsubmissionsaspost
What is searchSubmissions
?
searchSubmissions
?searchSubmissions
is an async function that queries the Kinetic Platform for form submission data. You can use it to:
- Retrieve all submissions in a specific Kapp
- Filter submissions by status, field value, or metadata
- Sort and paginate large result sets
- Include nested data like field values, form details, parent relationships, etc.
Parameters for searchSubmissions
searchSubmissions
Name | Type | Description |
---|---|---|
kapp | string | Required. The slug of the Kapp to search in. |
form | string | Form slug to specify submissions for a specific form. |
search | SearchMeta{} | The search metadata derived from the SubmissionSearch |
get | boolean | Indicates whether the query should get the GET method instead of the default POST method; defaults to false. |
limit | number | The number of records to return. Defaults to 25. Max 1000. |
pageToken | string | The pageToken retrieves a subsequent page of a query (the search will return a nextPageToken if there is a next page) |
What is SearchMeta
?
SearchMeta
?The search
parameter accepts a SearchMeta
object. This object defines how the query will behave, what to inclue, how to filter, and how to sort.
Property | Type | Description |
---|---|---|
q | string | A qualification to use when searching for submissions. |
include | string[] — details , activities , children , descendants , origin , parent , type , values , values.raw , values[FIELD NAME] , form , form.{any form include property} | Array of properties to include in each submission. |
orderBy | string | Comma separated list of submission properties and fields to sort the response by; all parts of the orderBy except the optionally specified timeline must be included in all indexes used by the query. |
direction | "ASC" | "DESC" | Sort direction (defaults to "DESC" ) |
Resolves
When searchSubmissions
completes, it returns a resolved object with the following structure:
-
submissions
→Submission[]
An array of submission objects that match the search criteria. Each object includes metadata and any included properties (likevalues
,details
, orform
). -
error
→ErrorResponse
(optional)
If the request fails, this field will contain error details such as the HTTP status code, message, and context. Always check for this when handling responses to gracefully manage failures.
Tip: A successful call will return
submissions
. If something goes wrong (like a 403 error or malformed query), theerror
field will be populated instead.
Basic Example: Search Submissions by Type and Status
Once you've defined your Kapp and understand the structure of a searchSubmissions
call, you can begin retrieving relevant data. In this example, we search for all submissions of a specific type with an active status—this is a common pattern used for request queues, dashboards, or task lists.
import { searchSubmissions } from '@kineticdata/react';
import { useEffect, useState } from 'react';
const ExampleComponent = () => {
const [submissions, setSubmissions] = useState([]);
useEffect(() => {
searchSubmissions({
kapp: 'services',
search: {
q: 'type = "Service" AND values[Status] IN ("Active", "Pending")',
include: ['values', 'details'],
orderBy: 'createdAt',
direction: 'DESC',
},
}).then(({ submissions }) => {
setSubmissions(submissions);
});
}, []);
return (
<ul>
{submissions.map((submission) => (
<li key={submission.id}>
{submission.values['Request Title']} — {submission.values['Status']}
</li>
))}
</ul>
);
};
Useful include
Values
include
ValuesBy default, a submission result only contains minimal data. To enrich your results with additional context, such as form fields, timestamps, or relationships, you can use the include
option in your searchSubmissions
call.
These include values tell the API which related properties to return with each submission. This is especially helpful when displaying submissions in the UI, performing audits, or building dashboards with field-specific logic.
Below are the most commonly used include
values:
Include Value | Description |
---|---|
values | Field values submitted by the user |
details | Metadata such as ID, createdBy, timestaps |
form | The form that the submission belongs to |
parent , origin | Related submissions |
type , activities | Internal tracking or workflow context |
When to Use searchSubmissions
searchSubmissions
- Displaying form results in a table or dashboard
- Filtering and reviewing requests
- Pulling submission data for reports or exports
- Powering manager or admin views
Build Powerful Filters with defineKqlQuery
defineKqlQuery
To build complex filters for use with searchSubmissions
, you'll often need to construct a KQL qualification string. Manually writing these strings is error-prone and difficult to manage. That’s where defineKqlQuery
comes in.
What is defineKqlQuery
?
defineKqlQuery
?defineKqlQuery
is a utility that helps you build query strings using a readable, chainable syntax. It returns a compiled query function that you can call with real values to generate a KQL string.
This makes it easy to dynamically build queries based on user input, roles, or business logic.
Example
const query = defineKqlQuery()
.equals('type', 'type')
.in('coreState', 'coreState')
.or()
.equals('values[Requested For]', 'username')
.equals('values[Requested By]', 'username')
.end()
.startsWith('values[Status]', 'status')
.end();
const result = query({
type: 'Service',
coreState: ['Draft', 'Submitted'],
username: 'allan.allbrook',
status: 'A',
});
Result
type = "Service"
AND coreState IN ("Draft", "Submitted")
AND (
values[Requested For] = "allan.allbrook"
OR values[Requested By] = "allan.allbrook"
)
AND values[Status] =* "A"
Why Use It?
- Avoid manual string formatting
- Build flexible and reusable filters
- Support dynamic conditions with multiple values or optional fields
- Combine
AND
/OR
logic safely
Supported Methods
The methods below are used to define your query structure. Each method accepts a field name (e.g., values[Status]
) and a key string, which corresponds to a property in the argument object passed to the compiled query function.
When the compiled function is executed, it replaces each key with its actual value. If a key is missing or its value is empty, that part of the query is automatically omitted unless you explicitly pass { strict: true }
to force inclusion of null or empty values.
This gives you flexible control over dynamic search logic without having to write conditionals manually.
Method | Description |
---|---|
and() -> SearchBuilder{} | Begins an and context. |
or() -> SearchBuilder{} | Begins an or context. |
end() -> SearchBuilder{} | Closes the last and or or context, or compiles the query and returns the query function. |
equals(field, value, strict) -> SearchBuilder{} | Adds an equality check. |
in(field, values, strict) -> SearchBuilder{} | Adds an in statement (accepts an array of values). |
startsWith(field, value) -> SearchBuilder{} | Adds a starts with check. |
between(field, minValue, maxValue, strict) -> SearchBuilder{} | Adds a between check. |
greaterThan(field, value, strict) -> SearchBuilder{} | Adds a greater than check. |
greaterThanOrEquals(field, value, strict) -> SearchBuilder{} | Adds a greater than or equals check. |
lessThan(field, value, strict) -> SearchBuilder{} | Adds a less than check. |
lessThanOrEquals(field, value, strict) -> SearchBuilder{} | Adds a less than or equals check. |
Best Practices
- Always call
.end()
after.or()
or.and()
blocks - Reuse query builders for different inputs
- Match key names used in the query with the object passed to the compiled function
- Combine with
searchSubmissions
for highly targeted filtering
Displaying Submissions in Your Portal
Once you've queried for submissions using searchSubmissions
, the next step is rendering those results in a user-friendly way. Whether you're building an admin dashboard, a request history view, or a manager approval queue, displaying submissions in your portal involves iterating over the returned data and formatting it for your use case.
Step 1: Run a Submission Query
Start by calling searchSubmissions
with the appropriate filters and includes:
import { searchSubmissions } from '@kineticdata/react';
import { useEffect, useState } from 'react';
const SubmissionList = () => {
const [submissions, setSubmissions] = useState([]);
useEffect(() => {
searchSubmissions({
kapp: 'services',
search: {
q: 'values[Status] = "Open"',
include: ['values', 'details'],
orderBy: 'createdAt',
direction: 'DESC',
},
}).then(({ submissions }) => setSubmissions(submissions));
}, []);
return (
<div>
<h2>Open Requests</h2>
{submissions.length === 0 ? (
<p>No submissions found.</p>
) : (
<ul>
{submissions.map((sub) => (
<li key={sub.id}>
<strong>{sub.values['Request Title']}</strong> — submitted by{' '}
{sub.values['Requested By']} on{' '}
{new Date(sub.createdAt).toLocaleDateString()}
</li>
))}
</ul>
)}
</div>
);
};
Step 2: Choose the Right Layout for Your Use Case
Depending on your audience and goals, you may want to display submissions in different layouts:
- Table format for detailed data views or reports
- Cards or tiles for a visual dashboard
- Timelines or activity feeds for request progress
Here’s a basic table-style layout:
<table>
<thead>
<tr>
<th>Title</th>
<th>Status</th>
<th>Requested By</th>
<th>Submitted On</th>
</tr>
</thead>
<tbody>
{submissions.map((s) => (
<tr key={s.id}>
<td>{s.values['Request Title']}</td>
<td>{s.values['Status']}</td>
<td>{s.values['Requested By']}</td>
<td>{new Date(s.createdAt).toLocaleDateString()}</td>
</tr>
))}
</tbody>
</table>
Step 3: Add Interactivity
To create a richer, more useful UI, consider enhancing your submission display with:
- Clickable rows to view or edit a submission
- Status badges for quick visual interpretation
- Pagination or infinite scroll for large result sets
- Filter controls to support user-driven queries
Tips
- Use
include: ['values', 'details']
in your query to access field values and metadata - Always check for
submissions.length === 0
to gracefully handle empty results - Use
submission.form.name
orsubmission.form.slug
when displaying results from multiple forms
Updated about 1 month ago