Project

General

Profile

Actions

Bug #32412

closed

TCA: readOnly renders as 'disabled' element instead of 'readonly'. 'passthrough' type renders nothing (not even a hidden field). No way to pass default IRRE child 'type' values.

Added by Christian Weiske over 12 years ago. Updated almost 3 years ago.

Status:
Rejected
Priority:
Must have
Assignee:
-
Category:
FormEngine aka TCEforms
Target version:
-
Start date:
2018-12-02
Due date:
% Done:

0%

Estimated time:
TYPO3 Version:
10
PHP Version:
7.4
Tags:
Complexity:
Is Regression:
Yes
Sprint Focus:

Description

When setting a TCA element's config "readOnly" to "true", then the element gets rendered with the "disabled" HTML attribute instead of the "readonly" attribute as described in http://www.w3.org/TR/html401/interact/forms.html#h-17.12.2

The problem with that is that "disabled" prevents the browser from sending the value, while "readonly" would cause the browser to send the value.


Related issues 2 (0 open2 closed)

Related to TYPO3 Core - Bug #23975: TCAtree config option readOnly = 1 has no effectClosed2010-11-07

Actions
Related to TYPO3 Core - Bug #56060: TCA type inline readOnlyClosed2014-02-17

Actions
Actions #1

Updated by Christian Weiske over 12 years ago

t3lib/class.t3lib_tceforms.php would need to be changed, all the instances of

        if($this->renderReadonly || $config['readOnly'])  {
            $disabled = ' disabled="disabled"';
        }

Actions #2

Updated by Markus Klein over 12 years ago

Why do you need these data sent back to TYPO3 from the browser?

Actions #3

Updated by Christian Weiske over 12 years ago

I need that when sending the user via a hand-crafted link to "add new record" form with some default values, and some of the default values may not be changed by the user.

Actions #4

Updated by Mathias Schreiber over 9 years ago

  • Category changed from Backend User Interface to FormEngine aka TCEforms
  • Status changed from New to Accepted
  • TYPO3 Version changed from 4.3 to 7
  • PHP Version changed from 5.3 to 5.5
  • Is Regression set to No
Actions #5

Updated by Christian Kuhn about 7 years ago

  • Status changed from Accepted to Rejected

type=passthrough can be used to send values to the dataHandler, and passthrough could have an own renderType if you still need something to be displayed.

changing disabled=disabled to readonly would cause hazard in formEngine.

Actions #6

Updated by Leonie Philine over 5 years ago

  • Subject changed from tca: readOnly disabled element instead of setting it to readonly to TCA: readOnly renders as 'disabled' element instead of 'readonly'. 'passthrough' type renders nothing (not even a hidden field). No way to pass default IRRE child 'type' values.
  • Priority changed from Should have to Must have
  • Start date changed from 2011-12-09 to 2018-12-02
  • TYPO3 Version changed from 7 to 9
  • PHP Version changed from 5.5 to 7.2
  • Is Regression changed from No to Yes

Hi!

I unfortunately must re-open this bug, since some circumstances seem to have changed:

Christian Kuhn wrote:
"type=passthrough can be used to send values to the dataHandler"

This is (no longer?) true. \TYPO3\CMS\Backend\Form\Element\PassThroughElement renders entirely empty - there is no hidden field which would post record data to the DataHandler.

There seems to be a regression now:

1) Create an inline field, e.g. in tt_content for a custom fluid styled content element, holding a list of items

// TCA/Overrides/tt_content.php

    $GLOBALS['TCA']['tt_content']['columns']['my_content_items'] = [
        'label' => $l10nPrefix . 'ContentElements.Generic.ContentItem.title',
        'config' => [
            'type' => 'inline',
            'foreign_table' => 'tx_my_content_item',
            'foreign_field' => 'parent_uid',
            'foreign_table_field' => 'parent_table',
        ],
    ];

2) The child table should have various types, which can be applied depending on the parent (tt_content) CType:

// child table tx_my_content_item

    'columns' => [
        'type' => [
            'exclude' => 0,
            'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType_formlabel',
            'config' => [
                'type' => 'select',
                'renderType' => 'selectSingle',
                'items' => [
                    [
                        $l10nPrefix . 'ContentElements.Generic.MyItemType1.title',
                        'my-item-type-one'
                    ],
                    [
                        $l10nPrefix . 'ContentElements.Generic.MyItemType2.title',
                        'my-item-type-two'
                    ],
                ]
            ]
        ],
        ...
    ],

3) Now register your custom FCE and override the default child type

