json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
300 lines (244 loc) • 10.4 kB
Markdown
# React Form Integration - Usage Example
## Overview
This document shows how to set up a JOE page with a React-powered form using JSON form definitions.
## Setup Steps
### 1. Create JSON Form Definition Include
1. In JOE, go to **Includes** schema
2. Create a new include:
- **Name**: "Harmonious Wellness Form Definition"
- **Filetype**: `json`
- **Content**: Paste your `form-qs.json` content
- **Fill Template**: `false` (or `true` if you want to use `${this.}` variables)
3. Save and note the `_id` of the include
### 2. Create JOE Form Record
1. Go to **Forms** schema
2. Create a new form:
- **Name**: "Harmonious Wellness Health Questionnaire"
- **Save Submission**: `true`
- **Meta** (optional): Add `json_definition_include: "{include_id}"` if you want to link it
3. Save and note the `_id` of the form
### 3. Create React Form JS Include (if not already created)
1. Go to **Includes** schema
2. Create a new include:
- **Name**: "JOE React Form Renderer"
- **Filetype**: `js`
- **Content**: Copy content from `js/joe-react-form.js`
3. Save and note the `_id` of the include
### 4. Create JOE Page
1. Go to **Pages** schema
2. Create a new page:
- **Name**: "Health Questionnaire"
- **Site**: Select your site
- **Path**: `/health-questionnaire` (or your desired path)
- **Content Type**: `code` (or `module` for dynamic generation - see examples below)
- **Form**: Select the form you created in step 2
- **Includes**:
- Add the React Form JS include from step 3
- Add the JSON Form Definition include from step 1 (optional - formDefinition plugin can find it automatically)
- **Content**: Use the template below
- **Layout**: Select a layout (or create one with minimal structure)
**Note:** When using `${INCLUDES}` in your page content, JOE will automatically generate `<script>` and `<link>` tags for all JS and CSS includes you add here. The JSON include is accessed via the formDefinition API endpoint, not as a direct include.
### 5. Page Content Template
**Option A: Using Code Content Type with Template Variables (Recommended)**
Set `content_type: 'code'` and use JOE template variables:
```html
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${this.PAGE.name}</title>
<!-- Tailwind CSS (for styling) - Optional -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- React from CDN - MUST load before ${INCLUDES} (which contains joe-react-form.js) -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<!-- JOE automatically includes all JS/CSS from page.includes here -->
<!-- Note: joe-react-form.js will wait for React if needed, but loading React first is recommended -->
${INCLUDES}
</head>
<body>
<div id="react-form-root"></div>
<script>
// Wait for joeReactForm to be available (script may still be loading)
function initForm() {
if (typeof joeReactForm !== 'undefined') {
joeReactForm.init({
rootId: 'react-form-root',
formDefinitionUrl: '/API/plugin/formBuilder/definition?formid=${this.PAGE.form}&pageid=${this.PAGE._id}',
formId: '${this.PAGE.form}'
});
} else {
// If not ready, wait for DOMContentLoaded or check again shortly
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initForm);
} else {
setTimeout(initForm, 50);
}
}
}
initForm();
</script>
</body>
</html>
```
**Benefits:**
- `${INCLUDES}` automatically includes all JS/CSS from page's includes array
- `${this.PAGE.form}` and `${this.PAGE._id}` automatically use linked form and page IDs
- No hardcoded IDs to maintain!
**Option B: Using Module Content Type**
Set `content_type: 'module'` - see the "Alternative: Using Module Content Type" section below.
### Alternative: Using Module Content Type (Recommended)
You can use `content_type: 'module'` to generate HTML dynamically using JOE's template patterns:
```javascript
module.exports = function(content) {
var page = content.PAGE;
var form = page.form ? JOE.Cache.findByID('form', page.form) : null;
if (!form) {
return '<div>Error: No form linked to this page</div>';
}
// Use formDefinition plugin to auto-find JSON include from page
// This will find the JSON include from page.includes automatically
var formDefUrl = '/API/plugin/formBuilder/definition?formid=' + form._id + '&pageid=' + page._id;
return `
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${page.name}</title>
<script src="https://cdn.tailwindcss.com"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
${content.INCLUDES}
</head>
<body>
<div id="react-form-root"></div>
<script>
// Wait for joeReactForm to be available (script may still be loading)
function initForm() {
if (typeof joeReactForm !== 'undefined') {
joeReactForm.init({
rootId: 'react-form-root',
formDefinitionUrl: '${formDefUrl}',
formId: '${form._id}'
});
} else {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initForm);
} else {
setTimeout(initForm, 50);
}
}
}
initForm();
</script>
</body>
</html>`;
};
```
**Key improvements:**
- Uses `${content.INCLUDES}` - automatically includes all JS/CSS from page's includes array
- Uses `formBuilder.definition` endpoint with `pageid` - automatically finds JSON include from page
- No need to manually specify include IDs
### Alternative: Using Code Content Type with Template Variables
You can also use `content_type: 'code'` with JOE template variables:
```html
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${this.PAGE.name}</title>
<script src="https://cdn.tailwindcss.com"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
${INCLUDES}
</head>
<body>
<div id="react-form-root"></div>
<script>
// Wait for joeReactForm to be available (script may still be loading)
function initForm() {
if (typeof joeReactForm !== 'undefined') {
joeReactForm.init({
rootId: 'react-form-root',
formDefinitionUrl: '/API/plugin/formBuilder/definition?formid=${this.PAGE.form}&pageid=${this.PAGE._id}',
formId: '${this.PAGE.form}'
});
} else {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initForm);
} else {
setTimeout(initForm, 50);
}
}
}
initForm();
</script>
</body>
</html>
```
This automatically:
- Uses `${INCLUDES}` to inject all page includes (JS/CSS)
- Uses `${this.PAGE.form}` and `${this.PAGE._id}` to pass form and page IDs
- No hardcoded IDs needed!
## API Endpoints
### Get Form Definition
```
GET /API/plugin/formBuilder/definition?include_id={include_id}
GET /API/plugin/formBuilder/definition?formid={form_id}&field=json_definition_include
```
Returns: JSON form definition (form-qs.json format)
### Submit Form
```
POST /API/plugin/formBuilder/submission
Content-Type: application/json
{
"formid": "{form_id}",
"submission": {
"first_name": "John",
"last_name": "Doe",
...
}
}
```
Returns: Submission confirmation or error
## How It Works
1. **Page loads** → Includes React CDN and form renderer JS
2. **Form renderer initializes** → Fetches JSON form definition from include
3. **React renders form** → Based on JSON structure (sections, fields, visibility rules)
4. **User fills form** → React manages state and conditional visibility
5. **User submits** → Data sent to `/API/plugin/formBuilder/submission`
6. **JOE saves submission** → Creates `submission` record linked to form
## Customization
### Styling
The form uses Tailwind CSS classes. You can:
- Include Tailwind CDN (as shown above)
- Add custom CSS via include
- Modify classes in `joe-react-form.js`
### Form Definition Template Variables
If you enable `fillTemplate` on the JSON include, you can use variables like:
```json
{
"formName": "${this.SITE.name} - Health Questionnaire",
"version": "${this.WEBCONFIG.version}"
}
```
### Form Callbacks
The JOE form record supports:
- **Callback**: Client-side function called after submission
- **Server Action**: Server-side function called during submission
- **Validate**: Client-side validation function
These can be added to the form record and will be executed as configured.
## Troubleshooting
### Form not loading
- Check browser console for errors
- Verify all include IDs are correct
- Ensure React CDN is loading (check Network tab)
### Submission errors
- Verify form ID is correct
- Check that form has `save_submission: true`
- Check server logs for submission errors
### Styling issues
- Ensure Tailwind CSS is loaded (or adjust classes)
- Check that Tailwind CDN version supports all classes used