Bug #32412

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 about 7 years ago. Updated 11 days ago.

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

0%

TYPO3 Version:
9
PHP Version:
7.2
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

Related to TYPO3 Core - Bug #23975: TCAtree config option readOnly = 1 has no effect Closed 2010-11-07
Related to TYPO3 Core - Bug #56060: TCA type inline readOnly New 2014-02-17

History

#1 Updated by Christian Weiske about 7 years ago

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

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

#2 Updated by Markus Klein about 7 years ago

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

#3 Updated by Christian Weiske about 7 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.

#4 Updated by Mathias Schreiber about 4 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

#5 Updated by Christian Kuhn over 1 year 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.

#6 Updated by Leonie Philine Bitto 11 days 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!

#7 Updated by Leonie Philine Bitto 11 days 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').)

#8 Updated by Leonie Philine Bitto 11 days 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,
    ];

Also available in: Atom PDF