TYPO3 v15 dev-main snapshot ()
@@ -0,0 +1,171 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _apireference-events:
|
||||
.. _apireference-formeditor-events:
|
||||
.. _apireference-formeditor-hooks-beforeformcreate:
|
||||
.. _apireference-formeditor-hooks-beforeformcreate-connect:
|
||||
.. _apireference-formeditor-hooks-beforeformcreate-use:
|
||||
.. _apireference-formeditor-events-beforeformiscreatedevent:
|
||||
.. _apireference-formeditor-hooks-beforeformduplicate:
|
||||
.. _apireference-formeditor-hooks-beforeformduplicate-connect:
|
||||
.. _apireference-formeditor-hooks-beforeformduplicate-use:
|
||||
.. _apireference-formeditor-hooks-beforeformdelete:
|
||||
.. _apireference-formeditor-hooks-beforeformdelete-connect:
|
||||
.. _apireference-formeditor-hooks-beforeformdelete-use:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-initializeformelement:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-initializeformelement-connect:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-initializeformelement-use:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-beforeremovefromparentrenderable:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-beforeremovefromparentrenderable-connect:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-beforeremovefromparentrenderable-use:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-afterbuildingfinished:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-afterbuildingfinished-connect:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-afterbuildingfinished-use:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-afterinitializecurrentpage:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-afterinitializecurrentpage-connect:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-afterinitializecurrentpage-use:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-aftersubmit:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-aftersubmit-connect:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-aftersubmit-use:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-beforerendering:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-beforerendering-connect:
|
||||
.. _apireference-frontendrendering-runtimemanipulation-hooks-beforerendering-use:
|
||||
.. _apireference-events-legacy-hooks-buildformvalidationconfiguration:
|
||||
.. _apireference-events-legacy-hooks-afterformstateinitialized:
|
||||
.. _apireference-events-legacy-hooks:
|
||||
|
||||
================
|
||||
PSR-14 Events
|
||||
================
|
||||
|
||||
EXT:form dispatches PSR-14 events at key points in the lifecycle of a form –
|
||||
both in the backend form editor and during frontend rendering. These events
|
||||
are the recommended extension point for developers; the legacy
|
||||
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']` hooks have been removed.
|
||||
|
||||
.. seealso::
|
||||
The canonical, always-up-to-date reference for all EXT:form events lives
|
||||
in the TYPO3 Core API documentation:
|
||||
|
||||
`Form <https://docs.typo3.org/permalink/t3coreapi:eventlist-form>`_
|
||||
|
||||
The extension documentation below provides context, usage notes and
|
||||
quick navigation; it intentionally avoids duplicating the full API
|
||||
reference.
|
||||
|
||||
.. contents::
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
.. _apireference-events-backend:
|
||||
|
||||
Backend events (form editor / manager)
|
||||
=======================================
|
||||
|
||||
These events are dispatched when an editor creates, saves, duplicates or
|
||||
deletes a form definition in the TYPO3 backend.
|
||||
|
||||
.. _apireference-events-backend-table:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 40 60
|
||||
|
||||
* - Event
|
||||
- When / what can be modified
|
||||
* - `BeforeFormIsCreatedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforeformiscreatedevent>`_
|
||||
- Modify the form definition array and/or the persistence identifier
|
||||
before a new form is created in the backend.
|
||||
* - `BeforeFormIsSavedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforeformissavedevent>`_
|
||||
- Modify the form definition array and/or the persistence identifier
|
||||
before a form is saved in the backend.
|
||||
* - `BeforeFormIsDuplicatedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforeformisduplicatedevent>`_
|
||||
- Modify the form definition array and/or the persistence identifier
|
||||
of the copy before a form is duplicated.
|
||||
* - `BeforeFormIsDeletedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforeformisdeletedevent>`_
|
||||
- Dispatched before a form is deleted. Set
|
||||
:php:`$event->preventDeletion = true` to abort the deletion (the
|
||||
event implements :php:`StoppableEventInterface`).
|
||||
|
||||
.. _apireference-events-frontend:
|
||||
|
||||
Frontend events (form rendering / runtime)
|
||||
==========================================
|
||||
|
||||
These events are dispatched during form rendering in the frontend.
|
||||
|
||||
.. _apireference-events-frontend-table:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 40 60
|
||||
|
||||
* - Event
|
||||
- When / what can be modified
|
||||
* - `AfterFormIsBuiltEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:afterformisbuiltevent>`_
|
||||
- Modify the :php:`FormDefinition` object after the form factory has
|
||||
finished building the complete form.
|
||||
* - `BeforeRenderableIsAddedToFormEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforerenderableisaddedtoformevent>`_
|
||||
- Modify or replace a renderable (page, section or element) before it
|
||||
is added to the form tree.
|
||||
* - `BeforeRenderableIsRemovedFromFormEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforerenderableisremovedfromformevent>`_
|
||||
- Dispatched before a renderable is removed from the form tree. Set
|
||||
:php:`$event->preventRemoval = true` to abort the removal (the
|
||||
event implements :php:`StoppableEventInterface`).
|
||||
* - `AfterCurrentPageIsResolvedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:aftercurrentpageisresolvedevent>`_
|
||||
- Override :php:`$event->currentPage` after the current page has been
|
||||
resolved from the request, e.g. to implement conditional page-skip
|
||||
logic.
|
||||
* - `BeforeRenderableIsValidatedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforerenderableisvalidatedevent>`_
|
||||
- Modify :php:`$event->value` before property-mapping and validation
|
||||
run for each submitted form element.
|
||||
* - `BeforeRenderableIsRenderedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforerenderableisrenderedevent>`_
|
||||
- Modify the renderable or the :php:`FormRuntime` just before a
|
||||
renderable is output to the browser.
|
||||
* - `BeforeEmailFinisherInitializedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:beforeemailfinisherinitializedevent>`_
|
||||
- Modify the options used by the :php:`EmailFinisher` (e.g. recipients,
|
||||
subject) before they are applied.
|
||||
* - `AfterFormStateInitializedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:afterformstateinitializedevent>`_
|
||||
- Enrich components with runtime data after the :php:`FormState` has
|
||||
been restored from the request (form state and form session are
|
||||
both available at this point).
|
||||
* - `AfterFormDefinitionLoadedEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:afterformdefinitionloadedevent>`_
|
||||
- Dispatched by :php:`FormPersistenceManager` after a YAML form
|
||||
definition has been loaded from disk. Modify the definition globally
|
||||
before it reaches the form factory.
|
||||
* - `AfterFormDefinitionValidationConfigurationIsBuiltEvent
|
||||
<https://docs.typo3.org/permalink/t3coreapi:afterformdefinitionvalidationconfigurationisbuiltevent>`_
|
||||
- Dispatched after the form definition validation configuration has
|
||||
been built from the form editor setup. Add additional writable
|
||||
property paths for custom inspector editor implementations.
|
||||
|
||||
.. _apireference-events-register:
|
||||
|
||||
Registering an event listener
|
||||
==============================
|
||||
|
||||
Register a listener via the :php:`#[AsEventListener]` PHP attribute:
|
||||
|
||||
.. literalinclude:: _codesnippets/_MyFormEventListener.php
|
||||
:language: php
|
||||
:caption: EXT:my_extension/Classes/EventListener/MyFormEventListener.php
|
||||
|
||||
|
||||
.. seealso::
|
||||
:ref:`t3coreapi:EventDispatcher` – TYPO3 Core API documentation on how to
|
||||
register and implement PSR-14 event listeners.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyVendor\MyExtension\EventListener;
|
||||
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\Form\Event\BeforeFormIsSavedEvent;
|
||||
|
||||
#[AsEventListener(
|
||||
identifier: 'my-extension/before-form-is-saved',
|
||||
)]
|
||||
final readonly class MyFormEventListener
|
||||
{
|
||||
public function __invoke(BeforeFormIsSavedEvent $event): void
|
||||
{
|
||||
// Enrich the form definition before it is persisted
|
||||
$event->form['renderingOptions']['myCustomOption'] = 'value';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel:
|
||||
.. _apireference-formeditor-formelementmodel:
|
||||
|
||||
==================
|
||||
FormElement model
|
||||
==================
|
||||
|
||||
Every form element in the editor is represented by a **FormElement model**
|
||||
object. This model is the single source of truth for all element properties
|
||||
during an editing session; it is separate from the YAML form definition on
|
||||
disk (which is only written on save).
|
||||
|
||||
.. contents::
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-property-identifierpath:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-property-parentrenderable:
|
||||
.. _apireference-formeditor-formelementmodel-structure:
|
||||
|
||||
Model structure
|
||||
===============
|
||||
|
||||
A FormElement model carries all YAML properties of the element plus two
|
||||
internal bookkeeping properties:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 30 70
|
||||
|
||||
* - Property
|
||||
- Description
|
||||
* - :js:`__identifierPath`
|
||||
- Slash-separated path from the root element to this element
|
||||
(e.g. :js:`'example-form/page-1/name'`). Used as a unique key
|
||||
for API lookups.
|
||||
* - :js:`__parentRenderable`
|
||||
- Reference to the parent FormElement model (filtered for display).
|
||||
|
||||
Example model in memory:
|
||||
|
||||
.. literalinclude:: _codesnippets/_model-structure.js
|
||||
:language: javascript
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-get:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-get-propertycollectionproperties:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-get-renderables:
|
||||
.. _apireference-formeditor-formelementmodel-api-get:
|
||||
|
||||
get()
|
||||
-----
|
||||
|
||||
Reads a property by its dot-separated path. All intermediate levels must
|
||||
be objects.
|
||||
|
||||
.. literalinclude:: _codesnippets/_get-simple.js
|
||||
:language: javascript
|
||||
|
||||
For **property collections** (validators / finishers), whose position in
|
||||
the array is unknown, use :js:`buildPropertyPath()` first:
|
||||
|
||||
.. literalinclude:: _codesnippets/_get-property-collection.js
|
||||
:language: javascript
|
||||
|
||||
For **renderables** (child elements), :js:`get('renderables')` returns a
|
||||
plain array of FormElement models. To access a specific child, use
|
||||
:js:`formEditorApp.getFormElementByIdentifierPath()` with the full path.
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-set:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-set-propertycollectionproperties:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-set-renderables:
|
||||
.. _apireference-formeditor-formelementmodel-api-set:
|
||||
|
||||
set()
|
||||
-----
|
||||
|
||||
Writes a property by its dot-separated path. Every :js:`set()` call
|
||||
automatically publishes all events registered for that path via
|
||||
:ref:`on() <apireference-formeditor-formelementmodel-api-on>`, including
|
||||
the built-in
|
||||
:ref:`core/formElement/somePropertyChanged <apireference-formeditor-jsevents-core-formelement-somepropertychanged>`.
|
||||
|
||||
.. literalinclude:: _codesnippets/_set.js
|
||||
:language: javascript
|
||||
|
||||
To modify property collection properties or add child renderables, use
|
||||
the dedicated API methods on :js:`formEditorApp` / :js:`getViewModel()`
|
||||
instead of setting array positions directly:
|
||||
|
||||
- :js:`createAndAddFormElement()`
|
||||
- :js:`addFormElement()`
|
||||
- :js:`moveFormElement()`
|
||||
- :js:`removeFormElement()`
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-unset:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-unset-propertycollectionproperties:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-unset-renderables:
|
||||
.. _apireference-formeditor-formelementmodel-api-unset:
|
||||
|
||||
unset()
|
||||
-------
|
||||
|
||||
Removes a property at the given dot-separated path.
|
||||
|
||||
.. literalinclude:: _codesnippets/_unset.js
|
||||
:language: javascript
|
||||
|
||||
For property collection properties, use :js:`buildPropertyPath()` in the
|
||||
same way as for :ref:`get() <apireference-formeditor-formelementmodel-api-get>`.
|
||||
|
||||
To remove a child renderable, call
|
||||
:js:`formEditorApp.removeFormElement()`.
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-on:
|
||||
.. _apireference-formeditor-formelementmodel-api-on:
|
||||
|
||||
on()
|
||||
----
|
||||
|
||||
Registers an additional publish/subscribe event name that is fired
|
||||
whenever :js:`set()` is called for a given property path.
|
||||
|
||||
.. literalinclude:: _codesnippets/_on.js
|
||||
:language: javascript
|
||||
|
||||
By default EXT:form registers
|
||||
:ref:`core/formElement/somePropertyChanged <apireference-formeditor-jsevents-core-formelement-somepropertychanged>`
|
||||
for every known property path of every form element.
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-off:
|
||||
.. _apireference-formeditor-formelementmodel-api-off:
|
||||
|
||||
off()
|
||||
-----
|
||||
|
||||
Removes an event registration created with :js:`on()`.
|
||||
|
||||
.. literalinclude:: _codesnippets/_off.js
|
||||
:language: javascript
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-getobjectdata:
|
||||
.. _apireference-formeditor-formelementmodel-api-getobjectdata:
|
||||
|
||||
getObjectData()
|
||||
---------------
|
||||
|
||||
Returns a deep-cloned plain object of all properties. Used internally for
|
||||
Ajax serialisation. Provides read access to data set via :js:`set()` from
|
||||
outside the model without breaking encapsulation.
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-clone:
|
||||
.. _apireference-formeditor-formelementmodel-api-clone:
|
||||
|
||||
clone()
|
||||
-------
|
||||
|
||||
Returns a fully dereferenced clone of the FormElement model.
|
||||
|
||||
.. literalinclude:: _codesnippets/_clone.js
|
||||
:language: javascript
|
||||
|
||||
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-formelementmodel-method-tostring:
|
||||
.. _apireference-formeditor-formelementmodel-api-tostring:
|
||||
|
||||
toString()
|
||||
----------
|
||||
|
||||
Returns the model data as a JSON string. Intended for debugging.
|
||||
|
||||
.. literalinclude:: _codesnippets/_to-string.js
|
||||
:language: javascript
|
||||
@@ -0,0 +1,5 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
const formElement = formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name');
|
||||
const copy = formElement.clone();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
const formElement = formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name');
|
||||
|
||||
const propertyPath = formEditorApp
|
||||
.buildPropertyPath('options.minimum', 'StringLength', 'validators', formElement);
|
||||
// propertyPath = e.g. 'validators.0.options.minimum'
|
||||
|
||||
const value = formElement.get(propertyPath); // '1'
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
// Returns 'Name'
|
||||
const placeholder = formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name')
|
||||
.get('properties.fluidAdditionalAttributes.placeholder');
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Illustrative snapshot of a FormElement model as it exists in memory at runtime.
|
||||
// The actual object is managed by the FormElement class – access it via
|
||||
// formEditorApp.getFormElementByIdentifierPath() and the get()/set() API.
|
||||
export const formElementSnapshot = {
|
||||
identifier: 'name',
|
||||
defaultValue: '',
|
||||
label: 'Name',
|
||||
type: 'Text',
|
||||
properties: {
|
||||
fluidAdditionalAttributes: {
|
||||
placeholder: 'Name',
|
||||
},
|
||||
},
|
||||
__parentRenderable: 'example-form/page-1 (filtered)',
|
||||
__identifierPath: 'example-form/page-1/name',
|
||||
validators: [
|
||||
{ identifier: 'NotEmpty' },
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name')
|
||||
.off('properties.fluidAdditionalAttributes.placeholder', 'my/custom/event');
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
const element = formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name');
|
||||
|
||||
element.on('properties.fluidAdditionalAttributes.placeholder', 'my/custom/event');
|
||||
|
||||
// The next set() on that path will also publish 'my/custom/event'.
|
||||
element.set('properties.fluidAdditionalAttributes.placeholder', 'New Placeholder');
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name')
|
||||
.set('properties.fluidAdditionalAttributes.placeholder', 'New Placeholder');
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
const formElement = formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name');
|
||||
console.log(formElement.toString());
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp
|
||||
.getFormElementByIdentifierPath('example-form/page-1/name')
|
||||
.unset('properties.fluidAdditionalAttributes.placeholder');
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
|
||||
.. _apireference-formeditor:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts:
|
||||
.. _apireference-formeditor-basicjavascriptconcepts-events:
|
||||
.. _apireference-formeditor-stage:
|
||||
|
||||
===========
|
||||
Form Editor
|
||||
===========
|
||||
|
||||
This chapter is the developer reference for the TYPO3 backend form editor.
|
||||
It covers the JavaScript extension points and the data model used by the
|
||||
editor's TypeScript modules.
|
||||
|
||||
.. contents::
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
.. _apireference-formeditor-architecture:
|
||||
|
||||
Architecture overview
|
||||
=====================
|
||||
|
||||
The form editor consists of four cooperating TypeScript modules, each
|
||||
responsible for one UI component:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 30 35 35
|
||||
|
||||
* - Module (import path)
|
||||
- Component
|
||||
- Responsibility
|
||||
* - :js:`@typo3/form/backend/form-editor/view-model`
|
||||
- —
|
||||
- Central view model; wires DOM events and publishes/subscribes
|
||||
to all cross-component events.
|
||||
* - :js:`@typo3/form/backend/form-editor/stage-component`
|
||||
- **Stage**
|
||||
- Renders the abstract and preview views of the current form page.
|
||||
* - :js:`@typo3/form/backend/form-editor/inspector-component`
|
||||
- **Inspector**
|
||||
- Renders the property editors for the selected form element.
|
||||
* - :js:`@typo3/form/backend/form-editor/tree-component-adapter`
|
||||
- **Structure tree**
|
||||
- Wraps the TYPO3 backend tree web component and bridges its
|
||||
events to the publish/subscribe bus.
|
||||
* - :js:`@typo3/form/backend/form-editor/mediator`
|
||||
- —
|
||||
- Wires all publish/subscribe events to view-model actions.
|
||||
Loaded automatically; replace via
|
||||
:yaml:`dynamicJavaScriptModules.mediator` only when you need to
|
||||
completely swap the event-wiring logic.
|
||||
|
||||
All modules communicate exclusively via a **publish/subscribe bus**
|
||||
(:js:`PublisherSubscriber`). Direct module-to-module calls are avoided
|
||||
so that extension code can hook into any point without modifying core
|
||||
files.
|
||||
|
||||
.. _apireference-formeditor-custom-modules:
|
||||
|
||||
Registering a custom JavaScript module
|
||||
=======================================
|
||||
|
||||
Custom modules must export a :js:`bootstrap` function. The form editor
|
||||
calls this function once all built-in modules have loaded, passing the
|
||||
central :js:`FormEditor` application object as the sole argument.
|
||||
|
||||
.. rst-class:: bignums-xxl
|
||||
|
||||
1. Create the JavaScript module
|
||||
|
||||
.. literalinclude:: _codesnippets/_bootstrap.js
|
||||
:language: javascript
|
||||
:caption: EXT:my_extension/Resources/Public/JavaScript/backend/form-editor/view-model.js
|
||||
|
||||
2. Register the module in the importmap
|
||||
|
||||
.. literalinclude:: _codesnippets/_JavaScriptModules.php
|
||||
:language: php
|
||||
:caption: EXT:my_extension/Configuration/JavaScriptModules.php
|
||||
|
||||
3. Tell the form editor to load the module
|
||||
|
||||
.. literalinclude:: _codesnippets/_prototype-setup.yaml
|
||||
:language: yaml
|
||||
:caption: EXT:my_extension/Configuration/Form/MyFormSet/config.yaml
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
JavaScriptEvents/Index
|
||||
StageTemplates/Index
|
||||
FormElementModel/Index
|
||||
@@ -0,0 +1,22 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp.getPublisherSubscriber().subscribe(
|
||||
'view/inspector/editor/insert/perform',
|
||||
(topic, args) => {
|
||||
const [editorConfiguration, editorHtml] = args;
|
||||
|
||||
if (editorConfiguration.templateName !== 'Inspector-MyCustomEditor') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wire up your custom editor UI inside editorHtml
|
||||
const input = editorHtml.querySelector('.my-custom-input');
|
||||
if (input) {
|
||||
input.addEventListener('change', (e) => {
|
||||
formEditorApp
|
||||
.getCurrentlySelectedFormElement()
|
||||
.set(editorConfiguration.propertyPath, e.target.value);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formEditor:
|
||||
dynamicJavaScriptModules:
|
||||
additionalViewModelModules:
|
||||
10: '@vendor/my-extension/backend/form-editor/view-model.js'
|
||||
formEditorPartials:
|
||||
Inspector-MyCustomEditor: 'Inspector/MyCustomEditor'
|
||||
formEditorFluidConfiguration:
|
||||
partialRootPaths:
|
||||
100: 'EXT:my_extension/Resources/Private/Backend/Partials/FormEditor/'
|
||||
formElementsDefinition:
|
||||
Text:
|
||||
formEditor:
|
||||
editors:
|
||||
600:
|
||||
templateName: 'Inspector-MyCustomEditor'
|
||||
myOption: 'example'
|
||||
@@ -0,0 +1,3 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp.getPublisherSubscriber().publish('my/custom/event', ['arg1', 'arg2']);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp.getPublisherSubscriber().subscribe(
|
||||
'core/formElement/somePropertyChanged',
|
||||
(topic, args) => {
|
||||
const [propertyPath, newValue, oldValue, identifierPath] = args;
|
||||
if (propertyPath === 'label' && identifierPath?.startsWith('my-form/page-1/')) {
|
||||
console.log('Label changed from', oldValue, 'to', newValue);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="formeditor-element-body">
|
||||
<div data-identifier="elementLabel"></div>
|
||||
<div data-identifier="elementSummary"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp.getPublisherSubscriber().subscribe(
|
||||
'view/stage/abstract/render/template/perform',
|
||||
(topic, args) => {
|
||||
const [formElement, template] = args;
|
||||
|
||||
if (formElement.get('type') !== 'MyCustomElement') {
|
||||
return;
|
||||
}
|
||||
|
||||
const labelEl = template.querySelector('[data-identifier="elementLabel"]');
|
||||
if (labelEl) {
|
||||
labelEl.textContent =
|
||||
formElement.get('label') || formElement.get('identifier');
|
||||
}
|
||||
|
||||
const summaryEl = template.querySelector('[data-identifier="elementSummary"]');
|
||||
if (summaryEl) {
|
||||
summaryEl.textContent =
|
||||
formElement.get('properties.myCustomProperty') ?? '';
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formEditor:
|
||||
dynamicJavaScriptModules:
|
||||
additionalViewModelModules:
|
||||
10: '@vendor/my-extension/backend/form-editor/view-model.js'
|
||||
formEditorPartials:
|
||||
FormElement-MyCustomElement: 'Stage/MyCustomElement'
|
||||
formEditorFluidConfiguration:
|
||||
partialRootPaths:
|
||||
100: 'EXT:my_extension/Resources/Private/Backend/Partials/FormEditor/'
|
||||
@@ -0,0 +1,11 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
const ps = formEditorApp.getPublisherSubscriber();
|
||||
|
||||
// Subscribe – returns a token for later unsubscription
|
||||
const token = ps.subscribe('view/ready', (topic, args) => {
|
||||
// args is a typed tuple matching the event signature
|
||||
});
|
||||
|
||||
// Unsubscribe
|
||||
ps.unsubscribe(token);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export function bootstrap(formEditorApp) {
|
||||
formEditorApp.getPublisherSubscriber().subscribe('view/ready', () => {
|
||||
// Safe to call any formEditorApp API here.
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _apireference-formeditor-stage-commonabstractformelementtemplates:
|
||||
.. _apireference-formeditor-stagetemplates:
|
||||
|
||||
===============
|
||||
Stage templates
|
||||
===============
|
||||
|
||||
The **Stage** component renders each form element as an HTML item in the
|
||||
abstract view. This section explains the two rendering strategies: the
|
||||
modern web-component approach (recommended) and the legacy Fluid-partial
|
||||
approach (deprecated).
|
||||
|
||||
.. contents::
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
|
||||
.. _apireference-formeditor-stagetemplates-webcomponent:
|
||||
|
||||
Built-in web component (recommended)
|
||||
=====================================
|
||||
|
||||
When no :yaml:`formEditorPartials` entry exists for a form element type,
|
||||
the Stage component automatically renders it using the built-in
|
||||
:html:`<typo3-form-form-element-stage-item>` web component. The component
|
||||
displays the element's label, type icon, validators, select options and
|
||||
allowed MIME types without requiring any custom JavaScript.
|
||||
|
||||
.. tip::
|
||||
For most custom form elements this is the recommended approach. Simply
|
||||
omit :yaml:`formEditorPartials` from the prototype configuration and the
|
||||
editor handles the rest.
|
||||
|
||||
Properties set on the web component from the :js:`FormElement` model:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 30 70
|
||||
|
||||
* - Property
|
||||
- Source in FormElement model
|
||||
* - :js:`elementType`
|
||||
- Form element definition :yaml:`label`
|
||||
* - :js:`elementLabel`
|
||||
- :yaml:`label` (falls back to :yaml:`identifier`)
|
||||
* - :js:`elementIconIdentifier`
|
||||
- Form element definition :yaml:`iconIdentifier`
|
||||
* - :js:`validators`
|
||||
- :yaml:`validators` array (excludes ``NotEmpty``, shown via :js:`isRequired`)
|
||||
* - :js:`isRequired`
|
||||
- ``true`` when a ``NotEmpty`` validator is present
|
||||
* - :js:`options`
|
||||
- :yaml:`properties.options` (for select-like elements)
|
||||
* - :js:`allowedMimeTypes`
|
||||
- :yaml:`properties.allowedMimeTypes`
|
||||
* - :js:`content`
|
||||
- :yaml:`properties.text` or :yaml:`properties.contentElementUid`
|
||||
* - :js:`isHidden`
|
||||
- ``true`` when :yaml:`renderingOptions.enabled` is ``false``
|
||||
|
||||
|
||||
.. _apireference-formeditor-stagetemplates-fluid:
|
||||
|
||||
Custom Fluid partial (advanced)
|
||||
================================
|
||||
|
||||
If you need fully custom stage rendering – for example to display a
|
||||
proprietary summary of complex properties – you can still provide a Fluid
|
||||
partial and subscribe to the
|
||||
:ref:`view/stage/abstract/render/template/perform <apireference-formeditor-jsevents-view-stage-abstract-render-template-perform>`
|
||||
event to populate it with DOM manipulation.
|
||||
|
||||
The core Fluid partials are located in
|
||||
:file:`EXT:form/Resources/Private/Backend/Partials/FormEditor/Stage/`.
|
||||
|
||||
.. warning::
|
||||
The legacy stage rendering helpers
|
||||
:js:`renderSimpleTemplateWithValidators()` and
|
||||
:js:`renderSelectTemplates()` from
|
||||
:js:`@typo3/form/backend/form-editor/stage-component` are deprecated
|
||||
since TYPO3 v14.2 and will be removed in TYPO3 v15. Migrate to the
|
||||
web component approach (omit :yaml:`formEditorPartials`) or implement
|
||||
custom DOM manipulation in the event subscriber.
|
||||
|
||||
.. _apireference-formeditor-stage-commonabstractformelementtemplates-simpletemplate:
|
||||
.. _apireference-formeditor-stagetemplates-fluid-simpletemplate:
|
||||
|
||||
Stage/SimpleTemplate (deprecated)
|
||||
----------------------------------
|
||||
|
||||
Displays the element :yaml:`label`. When the element has validators, a
|
||||
validator icon and their labels appear on hover/selection. Rendered via
|
||||
the deprecated :js:`renderSimpleTemplateWithValidators()`.
|
||||
|
||||
.. deprecated:: 14.2
|
||||
Use the :html:`<typo3-form-form-element-stage-item>` web component
|
||||
by omitting :yaml:`formEditorPartials`, or implement custom DOM
|
||||
manipulation in the
|
||||
:ref:`view/stage/abstract/render/template/perform <apireference-formeditor-jsevents-view-stage-abstract-render-template-perform>`
|
||||
subscriber. See Deprecation :issue:`109306`.
|
||||
|
||||
.. _apireference-formeditor-stage-commonabstractformelementtemplates-selecttemplate:
|
||||
.. _apireference-formeditor-stagetemplates-fluid-selecttemplate:
|
||||
|
||||
Stage/SelectTemplate (deprecated)
|
||||
----------------------------------
|
||||
|
||||
Extends ``Stage/SimpleTemplate`` by additionally listing the chosen option
|
||||
labels from :yaml:`properties.options.*`. Rendered via the deprecated
|
||||
:js:`renderSelectTemplates()`.
|
||||
|
||||
Example form element using select options:
|
||||
|
||||
.. literalinclude:: _codesnippets/_select-template.yaml
|
||||
:language: yaml
|
||||
|
||||
The template partial contains a container with the path to read:
|
||||
|
||||
.. literalinclude:: _codesnippets/_select-template-partial.html
|
||||
:language: html
|
||||
|
||||
For elements using a different array property (e.g. ``FileUpload`` with
|
||||
:yaml:`properties.allowedMimeTypes`), adjust the :html:`data-template-property`
|
||||
attribute accordingly:
|
||||
|
||||
.. literalinclude:: _codesnippets/_file-upload-partial.html
|
||||
:language: html
|
||||
|
||||
The web component handles both cases automatically.
|
||||
|
||||
.. deprecated:: 14.2
|
||||
Use the :html:`<typo3-form-form-element-stage-item>` web component
|
||||
by omitting :yaml:`formEditorPartials`.
|
||||
See `Deprecation: #109306 - Deprecate form editor stage template rendering functions <https://docs.typo3.org/permalink/changelog:deprecation-109306-1774010043>`_.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<div data-identifier="multiValueContainer"
|
||||
data-template-property="properties.allowedMimeTypes"></div>
|
||||
@@ -0,0 +1,2 @@
|
||||
<div data-identifier="multiValueContainer"
|
||||
data-template-property="properties.options"></div>
|
||||
@@ -0,0 +1,7 @@
|
||||
type: MultiCheckbox
|
||||
identifier: multicheckbox-1
|
||||
label: 'Multi checkbox'
|
||||
properties:
|
||||
options:
|
||||
value1: label1
|
||||
value2: label2
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'dependencies' => ['form'],
|
||||
'imports' => [
|
||||
'@vendor/my-extension/'
|
||||
=> 'EXT:my_extension/Resources/Public/JavaScript/',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Custom form editor module for EXT:my_extension.
|
||||
*/
|
||||
export function bootstrap(formEditorApp) {
|
||||
const ps = formEditorApp.getPublisherSubscriber();
|
||||
|
||||
ps.subscribe('view/ready', () => {
|
||||
// Editor is fully initialised – set up your custom logic here.
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formEditor:
|
||||
dynamicJavaScriptModules:
|
||||
additionalViewModelModules:
|
||||
10: '@vendor/my-extension/backend/form-editor/view-model.js'
|
||||
@@ -0,0 +1,320 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
|
||||
.. _apireference-frontendrendering:
|
||||
|
||||
============================
|
||||
Building and rendering forms
|
||||
============================
|
||||
|
||||
This chapter explains how EXT:form renders forms in the frontend and how
|
||||
developers can build forms programmatically or customize the rendering
|
||||
pipeline.
|
||||
|
||||
For the complete PHP API of every class mentioned here, see
|
||||
`EXT:form API on api.typo3.org <https://api.typo3.org/main/namespaces/typo3-cms-form.html>`__.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-fluidformrenderer:
|
||||
|
||||
Template resolution (FluidFormRenderer)
|
||||
========================================
|
||||
|
||||
The :php-short:`\TYPO3\CMS\Form\Domain\Renderer\FluidFormRenderer` resolves
|
||||
Fluid templates, layouts and partials through rendering options defined in the
|
||||
prototype configuration. All options are read from
|
||||
:php-short:`\TYPO3\CMS\Form\Domain\Model\FormDefinition::getRenderingOptions()`.
|
||||
|
||||
.. _apireference-frontendrendering-fluidformrenderer-options:
|
||||
|
||||
.. _apireference-frontendrendering-fluidformrenderer-options-templaterootpaths:
|
||||
|
||||
templateRootPaths
|
||||
-----------------
|
||||
|
||||
Defines one or more paths to Fluid **templates**.
|
||||
Paths are searched in reverse order (bottom to top); the first match wins.
|
||||
|
||||
Only the root form element (type :yaml:`Form`) must be a **template** file.
|
||||
All child elements are resolved as **partials**.
|
||||
|
||||
.. literalinclude:: _templateRootPaths.yaml
|
||||
:caption: EXT:my_sitepackage/Configuration/Form/CustomPrototype.yaml
|
||||
:language: yaml
|
||||
|
||||
With the default type :yaml:`Form` the renderer expects a file named
|
||||
:file:`Form.html` inside the first matching path.
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-fluidformrenderer-options-layoutrootpaths:
|
||||
|
||||
layoutRootPaths
|
||||
---------------
|
||||
|
||||
Defines one or more paths to Fluid **layouts**, searched in reverse order.
|
||||
|
||||
.. literalinclude:: _layoutRootPaths.yaml
|
||||
:caption: EXT:my_sitepackage/Configuration/Form/CustomPrototype.yaml
|
||||
:language: yaml
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-fluidformrenderer-options-partialrootpaths:
|
||||
|
||||
partialRootPaths
|
||||
----------------
|
||||
|
||||
Defines one or more paths to Fluid **partials**, searched in reverse order.
|
||||
|
||||
Within these paths the renderer looks for a file named after the
|
||||
form element type (e.g. :file:`Text.html` for a :yaml:`Text` element).
|
||||
Use :ref:`templateName <apireference-frontendrendering-fluidformrenderer-options-templatename>`
|
||||
to override this convention.
|
||||
|
||||
.. literalinclude:: _partialRootPaths.yaml
|
||||
:caption: EXT:my_sitepackage/Configuration/Form/CustomPrototype.yaml
|
||||
:language: yaml
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-fluidformrenderer-options-templatename:
|
||||
|
||||
templateName
|
||||
------------
|
||||
|
||||
By default the element type is used as the partial file name
|
||||
(e.g. type :yaml:`Text` → :file:`Text.html`).
|
||||
Set :yaml:`templateName` to use a different file instead:
|
||||
|
||||
.. literalinclude:: _templateName.yaml
|
||||
:caption: EXT:my_sitepackage/Configuration/Form/CustomPrototype.yaml
|
||||
:language: yaml
|
||||
|
||||
The element of type :yaml:`Foo` now renders using :file:`Text.html`.
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-renderviewHelper:
|
||||
|
||||
The render ViewHelper
|
||||
=====================
|
||||
|
||||
.. _apireference-frontendrendering-renderviewHelper-arguments:
|
||||
|
||||
Use :html:`<formvh:render>` in a Fluid template to render a form.
|
||||
The ViewHelper accepts the following arguments:
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-renderviewHelper-persistenceidentifier:
|
||||
|
||||
persistenceIdentifier
|
||||
---------------------
|
||||
|
||||
Path to a YAML form definition. This is the most common way to render a
|
||||
form:
|
||||
|
||||
.. literalinclude:: _renderPersistenceIdentifier.html
|
||||
:caption: EXT:my_sitepackage/Resources/Private/Templates/ContactPage.html
|
||||
:language: html
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-renderviewHelper-overrideconfiguration:
|
||||
|
||||
overrideConfiguration
|
||||
---------------------
|
||||
|
||||
A configuration array that is merged **on top** of the loaded form
|
||||
definition (or passed directly to the factory when no
|
||||
:yaml:`persistenceIdentifier` is given).
|
||||
This allows adjusting a form per usage without duplicating the YAML file.
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-renderviewHelper-factoryclass:
|
||||
|
||||
factoryClass
|
||||
------------
|
||||
|
||||
A fully qualified class name implementing
|
||||
:php-short:`\TYPO3\CMS\Form\Domain\Factory\FormFactoryInterface`.
|
||||
Defaults to :php-short:`\TYPO3\CMS\Form\Domain\Factory\ArrayFormFactory`.
|
||||
Set a custom factory to :ref:`build forms programmatically <apireference-frontendrendering-programmatically>`.
|
||||
|
||||
.. literalinclude:: _renderFactoryClass.html
|
||||
:caption: EXT:my_sitepackage/Resources/Private/Templates/ContactPage.html
|
||||
:language: html
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-renderviewHelper-prototypename:
|
||||
|
||||
prototypeName
|
||||
-------------
|
||||
|
||||
Name of the prototype the factory should use (e.g. :yaml:`standard`).
|
||||
If omitted the framework looks for the prototype name inside the form
|
||||
definition; if none is found, :yaml:`standard` is used.
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-programmatically:
|
||||
|
||||
Building forms programmatically
|
||||
===============================
|
||||
|
||||
Instead of writing YAML, you can create a form entirely in PHP by
|
||||
implementing a custom :php:`FormFactory`.
|
||||
|
||||
.. rst-class:: bignums-xxl
|
||||
|
||||
1. Create a FormFactory
|
||||
|
||||
Extend :php:`AbstractFormFactory` and implement :php:`build()`.
|
||||
Use :php:`FormDefinition::createPage()` to add pages,
|
||||
:php:`Page::createElement()` to add elements, and
|
||||
:php:`FormDefinition::createFinisher()` to attach finishers.
|
||||
|
||||
.. literalinclude:: _CustomFormFactory.php
|
||||
:caption: EXT:my_sitepackage/Classes/Domain/Factory/CustomFormFactory.php
|
||||
:language: php
|
||||
|
||||
2. Render the form
|
||||
|
||||
Reference your factory in a Fluid template:
|
||||
|
||||
.. literalinclude:: _renderFactoryClass.html
|
||||
:caption: EXT:my_sitepackage/Resources/Private/Templates/ContactPage.html
|
||||
:language: html
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-programmatically-key-concepts:
|
||||
|
||||
Key classes and their responsibilities
|
||||
--------------------------------------
|
||||
|
||||
.. _apireference-frontendrendering-programmatically-apimethods-formruntime:
|
||||
|
||||
The following table lists the most important classes you work with when
|
||||
building or manipulating forms programmatically. Use your IDE's
|
||||
autocompletion or the
|
||||
`API documentation <https://api.typo3.org/main/namespaces/typo3-cms-form.html>`__
|
||||
for the full method reference.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 30 70
|
||||
|
||||
* - Class
|
||||
- Purpose
|
||||
|
||||
* - :php-short:`\TYPO3\CMS\Form\Domain\Model\FormDefinition`
|
||||
- The complete form model. Create pages (:php:`createPage()`),
|
||||
attach finishers (:php:`createFinisher()`), look up elements
|
||||
(:php:`getElementByIdentifier()`), and bind to a request
|
||||
(:php:`bind()`).
|
||||
|
||||
* - :php-short:`\TYPO3\CMS\Form\Domain\Runtime\FormRuntime`
|
||||
- A *bound* form instance (created by :php:`FormDefinition::bind()`).
|
||||
Provides access to the current page, submitted values
|
||||
(:php:`getElementValue()`), and the request/response objects.
|
||||
This is the object available inside finishers and event listeners.
|
||||
|
||||
* - :php-short:`\TYPO3\CMS\Form\Domain\Model\FormElements\Page`
|
||||
- One page of a multi-step form. Add elements with
|
||||
:php:`createElement()`, reorder them with :php:`moveElementBefore()`
|
||||
/ :php:`moveElementAfter()`.
|
||||
|
||||
* - :php-short:`\TYPO3\CMS\Form\Domain\Model\FormElements\Section`
|
||||
- A grouping element inside a page. Same API as :php:`Page` for
|
||||
managing child elements.
|
||||
|
||||
* - :php-short:`\TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement`
|
||||
- Base class of all concrete elements. Most element types use
|
||||
:php-short:`\TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement`;
|
||||
specialized subclasses include, e.g.
|
||||
:php-short:`\TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload`.
|
||||
Set properties (:php:`setProperty()`), add validators
|
||||
(:php:`createValidator()`), define default values
|
||||
(:php:`setDefaultValue()`).
|
||||
|
||||
* - :php-short:`\TYPO3\CMS\Form\Domain\Configuration\ConfigurationService`
|
||||
- Reads the merged prototype configuration.
|
||||
Call :php:`getPrototypeConfiguration('standard')` to obtain the
|
||||
full array for a prototype.
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-programmatically-initializeformelement:
|
||||
|
||||
Initializing elements at runtime
|
||||
---------------------------------
|
||||
|
||||
Override :php:`initializeFormElement()` in a custom form element class to
|
||||
populate data (e.g. from a database) when the element is added to the form.
|
||||
At that point the prototype defaults have already been applied; properties
|
||||
from the YAML definition are applied **afterwards**.
|
||||
|
||||
.. tip::
|
||||
If you only need to initialize an element without writing a full custom
|
||||
class, listen to the :php:`BeforeRenderableIsAddedToFormEvent` PSR-14
|
||||
event instead. See :ref:`apireference-events`.
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-finishers:
|
||||
|
||||
Working with finishers
|
||||
======================
|
||||
|
||||
Custom finishers extend :php-short:`\TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher`
|
||||
and place their logic in :php:`executeInternal()`. The base class provides:
|
||||
|
||||
:php:`parseOption(string $optionName)`
|
||||
Resolves a finisher option, applying form-element variable replacements
|
||||
and TypoScript-style option overrides. Always prefer this over direct
|
||||
array access.
|
||||
|
||||
The :php-short:`\TYPO3\CMS\Form\Domain\Finishers\FinisherContext` passed to
|
||||
:php:`execute()` gives access to:
|
||||
|
||||
:php:`getFormRuntime()`
|
||||
The :php-short:`\TYPO3\CMS\Form\Domain\Runtime\FormRuntime` for the current
|
||||
submission.
|
||||
|
||||
:php:`getFormValues()`
|
||||
All submitted values (after validation and property mapping).
|
||||
|
||||
:php:`getFinisherVariableProvider()`
|
||||
A key/value store to **share data between finishers** within the same
|
||||
request. The returned
|
||||
:php-short:`\TYPO3\CMS\Form\Domain\Finishers\FinisherVariableProvider` offers:
|
||||
|
||||
:php:`add(string $finisherIdentifier, string $key, mixed $value)`
|
||||
Store a value under a finisher-specific namespace.
|
||||
|
||||
:php:`get(string $finisherIdentifier, string $key, mixed $default = null)`
|
||||
Retrieve a previously stored value (returns :php:`$default` if not set).
|
||||
|
||||
:php:`exists(string $finisherIdentifier, string $key)`
|
||||
Check whether a value has been stored.
|
||||
|
||||
:php:`remove(string $finisherIdentifier, string $key)`
|
||||
Remove a stored value.
|
||||
|
||||
:php:`cancel()`
|
||||
Stops execution of any remaining finishers.
|
||||
|
||||
.. seealso::
|
||||
:ref:`Accessing finisher options <concepts-finishers-customfinisherimplementations-accessingoptions>` |
|
||||
:ref:`Sharing data between finishers <concepts-finishers-customfinisherimplementations-finishercontext-sharedatabetweenfinishers>`
|
||||
|
||||
|
||||
.. _apireference-frontendrendering-runtimemanipulation:
|
||||
|
||||
Runtime manipulation
|
||||
====================
|
||||
|
||||
.. _apireference-frontendrendering-runtimemanipulation-events:
|
||||
|
||||
EXT:form dispatches PSR-14 events at every important step of the rendering
|
||||
lifecycle. Use them to modify the form, redirect page flow, or adjust
|
||||
submitted values – without subclassing framework internals.
|
||||
|
||||
.. seealso::
|
||||
:ref:`PSR-14 events overview for EXT:form <apireference-events>`
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Vendor\MySitePackage\Domain\Factory;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
|
||||
use TYPO3\CMS\Form\Domain\Factory\AbstractFormFactory;
|
||||
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
|
||||
use TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement;
|
||||
|
||||
final class CustomFormFactory extends AbstractFormFactory
|
||||
{
|
||||
public function build(
|
||||
array $configuration,
|
||||
?string $prototypeName = null,
|
||||
?ServerRequestInterface $request = null,
|
||||
): FormDefinition {
|
||||
$prototypeName ??= 'standard';
|
||||
$configurationService = GeneralUtility::makeInstance(
|
||||
ConfigurationService::class,
|
||||
);
|
||||
$prototypeConfiguration = $configurationService->getPrototypeConfiguration(
|
||||
$prototypeName,
|
||||
);
|
||||
|
||||
$form = GeneralUtility::makeInstance(
|
||||
FormDefinition::class,
|
||||
'ContactForm',
|
||||
$prototypeConfiguration,
|
||||
);
|
||||
$form->setRenderingOption('controllerAction', 'index');
|
||||
|
||||
// Page 1 – personal data
|
||||
$page1 = $form->createPage('page1');
|
||||
|
||||
/** @var AbstractFormElement $name */
|
||||
$name = $page1->createElement('name', 'Text');
|
||||
$name->setLabel('Name');
|
||||
$name->createValidator('NotEmpty');
|
||||
|
||||
/** @var AbstractFormElement $email */
|
||||
$email = $page1->createElement('email', 'Text');
|
||||
$email->setLabel('Email');
|
||||
|
||||
// Page 2 – message
|
||||
$page2 = $form->createPage('page2');
|
||||
|
||||
/** @var AbstractFormElement $message */
|
||||
$message = $page2->createElement('message', 'Textarea');
|
||||
$message->setLabel('Message');
|
||||
$message->createValidator('StringLength', ['minimum' => 5, 'maximum' => 500]);
|
||||
|
||||
// Radio buttons
|
||||
/** @var AbstractFormElement $subject */
|
||||
$subject = $page2->createElement('subject', 'RadioButton');
|
||||
$subject->setProperty('options', [
|
||||
'general' => 'General inquiry',
|
||||
'support' => 'Support request',
|
||||
]);
|
||||
$subject->setLabel('Subject');
|
||||
|
||||
// Finisher – send email
|
||||
$form->createFinisher('EmailToSender', [
|
||||
'subject' => 'Contact form submission',
|
||||
'recipients' => [
|
||||
'info@example.com' => 'My Company',
|
||||
],
|
||||
'senderAddress' => 'noreply@example.com',
|
||||
]);
|
||||
|
||||
$this->triggerFormBuildingFinished($form);
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formElementsDefinition:
|
||||
Form:
|
||||
renderingOptions:
|
||||
layoutRootPaths:
|
||||
10: 'EXT:form/Resources/Private/Frontend/Layouts/'
|
||||
20: 'EXT:my_sitepackage/Resources/Private/Forms/Frontend/Layouts/'
|
||||
@@ -0,0 +1,8 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formElementsDefinition:
|
||||
Form:
|
||||
renderingOptions:
|
||||
partialRootPaths:
|
||||
10: 'EXT:form/Resources/Private/Frontend/Partials/'
|
||||
20: 'EXT:my_sitepackage/Resources/Private/Forms/Frontend/Partials/'
|
||||
@@ -0,0 +1,3 @@
|
||||
<formvh:render
|
||||
factoryClass="Vendor\MySitePackage\Domain\Factory\CustomFormFactory"
|
||||
/>
|
||||
@@ -0,0 +1,3 @@
|
||||
<formvh:render
|
||||
persistenceIdentifier="EXT:my_sitepackage/Resources/Private/Forms/Contact.yaml"
|
||||
/>
|
||||
@@ -0,0 +1,6 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formElementsDefinition:
|
||||
Foo:
|
||||
renderingOptions:
|
||||
templateName: 'Text'
|
||||
@@ -0,0 +1,8 @@
|
||||
prototypes:
|
||||
standard:
|
||||
formElementsDefinition:
|
||||
Form:
|
||||
renderingOptions:
|
||||
templateRootPaths:
|
||||
10: 'EXT:form/Resources/Private/Frontend/Templates/'
|
||||
20: 'EXT:my_sitepackage/Resources/Private/Forms/Frontend/Templates/'
|
||||
@@ -0,0 +1,20 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
.. _apireference:
|
||||
|
||||
==============================
|
||||
For Developers / API Reference
|
||||
==============================
|
||||
|
||||
This chapter is a complete reference of the API of the form framework. It
|
||||
mainly addresses your concerns as a developer.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Events/Index
|
||||
FormEditor/Index
|
||||
FrontendRendering/Index
|
||||
|
||||
.. seealso::
|
||||
All built-in finishers including their options and programmatic usage
|
||||
is now described in: `Ready-to-use finishers <https://docs.typo3.org/permalink/typo3/cms-form:apireference-finisheroptions>`_.
|
||||
@@ -0,0 +1,46 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _accessibility:
|
||||
|
||||
=============
|
||||
Accessibility
|
||||
=============
|
||||
|
||||
There are numerous accessibility rules when it comes to making a form accessible
|
||||
to a large number of users. This includes accessibility to groups such as people
|
||||
with a disability, the elderly, non-native speakers, etc.
|
||||
|
||||
The following should be kept in mind by editors creating forms
|
||||
in the backend form editor:
|
||||
|
||||
Labels
|
||||
======
|
||||
|
||||
Always use clear, descriptive labels in the :guilabel:`Label` field. Simply
|
||||
putting the label in field :guilabel:`Placeholder` is not
|
||||
considered accessible.
|
||||
|
||||
Descriptions
|
||||
============
|
||||
|
||||
Add an extended description in the field :guilabel:`Description`.
|
||||
|
||||
Placeholder
|
||||
===========
|
||||
|
||||
The :guilabel:`Placeholder` field should not contain the label.
|
||||
It should contain example content to make filling out the field easier for
|
||||
users.
|
||||
|
||||
Autocomplete
|
||||
============
|
||||
|
||||
The autocomplete property should be used whenever a field contains personal
|
||||
information. This property can then be used by assistive
|
||||
technology to aid users to fill out forms. Select the desired purpose from the
|
||||
select :guilabel:`Autocomplete`. See `Input Purposes for User Interface
|
||||
Components at w3.org <https://www.w3.org/TR/WCAG21/#input-purposes>`__ for
|
||||
an explanation of which purposes to use.
|
||||
|
||||
If additional input purposes are needed, your integrator or developer can
|
||||
:ref:`add additional input purpose options <concepts-autocomplete-add-options>`.
|
||||
|
After Width: | Height: | Size: 68 KiB |
@@ -0,0 +1,36 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _finishers:
|
||||
.. _finishers-introduction:
|
||||
.. _finishers-overview-of-finishers:
|
||||
|
||||
=========
|
||||
Finishers
|
||||
=========
|
||||
|
||||
Any number of "finishers" can be added to a form. Finishers are actions that will
|
||||
be executed once the form has been submitted by a user.
|
||||
|
||||
In the following chapter, each finisher and its function will be explained. Not all
|
||||
finishers can be added via the form editor. There are some
|
||||
finishers that can only be added by integrators/ administrators. The following
|
||||
finishers are available by default:
|
||||
|
||||
* :ref:`Email to sender (form submitter) <finishers-email-to-sender>`
|
||||
* :ref:`Email to receiver (you) <finishers-email-to-receiver>`
|
||||
* :ref:`Redirect to a page <finishers-redirect>`
|
||||
* :ref:`Delete uploads <finishers-delete-uploads>`
|
||||
* :ref:`Confirmation message <finishers-confirmation-message>`
|
||||
|
||||
.. figure:: Images/form_finishers_overview.png
|
||||
:alt: Form editor - add new finishers.
|
||||
|
||||
Form editor - add new finishers
|
||||
|
||||
.. important::
|
||||
|
||||
Finishers are executed in the order that they appear in your form definition.
|
||||
This is particularly important for the ``Redirect finisher``. Make sure
|
||||
this finisher is the very last one to be executed. The ``Redirect finisher``
|
||||
stops the execution of all subsequent finishers in order to perform the redirect.
|
||||
Finishers defined after the ``Redirect finisher`` will be ignored.
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 766 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 946 B |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 1014 B |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 765 B |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 902 B |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 567 B |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 959 B |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 520 B |
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,651 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
|
||||
.. _form-elements:
|
||||
|
||||
==================================
|
||||
Form elements and their properties
|
||||
==================================
|
||||
|
||||
|
||||
.. _form-elements-overview-of-form-elements:
|
||||
|
||||
Overview of form elements
|
||||
-------------------------
|
||||
|
||||
.. figure:: Images/form_elements_all.png
|
||||
:alt: Overview of all form elements included in the TYPO3 core. There may
|
||||
be fewer or different elements in your installation.
|
||||
|
||||
Overview of all form elements included in TYPO3. There may be
|
||||
fewer or different elements in your installation.
|
||||
|
||||
|
||||
.. _form-elements-settings:
|
||||
|
||||
Form element settings
|
||||
---------------------
|
||||
|
||||
Most form elements have these 7 basic settings:
|
||||
|
||||
- **Label**: Label of the element.
|
||||
- **Description**: Description of the element. Can be used to
|
||||
provide the user with more information about the expected input.
|
||||
- **Placeholder**: Example of the expected content. Disappears with the user's
|
||||
input.
|
||||
- **Default value**: Preset value. Pre-entered by the system and does not
|
||||
disappear with the user's input.
|
||||
- **Mandatory field**: Specify whether the field is a mandatory field and thus
|
||||
must be filled in by the user.
|
||||
- **Custom error message**: Custom message that will be displayed to the user
|
||||
if the field is not filled in. If you don't provide a message, a default
|
||||
message is shown.
|
||||
- **Validators**: Validators are used to check the data entered in the
|
||||
field. The system displays error messages if there are errors.
|
||||
|
||||
.. warning::
|
||||
|
||||
If a form element is a required field or validators fail, error
|
||||
messages are displayed by the browser. These error texts and formatting cannot be
|
||||
changed by editors or integrators as they are controlled
|
||||
by the browser/operating system.
|
||||
|
||||
|
||||
.. _form-elements-basic-elements:
|
||||
|
||||
Basic form elements
|
||||
-------------------
|
||||
|
||||
|
||||
.. _form-elements-basic-elements-text:
|
||||
|
||||
Text
|
||||
====
|
||||
|
||||
A single-line text field, e.g. for entering short information such as name,
|
||||
address, location. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`.
|
||||
|
||||
.. figure:: Images/form_elements_text_1.png
|
||||
:alt: Element 'Text' - preview in the frontend.
|
||||
|
||||
Element 'Text' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_text_2.png
|
||||
:alt: Settings for the 'Text' element.
|
||||
|
||||
Settings for the 'Text' element.
|
||||
|
||||
|
||||
.. _form-elements-basic-elements-textarea:
|
||||
|
||||
Textarea
|
||||
========
|
||||
|
||||
A multi-line text field, e.g. for the free input of continuous text. This allows
|
||||
the user to provide a short text such as a message. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`.
|
||||
|
||||
.. figure:: Images/form_elements_textarea_1.png
|
||||
:alt: Element 'Textarea' - preview in the frontend.
|
||||
|
||||
Element 'Textarea' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_textarea_2.png
|
||||
:alt: Settings for the 'Textarea' element.
|
||||
|
||||
Settings for the 'Textarea' element.
|
||||
|
||||
|
||||
.. _form-elements-basic-elements-password:
|
||||
|
||||
Password
|
||||
========
|
||||
|
||||
A single-line text field for entering a password. The browser "hides" the text
|
||||
input, i.e. the entered characters are not visible. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`.
|
||||
|
||||
.. figure:: Images/form_elements_password_1.png
|
||||
:alt: Element 'Password' - preview in the frontend.
|
||||
|
||||
Element 'Password' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_password_2.png
|
||||
:alt: Settings for the 'Password' element.
|
||||
|
||||
Settings for the 'Password' element.
|
||||
|
||||
|
||||
.. _form-elements-special-elements:
|
||||
|
||||
Special elements
|
||||
================
|
||||
|
||||
Sometimes it is better to use special elements instead of simple text
|
||||
elements. Mobile devices such as smartphones display on-screen keyboards. If you
|
||||
use the "Email address" element the form field on the device will contain a
|
||||
"@" character in a central position and a validator will be triggered
|
||||
that checks for the input format "firstname.lastname@example.org".
|
||||
|
||||
|
||||
.. _form-elements-special-elements-email:
|
||||
|
||||
Email address
|
||||
==============
|
||||
|
||||
A single-line field for entering an email address. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. In addition, the field has an
|
||||
`Email` validator (this is the only validator available for this form element).
|
||||
|
||||
.. figure:: Images/form_elements_email_1.png
|
||||
:alt: Element 'E-mail' - preview in the frontend.
|
||||
|
||||
Element 'E-mail' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_email_2.png
|
||||
:alt: Settings for the 'E-mail' element.
|
||||
|
||||
Settings for the 'E-mail' element.
|
||||
|
||||
|
||||
.. _form-elements-special-elements-telephone-number:
|
||||
|
||||
Telephone number
|
||||
================
|
||||
|
||||
A single-line text field for entering a phone number. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`.
|
||||
|
||||
.. figure:: Images/form_elements_telephone_1.png
|
||||
:alt: Element 'Telephone' - preview in the frontend.
|
||||
|
||||
Element 'Telephone' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_telephone_2.png
|
||||
:alt: Settings for the 'Telephone' element.
|
||||
|
||||
Settings for the 'Telephone' element.
|
||||
|
||||
|
||||
.. _form-elements-special-elements-url:
|
||||
|
||||
URL
|
||||
===
|
||||
|
||||
A single-line text field for entering a URL. A URL is typically an internet
|
||||
address, such as that of your website. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`
|
||||
|
||||
.. figure:: Images/form_elements_url_1.png
|
||||
:alt: Element 'URL' - preview in the frontend.
|
||||
|
||||
Element 'URL' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_url_2.png
|
||||
:alt: Settings for the 'URL' element.
|
||||
|
||||
Settings for the 'URL' element.
|
||||
|
||||
|
||||
.. _form-elements-special-elements-number:
|
||||
|
||||
Number
|
||||
======
|
||||
|
||||
A single-line text field for entering a number. A user can increase and decrease
|
||||
the number in preconfigured steps using visual controls in the browser.
|
||||
This element has the :ref:`basic settings <form-elements-settings>`.
|
||||
By default, the field has a `Number` validator. Additional settings:
|
||||
|
||||
- **Step**: Here you can enter a number that defines the step size. The step size
|
||||
is the amount by which a number is increased or decreased in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_number_1.png
|
||||
:alt: Element 'Number' - preview in the frontend.
|
||||
|
||||
Element 'Number' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_number_2.png
|
||||
:alt: Settings for the 'Number' element.
|
||||
|
||||
Settings for the 'Number' element.
|
||||
|
||||
|
||||
.. _form-elements-special-elements-date:
|
||||
|
||||
Date
|
||||
====
|
||||
|
||||
A single-line text field for entering a date.
|
||||
`Most modern browsers <https://caniuse.com/input-datetime>`_ will also display a calendar from
|
||||
which the user can select the date. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **Frequency**: default value "1" means that the user can select every day.
|
||||
|
||||
.. figure:: Images/form_elements_date_1.png
|
||||
:alt: Element 'Date' - preview in the frontend.
|
||||
|
||||
Element 'Date' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_date_2.png
|
||||
:alt: Settings for the 'Date' element.
|
||||
|
||||
Settings for the 'Date' element.
|
||||
|
||||
|
||||
.. _form-elements-select-elements:
|
||||
|
||||
Select elements
|
||||
---------------
|
||||
|
||||
Select elements (including checkboxes, radio buttons and selectboxes) do not
|
||||
allow a user to enter text. Instead, they offer a predefined
|
||||
number of choices, for example, salutation options.
|
||||
|
||||
.. note::
|
||||
|
||||
Select elements behave differently to text fields if they are marked as
|
||||
"required".Checkboxes with multiple choices, for example, cannot be
|
||||
be required fields. This is not supported by the HTML standard.
|
||||
|
||||
|
||||
.. _form-elements-select-elements-checkbox:
|
||||
|
||||
Checkbox
|
||||
========
|
||||
|
||||
A simple checkbox. This element has the :ref:`basic settings <form-elements-settings>`.
|
||||
|
||||
.. figure:: Images/form_elements_checkbox_1.png
|
||||
:alt: Element 'Checkbox' - preview in the frontend.
|
||||
|
||||
Element 'Checkbox' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_checkbox_2.png
|
||||
:alt: Settings for the 'Checkbox' element.
|
||||
|
||||
Settings for the 'Checkbox' element.
|
||||
|
||||
|
||||
.. _form-elements-select-elements-single-select:
|
||||
|
||||
Single selectbox
|
||||
================
|
||||
|
||||
An element to create a drop-down list. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **First option**: Define the "empty option", i.e. the first element of the
|
||||
selectbox. You can use this to provide additional guidance for the user.
|
||||
- **Choices**: A tool to insert and manage options.
|
||||
- **Label**: Name of the option.
|
||||
- **Value**: Value of the option. The system automatically sets the
|
||||
"Value" to the "Label". You can leave it like this if you are
|
||||
unsure of what you are doing.
|
||||
- **Selected**: Check this to pre-select an option in the frontend.
|
||||
- **[ + ]**: Adds a new line for a new option.
|
||||
|
||||
.. figure:: Images/form_elements_singleSelect_1.png
|
||||
:alt: Element 'Single select' - preview in the frontend.
|
||||
|
||||
Element 'Single select' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_singleSelect_2.png
|
||||
:alt: Settings for the 'Single select' element.
|
||||
|
||||
Settings for the 'Single select' element.
|
||||
|
||||
|
||||
.. _form-elements-select-elements-radiobutton:
|
||||
|
||||
Radio buttons
|
||||
=============
|
||||
|
||||
An element to display one or more radio buttons. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **Choices**: A tool to insert and manage the options.
|
||||
- **Label**: Name of the option.
|
||||
- **Value**: Value of the option. The system automatically sets the
|
||||
"Value" to the "Label". You can leave it like this if you are
|
||||
unsure of what you are doing.
|
||||
- **Selected**: Check this to pre-select an option in the frontend.
|
||||
- **[ + ]**: Adds a new line for a new option.
|
||||
|
||||
.. figure:: Images/form_elements_radioBtn_1.png
|
||||
:alt: Element 'Radio button' - preview in the frontend.
|
||||
|
||||
Element 'Radio button' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_radioBtn_2.png
|
||||
:alt: Settings for the 'Radio button' element.
|
||||
|
||||
Settings for the 'Radio button' element.
|
||||
|
||||
|
||||
.. _form-elements-select-elements-multi-checkbox:
|
||||
|
||||
Multi checkbox
|
||||
==============
|
||||
|
||||
An element to create one or more checkboxes. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **Choices**: A tool to insert and manage the options.
|
||||
- **Label**: Name of the option.
|
||||
- **Value**: Value of the option. The system automatically sets the
|
||||
"Value" to the "Label". You can leave it like this if you are
|
||||
unsure of what you are doing.
|
||||
- **Selected**: Check this to pre-select an option in the frontend.
|
||||
- **[ + ]**: Adds a new line for a new option.
|
||||
|
||||
.. figure:: Images/form_elements_multiCheckbox_1.png
|
||||
:alt: Element 'Multi checkbox' - preview in the frontend.
|
||||
|
||||
Element 'Multi checkbox' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_multiCheckbox_2.png
|
||||
:alt: Settings for the 'Multi checkbox' element.
|
||||
|
||||
Settings for the 'Multi checkbox' element.
|
||||
|
||||
.. warning::
|
||||
|
||||
**HTML** does not check that "required" fields are filled out. They
|
||||
are only checked after a form has been submitted.
|
||||
|
||||
|
||||
.. _form-elements-select-elements-multi-select:
|
||||
|
||||
Multi select
|
||||
============
|
||||
|
||||
An element to create a multiple selection. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **First option**: Define the "empty option", i.e. the first element of the
|
||||
select. You can use this to provide additional guidance for the user.
|
||||
- **Choices**: A tool to insert and manage the options.
|
||||
- **Label**: Name of the option.
|
||||
- **Value**: Value of the option. The system automatically sets the
|
||||
"Value" to the "Label". You can leave it like this if you are
|
||||
unsure of what you are doing.
|
||||
- **Selected**: Check this to pre-select an option in the frontend.
|
||||
- **[ + ]**: Adds a new line for a new option.
|
||||
|
||||
.. figure:: Images/form_elements_multiSelect_1.png
|
||||
:alt: Element 'Multi select' - preview in the frontend.
|
||||
|
||||
Element 'Multi select' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_multiSelect_2.png
|
||||
:alt: Settings for the 'Multi select' element.
|
||||
|
||||
Settings for the 'Multi select' element.
|
||||
|
||||
|
||||
.. _form-elements-select-elements-country-select:
|
||||
|
||||
Country select
|
||||
==============
|
||||
|
||||
An element to create a country selectbox. This element has the
|
||||
:ref:`basic settings <form-elements-settings>` Additional settings:
|
||||
|
||||
- **First option**: Define the "empty option", i.e. the first element of the
|
||||
select. You can use this to provide additional guidance for the user.
|
||||
- **Prioritized countries**: A multi-selection of country names, which should
|
||||
be listed as the top options in the form element.
|
||||
- **Only countries**: Restrict the countries to be rendered in the selection.
|
||||
- **Exclude countries**: Define which countries should not appear in the
|
||||
selection.
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements:
|
||||
|
||||
Advanced elements
|
||||
-----------------
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements-file-upload:
|
||||
|
||||
File upload
|
||||
===========
|
||||
|
||||
An element to upload a file to the :guilabel:`File > Filelist` module. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **Allowed Mime Types**: Select the allowed file extensions a user is able to
|
||||
upload.
|
||||
- **Storage path for uploads**: Select the storage path in your TYPO3 installation.
|
||||
This is where the uploaded file will be saved.
|
||||
|
||||
.. figure:: Images/form_elements_fileUpload_1.png
|
||||
:alt: Element 'File upload' - preview in the frontend.
|
||||
|
||||
Element 'File upload' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_fileUpload_2.png
|
||||
:alt: Settings for the 'File upload' element.
|
||||
|
||||
Settings for the 'File upload' element.
|
||||
|
||||
.. error::
|
||||
|
||||
**Privacy issues**:
|
||||
Keep in mind that the storage path you choose may not be protected. The path may
|
||||
be indexed by your search and search engines. If you need to protect sensitive
|
||||
documents, contact your administrator to create a secure storage path.
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements-hidden:
|
||||
|
||||
Hidden
|
||||
======
|
||||
|
||||
A field that is not visible in the frontend. The form element is inside the red
|
||||
rectangle in the image. Such a field might be needed for technical functionality,
|
||||
e.g. to add hidden values to a form. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **Value**: Here you can set a value for the element.
|
||||
|
||||
.. figure:: Images/form_elements_hidden_1.png
|
||||
:alt: Element 'Hidden' - preview in the frontend.
|
||||
|
||||
Element 'Hidden' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_hidden_2.png
|
||||
:alt: Settings for the 'Hidden' element.
|
||||
|
||||
Settings for the 'Hidden' element.
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements-image-upload:
|
||||
|
||||
Image upload
|
||||
============
|
||||
|
||||
An element to upload an image to :guilabel:`File > Filelist`. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Other settings:
|
||||
|
||||
- **Allowed Mime Types**: Select the file extensions a user is allowed to
|
||||
upload.
|
||||
- **Storage path for uploads**: Select the storage path in your TYPO3 installation.
|
||||
This is where the uploaded file will be saved.
|
||||
|
||||
.. figure:: Images/form_elements_imageUpload_1.png
|
||||
:alt: Element 'Image upload' - preview in the frontend.
|
||||
|
||||
Element 'Image upload' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_imageUpload_2.png
|
||||
:alt: Settings for the 'Image upload' element.
|
||||
|
||||
Settings for the 'Image upload' element.
|
||||
|
||||
.. error::
|
||||
|
||||
**Privacy issues**:
|
||||
Keep in mind that the storage path you choose may not be protected. The path may
|
||||
be indexed by your search and search engines. If you need to protect sensitive
|
||||
documents, contact your administrator to create a secure storage path.
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements-advanced-password:
|
||||
|
||||
Advanced password
|
||||
=================
|
||||
|
||||
The element is analogous to the `Password` form element. A single-line text
|
||||
field is displayed for entering a password. The browser "hides" the text input,
|
||||
i.e. the entered characters are not visible. Another field is displayed below it
|
||||
so that the user has to repeat the password to prevent typing errors. This field
|
||||
is useful for registration forms. This element has the
|
||||
:ref:`basic settings <form-elements-settings>`. Additional settings:
|
||||
|
||||
- **Confirmation label**: Label for the confirmation field.
|
||||
|
||||
.. figure:: Images/form_elements_advancedPassword_1.png
|
||||
:alt: Element 'Advanced password' - preview in the frontend.
|
||||
|
||||
Element 'Advanced password' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_advancedPassword_2.png
|
||||
:alt: Settings for the 'Advanced password' element.
|
||||
|
||||
Settings for the 'Advanced password' element.
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements-static-text:
|
||||
|
||||
Static text
|
||||
===========
|
||||
|
||||
A field for static text. This text cannot be formatted, which means you can't
|
||||
insert links or highlight text. Instead, the text is output in the style of
|
||||
your website. The settings for this element are:
|
||||
|
||||
- **Heading**: Heading for the element.
|
||||
- **Text**: Content for the element.
|
||||
|
||||
.. figure:: Images/form_elements_staticText_1.png
|
||||
:alt: Element 'Static text' - preview in the frontend.
|
||||
|
||||
Element 'Static text' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_staticText_2.png
|
||||
:alt: Settings for the 'Static text' element.
|
||||
|
||||
Settings for the 'Static text' element.
|
||||
|
||||
|
||||
.. _form-elements-advanced-elements-content-element:
|
||||
|
||||
Content element
|
||||
================
|
||||
|
||||
You can display any content elements that are on your website. The settings for
|
||||
this element are:
|
||||
|
||||
- **Content element uid**: ID of the content element you want to display. You can
|
||||
either enter the ID manually or select it via the page tree.
|
||||
To do this, click on the "Page content" button.
|
||||
- **[ Page content ]**: Modal which displays the page tree. You can select
|
||||
a page and the content element.
|
||||
|
||||
.. figure:: Images/form_elements_contentElement_1.png
|
||||
:alt: Element 'Content element' - preview in the frontend.
|
||||
|
||||
Element 'Content element' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_contentElement_2.png
|
||||
:alt: Settings for the 'Content element' element.
|
||||
|
||||
Settings for the 'Content element' element.
|
||||
|
||||
|
||||
.. _form-elements-container-elements:
|
||||
|
||||
Container elements
|
||||
------------------
|
||||
|
||||
Fieldset and grid elements are container elements that structure
|
||||
your form in terms of content or visual appearance. Container elements can
|
||||
be combined. For example, a fieldset can contain several grids.
|
||||
|
||||
|
||||
.. _form-elements-container-elements-fieldset:
|
||||
|
||||
Fieldset
|
||||
========
|
||||
|
||||
This container groups form elements based on content. This is
|
||||
important for screen readers and helps you to improve the accessibility of your form.
|
||||
For example, in an "Address" fieldset you could have
|
||||
street, house number, postal code and city form elements. The settings for
|
||||
this element are:
|
||||
|
||||
- **Field group name**: Heading for the field group, e.g. "Address".
|
||||
|
||||
.. figure:: Images/form_elements_fieldset_1.png
|
||||
:alt: Element 'Fieldset' - preview in the frontend.
|
||||
|
||||
Element 'Fieldset' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_fieldset_2.png
|
||||
:alt: Element 'Fieldset' - preview in the backend.
|
||||
|
||||
Element 'Fieldset' - preview in the backend.
|
||||
|
||||
.. figure:: Images/form_elements_fieldset_3.png
|
||||
:alt: Settings for the 'Fieldset' element.
|
||||
|
||||
Settings for the 'Fieldset' element.
|
||||
|
||||
|
||||
.. _form-elements-container-elements-grid:
|
||||
|
||||
Grid
|
||||
====
|
||||
|
||||
Use this container element to place fields next to each other (create a visual structure).
|
||||
|
||||
**The additional settings apply to the content elements inside the grid**:
|
||||
|
||||
- **Configuration Grid Area**:
|
||||
- Areas: **xs** (Very small), **sm** (Small), **md** (Medium), **lg** (Large),
|
||||
**xl** (Extra large), **xxl** (Extra extra large).
|
||||
- These are the "breakpoints". These are ranges of
|
||||
resolutions or adaptations to different screen sizes. Smartphones,
|
||||
for example, have a low resolution range (xs or sm) and desktop monitors
|
||||
have a high resolution range (lg, xl or xxl). Use this to
|
||||
abstractly control how many elements are displayed next to each other in
|
||||
which resolution.
|
||||
- **Number of columns for grid area "xx"**:
|
||||
- Enter a number for the selected area.
|
||||
- The number determines how much space the field takes up on the different
|
||||
screen sizes and therefore how many elements are displayed next to
|
||||
each other.
|
||||
|
||||
.. figure:: Images/form_elements_grid_1.png
|
||||
:alt: Element 'Grid' - preview in the frontend.
|
||||
|
||||
Element 'Grid' - preview in the frontend.
|
||||
|
||||
.. figure:: Images/form_elements_grid_2.png
|
||||
:alt: Element 'Grid' - preview in the backend.
|
||||
|
||||
Element 'Grid' - preview in the backend.
|
||||
|
||||
.. figure:: Images/form_elements_grid_3.png
|
||||
:alt: Settings for the 'Grid' element - Part 1.
|
||||
|
||||
Settings for the 'Grid' element - Part 1.
|
||||
|
||||
.. figure:: Images/form_elements_grid_4.png
|
||||
:alt: Settings for the 'Grid' element - Part 2.
|
||||
|
||||
Settings for the 'Grid' element - Part 2.
|
||||
@@ -0,0 +1,61 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _forEditors:
|
||||
|
||||
===========
|
||||
For Editors
|
||||
===========
|
||||
|
||||
Introduction to forms
|
||||
---------------------
|
||||
|
||||
Forms are provided by the **Form TYPO3 extension**. Form is a TYPO3 core
|
||||
extension which has been available by default since TYPO3 version 8.
|
||||
|
||||
What can Form do?
|
||||
-----------------
|
||||
|
||||
- TYPO3 core extension
|
||||
- flexible, extensible and easy to use
|
||||
- easy to use via drag-and-drop
|
||||
- live preview
|
||||
- form reuse
|
||||
- create templates for new forms
|
||||
- set mandatory fields
|
||||
- set finishers (downstream processing)
|
||||
- automatic spam protection
|
||||
- multi-step forms
|
||||
|
||||
What can't Form do?
|
||||
-------------------
|
||||
|
||||
Form has limited:
|
||||
|
||||
- formatting of form labels
|
||||
- multilingual support
|
||||
- possibilities for textual design of emails
|
||||
|
||||
When can I use Form?
|
||||
--------------------
|
||||
|
||||
- for contact forms
|
||||
- for application forms
|
||||
- for simple or complex forms
|
||||
- for different forms on my pages
|
||||
|
||||
Notes on data protection
|
||||
------------------------
|
||||
|
||||
Data submitted in forms is not stored in the TYPO3 backend due to privacy reasons.
|
||||
There are TYPO3 extensions that retrofit this behavior but we do not recommend using these
|
||||
extensions. Instead, check if the form data can be transferred directly to your
|
||||
CRM or similar tools.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
FormElements/Index
|
||||
Validators/Index
|
||||
Finishers/Index
|
||||
Accessibility/Index
|
||||
Tutorials/Index
|
||||
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 42 KiB |