// TCA/Overrides/tt_content.php

    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(
        [
            $l10nPrefix . 'ContentElements.MyCustomFCE.title',
            'my_customfce',
            'content-element-my-custom-fce',
        ],
        'CType',
        $extensionKey
    );
    $GLOBALS['TCA']['tt_content']['types']['my_customfce'] = [
        'showitem' => '
            --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
                CType,
                header;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:header_formlabel,
                tx_my_content_items;' . $l10nPrefix . 'ContentElements.MyCustomFCE.items,
        ',
        'columnsOverrides' => [
            'tx_my_content_items' => [
                'config' => [
                    'overrideChildTca' => [
                        'columns' => [
                            'type' => [
                                'config' => [
                                    'default' => 'my-item-type-two',
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ];

4) Note that this works as long as we display the child type column in showItems, and the type column is rendered as EDITABLE select (which we DO NOT want!)

// child table tx_my_content_item

    'types' => [
        'my-item-type-two' => [
            'showitem' => '
                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
                    type;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType_formlabel,
                    header;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:header_formlabel,
                    bodytext_primary;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext_formlabel,
            ',
            'columnsOverrides' => [
                'type' => [
                    'config' => [
                        // Darn - nothing here works. No readOnly, no passthrough - only very expensively writing an own renderType. Oh dear gosh, what a regression.
                    ],
                ],
            ],
        ],
        ...
    ],

5) Now try either setting the child table's type column to "'readOnly' => true" (renders fine - submits nothing) or to "'type' => 'passthrough'" (renders nothing - submits nothing).

=> Clearly a regression! There is NO single way, except writing a complicated own renderType (should absolutely not be necessary for such a common use case of passing an inline child's default 'type' and having the datahandler save it).

The only chance you have is to have the child 'type' select field editable and tell the end-user not to edit it. That's catastrophic.

How to fix it?

1) Make 'readOnly' fields render with the html attribute 'readonly', instead of 'disabled'. This is how it should work anyway.

2) Make 'passthrough' render a hidden field, so that (overridden) default values are transferred.

3) Fix the reason for the big fat red warning in https://docs.typo3.org/typo3cms/TCAReference/Types/Index.html#columnsoverrides , make sure default values are not just presentational.

Thanks for listening!

Actions #7

Updated by Leonie Philine over 5 years ago

Dear random reader:

EDIT: There is no escape. :( The hack described below here won't work, because \TYPO3\CMS\Backend\Form\FormResultCompiler::JSbottom() is not being invoked for child items - only for the main form.

So you can only wait for the core team to come with a fix for this regression, or try to implement your own renderType for your type select field.


THE HACK BELOW HERE DOES NOT WORK FOR INLINE ITEMS. (No need to read further :) )

For anyone wanting a hacky workaround until this is fixed:

Your child table's 'type' field is of type=select and renderType=selectSingle by default.

I found the entirely undocumented \TYPO3\CMS\Backend\Form\Element\InputHiddenElement. You can use that in your child table's 'types' section with 'columnsOverrides':

// child table tx_my_content_item

    'types' => [
        'my-item-type-two' => [
            'showitem' => '
                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
                    type;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType_formlabel,
                    header;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:header_formlabel,
                    bodytext_primary;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext_formlabel,
            ',
            'columnsOverrides' => [
                'type' => [
                    'config' => [
                        'type' => 'input',
                        'renderType' => 'hidden',
                        'default' => 'my-item-type-two',
                    ],
                ],
            ],
        ],
        ...
    ],

Note:
You MUST set type=input, since keeping the non-overridden type=select will cause \TYPO3\CMS\Backend\Form\Element\InputHiddenElement to crash (actually, php throws an exception on `htmlspecialchars()`),
since $parameterArray['itemFormElValue'] will be an array (you won't get your default type resolved as 'my-overridden-default-value' but instead as: array('my-overridden-default-value').)

Actions #8

Updated by Leonie Philine over 5 years ago

Dear random reader:

So here's an actually working render type hack.

Dead TYPO3 core dev:
This is a hack, not a solution. :)

<?php
// typo3conf/ext/my_extension/Classes/System/Form/Element/SelectPassthroughElement.php

namespace Acme\MyExtension\System\Form\Element;

/**
 * Generation of TCEform elements of the type "input type=hidden" for select-value-passthrough
 */
class SelectPassthroughElement extends \TYPO3\CMS\Backend\Form\Element\AbstractFormElement
{
    /**
     * This will render an input type="hidden" form field
     * @return array As defined in initializeResultArray() of AbstractNode
     */
    public function render()
    {
        $parameterArray = $this->data['parameterArray'];
        $resultArray = $this->initializeResultArray();

        $selectedValue = '';
        if (!empty($parameterArray['itemFormElValue'])) {
            $selectedValue = (string)$parameterArray['itemFormElValue'][0];
        }

        $fieldValueLabel = '';
        foreach ($parameterArray['fieldConf']['config']['items'] as $item) {
            if ($item[1] === $selectedValue) {
                $fieldValueLabel = $item[0];
                break;
            }
        }

        $resultArray['html'] = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($selectedValue) . '" />';

        $resultArray['html'] .= '<div>' . $this->appendValueToLabelInDebugMode($fieldValueLabel, $selectedValue) . '</div>';

        return $resultArray;
    }
}

This renders a plain text output of the selected type value.
Feel free to fancy this up as a readonly <select> with a single and default <option>.

Registration goes into ext_localconf.php:

    /**
     * FormEngine custom renderTypes
     */
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1543778876] = [
        'nodeName' => 'selectPassthrough',
        'priority' => 30,
        'class' => \Acme\MyExtension\System\Form\Element\SelectPassthroughElement::class,
    ];
Actions #9

Updated by Johannes Rebhan over 3 years ago

The problem with rendering the field as disabled is that if you use a field with a default value in a FlexForm, it is not saved into the FlexForm data, thanks to the disabled state in the rendering. This should be readonly, not disabled. If it's "disabled", the setting should be named "disabled". It's misleading and limits the usefullness of Flexforms.

Actions #10

Updated by Bastian Stargazer almost 3 years ago

  • TYPO3 Version changed from 9 to 10
  • PHP Version changed from 7.2 to 7.4

We run into this issue as well! The use-case is

- A custom record child-record has some settings, e.g. a true/false switch and a single-select
- Depending on the parent-record type, some of these settings have to be forced/fixed into a certain state (e.g. false for the switch), which usually works with overrideChildTca.
- The editor is now allowed to change these settings for the certain type, so we tried to set readOnly=TRUE.
- Unfortunately like describe above, the rendering works great, but when we save the record, these record fields falling back to their default values.

The only solution so far is to tell the editors not to change these settings!

TYPO3 v10.4.17
PHP v7.4

Actions

Also available in: Atom PDF