6

I couldn't find any documentation or examples about this. The implementation is very problematic. Do you a means to do this?

Problems

While trying to create a system settings form with text_format input, I get following errors while displaying the form. The form is being submitted normally and the values are being saved but when the page refreshes the text editor is not populated with the saved values and the errors are always there.

User error: "value" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).

User error: "format" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).

The code in buildForm() is as follows:

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config('commerce_distance_terms.distanceterms');
    $form['title'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Title'),
      '#description' => $this->t('Title for the terms'),
      '#maxlength' => 64,
      '#size' => 64,
      '#default_value' => $config->get('title'),
    ];
    $form['distance_selling_terms'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Distance Selling Terms'),
      '#description' => $this->t('Enter Distance Selling terms'),
      '#default_value' => [
        'value' => $config->get('distance_selling_terms.value'),
        'format' => $config->get('distance_selling_terms.format'),
//         '#tree' => FALSE,
        '#printed' => TRUE,
      ],
    ];
    return parent::buildForm($form, $form_state);
  }

Background information

  • This is the error as it links from the code.
  • The errors are thrown because of the #default_value part of the array. Adding a #value => array() reduces the errors. But nothing changes.
  • What I got from the stacktrace is that the form is being rendered, then the textarea is being rendered, and then the source of the error is being rendered (There are small elements inbetween). So I think the source of the error is the #default_value element of the textarea which is copied and pasted from the above array part while the compound text editor is being created.
  • In one of the rendering iterations, the Element::children() thinks that it should render the value and the format elements of the above array. Since they don't start with #.
  • There is a word here that system settings form doesn't support text_area input from Drupal 7. Also that and some linked issues tell that there are some automatic defaults for system_settings_form but I couldn't find the equal.
  • The text_format input is a compound element that includes a textarea (to hold and populate the actual value), a dropdown format element to select from, etc. The textarea element comes with the exact #default_value that I put above (as an array). I tried to preprocess this textarea and change that value to the related string to populate the field but whatever I do textarea comes always empty.
  • The #printed and #tree elements of the array don't change anything. I also put them inside the textarea array in the preprocess function but nothing changed.
  • The textarea's data-editor-value-original property comes with the above array flattened even tough I change the #default_value and #value in the preprocess.
  • The text editor not being able to be populated may not be related to above errors. I know nothing.

5 Answers 5

11
+50
$form['distance_selling_terms'] = [
  '#type' => 'text_format',
  '#title' => $this->t('Distance Selling Terms'),
  '#description' => $this->t('Enter Distance Selling terms'),
  '#default_value' => config->get('distance_selling_terms.value'),
  '#format' => $config->get('distance_selling_terms.format'),
];

And if you want to limit the wysiwyg editor to only the one format, add #allowed_formats as in:

$form['distance_selling_terms'] = [
  '#type' => 'text_format',
  '#title' => $this->t('Distance Selling Terms'),
  '#description' => $this->t('Enter Distance Selling terms'),
  '#default_value' => config->get('distance_selling_terms.value'),
  '#format' => $config->get('distance_selling_terms.format'),
  '#allowed_formats' => [
    $config->get('distance_selling_terms.format') => 'Description of format'
  ],
];
2

In order to make your configuration translatable when it uses a text_format you need to have the following mapping:

your_custom_form_field:
  type: mapping
  label: 'Free text with text format support'
  translatable: true
  mapping:
    value:
      type: text
      label: 'Custom Text'
    format:
      type: string
      label: 'Text format'

Have a look at this core patch and thread:
https://www.drupal.org/files/issues/2144413-185-config-translation-text-format.patch
https://www.drupal.org/node/2144413
for a more detailed example and discussion.

1

In your builForm() method, your text_format form/render element usage is wrong.

You can see the text format render element properties and usage on drupal.org: Text format render element

So you can use like this:

/**
 * Provides a text format render element.
 *
 * Properties:
 * - #base_type: The form element #type to use for the 'value' element.
 *   'textarea' by default.
 * - #format: (optional) The text format ID to preselect. If omitted, the
 *   default format for the current user will be used.
 * - #allowed_formats: (optional) An array of text format IDs that are available
 *   for this element. If omitted, all text formats that the current user has
 *   access to will be allowed.
 *
 * Usage Example:
 * @code
 * $form['body'] = array(
 *   '#type' => 'text_format',
 *   '#title' => 'Body',
 *   '#format' => 'full_html',
 *   '#default_value' => '<p>The quick brown fox jumped over the lazy dog.</p>',
 * );
 * @endcode
 */

In your case your code should be modified to this:

 $form['distance_selling_terms'] = [
   '#type' => 'text_format',
   '#title' => $this->t('Distance Selling Terms'),
   '#description' => $this->t('Enter Distance Selling terms'),
   '#format' => $config->get('distance_selling_terms.format'),
   '#default_value' => $config->get('distance_selling_terms.value'),
 ];

In the submitForm() method you should update the configuration:

/**
 * {@inheritdoc}
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
  // This parent class's submitForm method only shows
  // "The configuration options have been saved." message
  parent::submitForm($form, $form_state);

  // You can get all submitted values in array format with $form_state->getValues()
  $values = $form_state->getValues();

  // Update the configuration
  $this->config('commerce_distance_terms.distanceterms')
    // Set the title to the configuration
    ->set('title', $values['title'])
    // Set the value of the textarea to the configuration
    ->set('distance_selling_terms.value', $values['distance_selling_terms']['value'])
    // Set the format of the textarea to the configuration
    ->set('distance_selling_terms.format', $values['distance_selling_terms']['format'])
    // Save the configuration
    ->save();
}
1

Also, the the mapping section for the module's schema file, the field should be something like:

YOUR_MODULE.settings
  type: mapping
  label: Settings or whatever
  mapping:
    distance_selling_terms.value:
      type: text
    distance_selling_terms.format:
      type: string

Similarly, your settings.yml file will look something like:

 distance_selling_terms:
     value: "whatever"
     format: basic_html
1

I was facing on this problem recently, thanks to @bserem for have to shared : https://www.drupal.org/files/issues/2144413-185-config-translation-text-format.patch cuz I found the answer in this patch. So I used this on my mymodule.schema.yml

block.settings.myblock:
  type: block_settings
  label: 'Myblock configuration'
  translatable: true
  mapping:
    text:
      type: text_format
      label: 'Text'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.