UNPKG

json-object-editor

Version:

JOE the Json Object Editor | Platform Edition

300 lines (244 loc) 10.4 kB
# 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 <!DOCTYPE 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 `<!DOCTYPE html> <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 <!DOCTYPE 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