.. include:: /Includes.rst.txt .. _concepts-frontendrendering: ================== Frontend rendering ================== .. _concepts-frontendrendering-templates: Templates ========= Fluid templates in the form framework are based on `Bootstrap`_. .. _Bootstrap: https://getbootstrap.com/ .. _concepts-frontendrendering-templates-customtemplates: Custom templates ---------------- In order to use your own Fluid templates for frontend forms, register your own template paths via YAML in the form configuration (here under the default ``standard`` prototype). .. code-block:: yaml prototypes: standard: formElementsDefinition: Form: renderingOptions: templateRootPaths: 100: 'EXT:my_site_package/Resources/Private/Frontend/Templates/' partialRootPaths: 100: 'EXT:my_site_package/Resources/Private/Frontend/Partials/' layoutRootPaths: 100: 'EXT:my_site_package/Resources/Private/Frontend/Layouts/' If your `form definition` then references the `standard` prototype, the form framework will look for Fluid templates in :directory:`EXT:my_site_package/Resources/Private/Frontend/[*]`. The `Form` element is the 'main' element. The framework will look for :file:`Form.html` in :directory:`templateRootPaths`. For all other elements, it will look in :directory:`partialRootPaths`. A partial has the same name as the `formElementTypeIdentifier` property, for example, a `Text` template will be in a partial named :file:`Text.html` in :directory:`partialRootPaths`. .. _concepts-frontendrendering-templates-singlevalues: Form element values in finisher templates ----------------------------------------- Use the :php:`RenderFormValueViewHelper` to access form element values in your finisher templates. This ViewHelper accepts a single form element and renders it. The following example shows the :php:`RenderFormValueViewHelper` being called with two parameters (`renderable` and `as`) to output the value of a `message` field. The value :fluid:`{formValue.processedValue}` can then be manipulated with Fluid, styled, etc. .. code-block:: html {formValue.processedValue} Names of your form elements can be found in your form definition (in your individual YAML files or in the :guilabel:`System > Configuration` module if you have the lowlevel extension installed). Or use the debug ViewHelper in Fluid to list all the form elements. .. code-block:: html {page.rootForm.elements} .. _concepts-frontendrendering-translation: Translation =========== .. _concepts-frontendrendering-translation-formdefinition: Translate form definition ------------------------- Translation of `form definitions` works differently to the usual translation of the backend. Currently, there is no graphical user interface for this translation process. If `form definition` properties were translated in the same way as the rest of the backend, a backend editor using the `form editor` to edit a form they would see long unwieldy translation keys. In order to avoid this, form element *properties* are translated instead of their values. The form framework does not look for translation keys in a translation file. Instead, the system searches for translations of the form element properties independent of their property values. The property values are ignored if an entry is found in a translation file. The form element property values are overridden by the translated values. This approach is a compromise between two scenarios: creating forms using the `form editor` or creating `form definitions` (which could later be edited in the `form editor`). An editor can create forms just using the `form editor` where form element property values are displayed in the default language. An integrator can provide additional language files which translate the form depending on the prototype. Add additional translation files to the form configuration as follows: .. code-block:: yaml prototypes: standard: formElementsDefinition: Form: renderingOptions: translation: translationFiles: # custom translation file 20: 'EXT:my_site_package/Resources/Private/Language/Form/locallang.xlf' The translationFiles array is processed from the highest key to the lowest, i.e. your translation file with key `20` is processed before translation files with key '10' in EXT:form. If no key is found in the translation files, a property value will be displayed unmodified. The following properties can be translated: * label * properties.[*] * properties.options.[*] * properties.fluidAdditionalAttributes.[*] * renderingOptions.[*] The translation keys are put together based on a specific pattern and there is a order (fallback chain) for the translations that depends on translation scenarios. These are the translation scenarios: * translation of a form element property for a specific form (`formDefinitionIdentifier) and form element (`ElementIdentifier`) * translation of a form element property for a specific form element (`formElementIdentifier`) and various forms * translation of a form element property for an element type (`elementType`) and various forms, e.g. the `Page` element The look-up process searches for translation keys in all given translation files based on the following order (the same order as the translation scenarios above): * `.element..properties.` * `element..properties.` * `element..properties.` Translation of options (`properties.options`) in form elements, like the `Select` element, have the following look-up order: * `.element..properties.options.` * `element..properties.options.` .. _concepts-frontendrendering-translation-formdefinition-example: Example Form Definition ~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: yaml identifier: ApplicationForm type: Form prototypeName: standard label: 'Application form' renderables: - identifier: GeneralInformation type: Page label: 'General information' renderables: - identifier: LastName type: Text label: 'Last name' properties: placeholder: 'Please enter your last name.' defaultValue: '' - identifier: Software type: MultiSelect label: 'Known software' properties: options: value1: TYPO3 value2: Neos In order to translate the form element `LastName`, the process will look for the following translation keys in the translation files: * `ApplicationForm.element.LastName.properties.label` (*.element..properties.*) * `element.LastName.properties.label` (*element..properties.*) * `element.Text.properties.label` (*element..properties.*) If none of these keys exist, 'Last name' will be displayed. In order to translate the form element `Software`, the process will look for the following translation keys in the translation files: * `ApplicationForm.element.Software.properties.label` (*.element..properties.*) * `element.Software.properties.label` (*element..properties.*) * `element.MultiSelect.properties.label` (*element..properties.*) If none of the these keys exist, 'Known software' will be displayed. The option properties lookup process is as the following: * `ApplicationForm.element.Software.properties.options.value1` (*.element..properties.options.*) * `element.Software.properties.options.value1` (*element..properties.options.*) * `ApplicationForm.element.Software.properties.options.value2` (*.element..properties.options.*) * `element.Software.properties.options.value2` (*element..properties.options.*) If none of the these keys exist, 'TYPO3' will be displayed as label for the first option and 'Neos' for the second option. .. _concepts-frontendrendering-translation-validationerrors: Translation of validation messages ---------------------------------- The translation of validation messages is similar to the translation of `form definitions` abpve. The same translation files can be used. If the look-up process does not find a key within the files, an Extbase message will be displayed. EXT:form translates validators by default. The same as for `form definitions`, the translation keys are put together based on a specific pattern. There is also a fallback chain. The following translation scenarios are possible: * translation of validation messages for a specific validator of a specific form element (`elementIdentifier`) and specific form (`formDefinitionIdentifier`) * translation of validation messages for a specific validator of various form elements within a specific form (`formDefinitionIdentifier`) * translation of validation messages for a specific validator of a specific form element (`elementIdentifier`) in various forms * translation of validation messages for a specific validator in various forms In Extbase, validation messages are identified by numerical codes (UNIX timestamps). Different codes can be used for the same validator. Read more about :ref:`concrete validator configurations `. The look-up process searches for translation keys in the translation files in the following order (the same order as the translation scenarios above): * `.validation.error..` * `.validation.error.` * `validation.error..` * `validation.error.` .. _concepts-frontendrendering-translation-validation-example: Example Form Definition with Validator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: yaml identifier: ContactForm type: Form prototypeName: standard label: 'Contact us' renderables: - identifier: Page1 type: Page label: 'Page 1' renderables: - identifier: LastName type: Text label: 'Last name' properties: fluidAdditionalAttributes: required: required validators: - identifier: NotEmpty If a user submits this form without providing a last name, the `NotEmpty` validator (at the bottom of the example above) fails and sends 1221560910 as a ``. The system looks through the translation keys in the following order searching for the `NotEmpty` validator for form element `LastName`: * ContactForm.validation.error.LastName.1221560910 (*.validation.error..*) * ContactForm.validation.error.1221560910 (*.validation.error.*) * validation.error.LastName.1221560910 (*validation.error..*) * validation.error.1221560910 (validation*.error.*) As mentioned above, if no translation key is available, a default Extbase framework message is displayed. .. _concepts-finishers-translation: .. _concepts-frontendrendering-translation-finishers: Translation of finisher options ------------------------------- The translation of finisher options is similar to the translation of `form definitions` above. The same translation files can be used. If the look-up process does not find a key in the provided translation files, the property value will be displayed unmodified. The same as for `form definitions`, the translation keys are put together based on a specific pattern. There is also a fallback chain. The following translation scenarios are possible: * translation of finisher options for a specific finisher (`finisherIdentifier`) of a specific form (`formDefinitionIdentifier` below) * translation of finisher options for a specific finisher (`finisherIdentifier`) of various forms The look-up process searches for translation keys in all the translation files based on the following order (the same order as the translation scenarios above): * `.finisher..` * `finisher..` The translation order is as follows: 1. Default value from form definition 2. Overridden value from a FlexForm (if any) 3. Localized value provided by translation files (if any) The :yaml:`translation.propertiesExcludedFromTranslation` option skips the third step so that the translation resolves to a FlexForm value if one exists. For an example see `Skip translation of overridden form finisher options `_. .. _concepts-frontendrendering-translation-finishers-example: Example Form Definition with Finisher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: yaml identifier: ContactForm type: Form prototypeName: standard label: 'Contact us' finishers: - identifier: Confirmation options: message: 'Thank you for your inquiry.' renderables: ... The look-up process searches for the following translation keys for the 'Confirmation' finisher message option: * `ContactForm.finisher.Confirmation.message` (*.finisher..*) * `finisher.Confirmation.message` (*finisher..*) If no translation key exists, the message 'Thank you for your inquiry.' will be displayed. .. _concepts-frontendrendering-translation-arguments: Form element translation arguments ================================== Form element property translations and finisher option translations can have placeholders to output translation arguments. Translations can be enriched with variable values by passing arguments to form element properties. This feature was introduced in :issue:`81363`. .. _concepts-frontendrendering-translation-properties: Form element properties ----------------------- In the YAML form configuration you can add simple literal values: .. code-block:: yaml renderables: - identifier: field-with-translation-arguments type: Checkbox label: This is a %s feature renderingOptions: translation: translationFiles: 10: path/to/locallang.xlf arguments: label: - useful This will produce the label: `This is a useful feature`. Alternatively, you can use :typoscript:`formDefinitionOverrides` in TypoScript to set translation arguments. One use case is a checkbox for user confirmation which links to further information. Here it makes sense to use YAML hashes (key value pairs) instead of YAML lists so that sections have keys. This simplifies references in TypoScript since named keys are easy to read and can easily be reordered. With lists and numeric keys the TypoScript setup would also need to be updated in this case. In the following form configuration example the list of :yaml:`renderables` has been replaced with a hash of :yaml:`renderables`, and the field :yaml:`field-with-translation-arguments` now has a named key :yaml:`fieldWithTranslationArguments`. This key can be anything as long as it is unique at its level in the YAML - here just the :yaml:`identifier` in another form: .. code-block:: yaml renderables: fieldWithTranslationArguments: identifier: field-with-translation-arguments type: Checkbox label: I agree to the terms and conditions renderingOptions: translation: translationFiles: 10: path/to/locallang.xlf If the label contains HTML markup - like in the above example - it must be wrapped in `CDATA` tags in the :directory:`path/to/locallang.xlf` translation file, to prevent analysis of character data by the parser. Also, the label should be rendered using the :fluid:`` ViewHelper in fluid templates, to prevent escaping of HTML tags: .. code-block:: xml terms and conditions]]> The TypoScript below can use the :typoscript:`fieldWithTranslationArguments` key to refer to the field and adds a page URL as a translation argument for the link in the label: .. code-block:: typoscript plugin.tx_form { settings { formDefinitionOverrides { { renderables { 0 { # Page renderables { fieldWithTranslationArguments { renderingOptions { translation { arguments { label { 0 = TEXT 0.typolink { # Terms and conditions page, could be # set also via TypoScript constants parameter = 42 returnLast = url } } } } } } } } } } } } } The :yaml:`Page` element of the form definition is not registered with a named key so a numeric key :yaml:`0` is used which, as mentioned above, is prone to errors when more pages are added or reordered. .. important:: There must be at least one translation file with a translation for the form element property. Arguments are not inserted into default values in a form definition. Finishers --------- The same mechanism (YAML, YAML + TypoScript) works for finisher options: .. code-block:: yaml finishers: finisherWithTranslationArguments: identifier: EmailToReceiver options: subject: My %s subject recipients: your.company@example.com: 'Your Company name' ceo@example.com: 'CEO' senderAddress: bar@example.org translation: translationFiles: 10: path/to/locallang.xlf arguments: subject: - awesome This will produce `My awesome subject`. .. _concepts-frontendrendering-basiccodecomponents: Basic code components ===================== .. figure:: ../../Images/basic_code_components.png :alt: Basic code components Basic code components .. _concepts-frontendrendering-basiccodecomponents-formdefinition: TYPO3\\CMS\\Form\\Domain\\Model\\FormDefinition ----------------------------------------------- The class :php:`TYPO3\CMS\Form\Domain\Model\FormDefinition` encapsulates a complete `form definition`, with all of its * pages, * form elements, * validation rules, and * finishers which are executed when the form is submitted. The FormDefinition domain model is not modified when the form is executed. .. _concepts-frontendrendering-basiccodecomponents-formdefinition-anatomy: The anatomy of a form ~~~~~~~~~~~~~~~~~~~~~ A `FormDefinition` domain model consists of multiple `Page` objects. When a form is displayed, only one `Page` is visible at a time. However, you can navigate back and forth between the pages. A `Page` consists of multiple `FormElements` which represent input fields, textareas, checkboxes, etc, on a page. The `FormDefinition` domain model, `Page` and `FormElement` objects have `identifiers` which must be unique for each ``, i.e. the `FormDefinition` domain model and a `FormElement` object may have the same `identifier` but two `FormElement` objects cannot have the same identifier. .. _concepts-frontendrendering-basiccodecomponents-formdefinition-anatomy-example: Example """"""" You can create a :php:`FormDefinition` domain model by calling the API methods on it, or you can use a :php:`FormFactory` to build the form from a different representation format such as YAML. The example below calls API methods to add a page to a :php:`FormDefinition` and then to add an element to the page: .. code-block:: php $formDefinition = GeneralUtility::makeInstance(FormDefinition::class, 'myForm'); $page1 = GeneralUtility::makeInstance(Page::class, 'page1'); $formDefinition->addPage($page); // second argument is the of the form element $element1 = GeneralUtility::makeInstance(GenericFormElement::class, 'title', 'Text'); $page1->addElement($element1); .. _concepts-frontendrendering-basiccodecomponents-formdefinition-createformusingabstracttypes: Creating a form using abstract form element types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use the :php:`TYPO3\CMS\Form\Domain\Model\FormDefinition::addPage()` and :php:`TYPO3\CMS\Form\Domain\Model\FormElements\Page::addElement()` methods as above and create the `Page` and `FormElement` objects manually, but it is often better to use the corresponding *create* methods (:php:`TYPO3\CMS\Form\Domain\Model\FormDefinition::createPage()` and :php:`TYPO3\CMS\Form\Domain\Model\FormElements\Page::createElement()`). You only need to pass them an abstract `` such as `Text` or `Page` and EXT:form will resolve the classname and set default values. The :ref:`simple example ` shown above can then be rewritten as follows: .. code-block:: php // we will come back to this later on $prototypeConfiguration = []; $formDefinition = GeneralUtility::makeInstance(FormDefinition::class, 'myForm', $prototypeConfiguration); $page1 = $formDefinition->createPage('page1'); $element1 = $page1->addElement('title', 'Text'); You might wonder how the system knows that the element `Text` is implemented with a `GenericFormElement`. This is configured in the :php:`$prototypeConfiguration`. To make the example from above actually work, we need to add some meaningful values to :php:`$prototypeConfiguration`: .. code-block:: php $prototypeConfiguration = [ 'formElementsDefinition' => [ 'Page' => [ 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page' ], 'Text' => [ 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement' ], ], ]; For each abstract ``, we have to add some configuration. In the snippet above, we only define the `implementation class name`. Apart from that, it is always possible to set default values for all configuration options of such elements, as the following example shows: .. code-block:: php $prototypeConfiguration = [ 'formElementsDefinition' => [ 'Page' => [ 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page', 'label' => 'This is the label of the page if nothing else is specified' ], 'Text' => [ 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement', 'label' = >'Default Label', 'defaultValue' => 'Default form element value', 'properties' => [ 'placeholder' => 'Text that is shown if element is empty' ], ], ], ]; .. _concepts-frontendrendering-basiccodecomponents-formdefinition-preconfiguredconfiguration: Using pre-configured $prototypeConfiguration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Often, it does not make sense to manually create the $prototypeConfiguration array. Bigger parts of this array are pre-configured in the extensions's YAML settings. The :php:`TYPO3\CMS\Form\Domain\Configuration\ConfigurationService` contains helper methods which return the ready-to-use :php`$prototypeConfiguration`. .. _concepts-frontendrendering-basiccodecomponents-formdefinition-rednering: Rendering a FormDefinition ~~~~~~~~~~~~~~~~~~~~~~~~~~ To trigger the rendering of a :php:`FormDefinition` domain model, the current :php:`TYPO3\CMS\Extbase\Mvc\Web\Request` needs to be bound to the `FormDefinition`. This binding results in a :php:`TYPO3\CMS\Form\Domain\Runtime\FormRuntime` object which contains the `Runtime State` of the form. Among other things, this object includes the currently inserted values: .. code-block:: php // $currentRequest needs to be available. // Inside a controller, you would use $this->request $form = $formDefinition->bind($currentRequest); // now, you can use the $form object to get information about the currently entered values, etc. .. _concepts-frontendrendering-basiccodecomponents-formruntime: TYPO3\\CMS\\Form\\Domain\\Runtime\\FormRuntime ---------------------------------------------- This class implements the runtime logic of a form, i.e. the class * decides which page is currently shown, * determines the current values of the form * triggers validation and property mappings. You generally receive an instance of this class by calling :php:`TYPO3\CMS\Form\Domain\Model\FormDefinition::bind()`. .. _concepts-frontendrendering-basiccodecomponents-formruntime-render: Rendering a form ~~~~~~~~~~~~~~~~ Rendering a form is easy. Just call :php:`render()` on the :php:`FormRuntime`:: .. code-block:: php $form = $formDefinition->bind($request); $renderedForm = $form->render(); .. _concepts-frontendrendering-basiccodecomponents-formruntime-accessingformvalues: Accessing form values ~~~~~~~~~~~~~~~~~~~~~ In order to get the values the user has entered into the form, you can access the :php:`FormRuntime` object like an array. If a form element with the identifier `firstName` exists, you can use :php:`$form['firstName']` to retrieve its current value. You can set values the same way. .. _concepts-frontendrendering-basiccodecomponents-formruntime-renderinginternals: Rendering internals ~~~~~~~~~~~~~~~~~~~ The :php:`FormRuntime` inquires the :php:`FormDefinition` domain model regarding the configured renderer (:php:`TYPO3\CMS\Form\Domain\Model\FormDefinition::getRendererClassName()`) and then triggers :php:`render()` on this Renderer. This allows you to declaratively define how a form should be rendered. .. code-block:: yaml prototypes: standard: formElementsDefinition: Form: rendererClassName: 'TYPO3\CMS\Form\Domain\Renderer\FluidFormRenderer' .. _concepts-frontendrendering-basiccodecomponents-fluidformrenderer: TYPO3\\CMS\\Form\\Domain\\Renderer\\FluidFormRenderer ----------------------------------------------------- This class is a :php:`TYPO3\CMS\Form\Domain\Renderer\RendererInterface` implementation which used to render a :php:`FormDefinition` domain model. It is the default :t3ext:`form` renderer. Learn more about the :ref:`FluidFormRenderer Options`. .. _concepts-frontendrendering-codecomponents-customformelementimplementations: Custom form element implementations ----------------------------------- :t3ext:`form` ships a decent amount of hooks which are available at crucial points of the life cycle of a `FormElement`. Most of the time, own implementations are therefore unnecessary. An own form element can be defined by: * writing some configuration, and * utilizing the standard implementation of :php:`TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement`. .. code-block:: yaml prototypes: standard: formElementsDefinition: CustomFormElementIdentifier: implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement' With the provided hooks, this `FormElement` can now be manipulated. .. seealso:: * :ref:`Hooks for runtime manipulation ` * :ref:`PSR-14 events ` If you insist on your own implementation, the abstract class :php:`TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement` offers a perfect entry point. In addition, we recommend checking-out :php:`TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable`. All of your own form element implementations must be programmed to the interface :php:`TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface`. It is a good idea to derive your implementation from :php:`TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement`. .. _concepts-frontendrendering-renderviewHelper: "render" viewHelper =================== The `RenderViewHelper` is the actual starting point for form rendering and not the typical Extbase Controller as you may know it. For more technical insights read more about the viewHelper's :ref:`arguments`. .. _concepts-frontendrendering-fluidtemplate: Render through FLUIDTEMPLATE (without controller) ------------------------------------------------- .. code-block:: typoscript tt_content.custom_content_element = COA_INT tt_content.custom_content_element { 20 = FLUIDTEMPLATE 20 { file = EXT:my_site_package/Resources/Private/Templates/CustomContentElement.html settings { persistenceIdentifier = EXT:my_site_package/Resources/Private/Forms/MyForm.yaml } extbase.pluginName = Formframework extbase.controllerExtensionName = Form extbase.controllerName = FormFrontend extbase.controllerActionName = perform } } ``my_site_package/Resources/Private/Templates/CustomContentElement.html``: .. code-block:: html .. _concepts-frontendrendering-extbase: Render within your own Extbase extension ---------------------------------------- It is straight forward. Use the `RenderViewHelper` like this and you are done: .. code-block:: html Point the property `controllerAction` to the desired action name and provide values for the other parameters displayed below (you might need those). .. code-block:: yaml type: Form identifier: 'example-form' label: 'TYPO3 is cool' prototypeName: standard renderingOptions: controllerAction: perform addQueryString: false argumentsToBeExcludedFromQueryString: [] additionalParams: [] renderables: ... .. note:: In general, you can override each and every `form definition` with the help of TypoScript (see ':ref:`TypoScript overrides`'). When using the `RenderViewHelper`, there is a second way: The ':ref:`overrideConfiguration`' parameter. This way, you can override the form definition within your template. Provide an according array as shown in the example below. .. code-block:: html .. _concepts-frontendrendering-programmatically: Build forms programmatically ============================ To learn more about this topic, head to the chapter ':ref:`Build forms programmatically`' which is part of the API reference section. .. _concepts-frontendrendering-runtimemanipulation: Runtime manipulation ==================== .. _concepts-frontendrendering-runtimemanipulation-hooks: Hooks ----- :t3ext:`form` implements a decent amount of hooks that allow the manipulation of your forms during runtime. In this way, it is possible to, for example, * ... prefill form elements with values from your database, * ... skip a whole page based on the value of a certain form element, * ... mark a form element as mandatory depending of the chosen value of another form element. Please check out the ':ref:`API reference section`' for more details. .. _concepts-frontendrendering-runtimemanipulation-typoscriptoverrides: TypoScript overrides -------------------- Each and every `form definition` can be overridden via TypoScript if the :php:`FormFrontendController` of :t3ext:`form` is used to render the form. Normally, this is the case if the form has been added to the page using the form plugin or when rendering the form via :ref:`FLUIDTEMPLATE `. The overriding of settings with TypoScript's help takes place after the :ref:`custom finisher settings` of the form plugin have been loaded. In this way, you are able to manipulate the `form definition` for a single page. In doing so, the altered `form definition` is passed to the :php:`RenderViewHelper` which then generates the form programmatically. At this point, you can still change the form elements using the above-mentioned concept of :ref:`hooks`. .. code-block:: typoscript plugin.tx_form { settings { formDefinitionOverrides { { renderables { 0 { renderables { 0 { label = TEXT label.value = Overridden label } } } } } } } }