5

I have created a field field_time_zone in a content type = article.

I want to set allowed values of list field, i.e. options of select list should be $zones = system_time_zones();

For this, I have written a hook_form_alter:

$zones = system_time_zones();
$entityManager = \Drupal::service('entity_field.manager');
$fields = $entityManager->getFieldStorageDefinitions('node', 'local_market');
$options = options_allowed_values($fields['field_time_zone']);

if(empty($options)) {
$options =  $zones;
$form['field_time_zone']['widget']['#options'] = $options;
}

Above function successfully added time zones to my select list field but when I save this node, it won't allow the node to get saved.

It throws error;

The value you selected is not a valid choice.

How can I set allowed value options to a field of type text(list) and save it accordingly?

12

You can't do this in a form alter hook, because the entity field validation will fail.

You have to add a function to the field settings. This is not in the field UI, so you have to export the configuration and change the field in field.storage.node.field_time_zone.yml:

type: list_string
settings:
  allowed_values: {  }
  allowed_values_function: 'mymodule_allowed_values_function'

Reimport the configuration. Then you can implement this function in mymodule.module to set the options dynamically:

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\field\Entity\FieldStorageConfig;

  function mymodule_allowed_values_function(FieldStorageConfig $definition, ContentEntityInterface $entity = NULL, $cacheable) {
    $options = [
      ...
    ];
    return $options;
  }

See https://chromatichq.com/blog/dynamic-default-and-allowed-values-list-fields-drupal-8


For the question added later:

How can I set allowed value options to a field of type text(list) and save it accordingly?

The question originally was what to do with the code which doesn't work in form alter, where you can place it instead.

If you mean with this question you have a static allowed value list, then you can copy and paste the list in the field settings UI and save it:

enter image description here

And now it is stored in the mentioned yaml file of the exported configuration here:

  allowed_values: {  }
  • 1
    Note you would not even a callback if you just exported all allowed values. You only need the allowed_values_function callback if you need a dynamically computed list of allowed values. – Wim Leers Aug 9 '17 at 17:44
  • @WimLeers, yes, this is right. But this is not what my answer is about. The OP wanted to change the option list in a form alter hook. This is OK for normal forms, but doesn't work for entity forms. In this case you have to move the dynamic code to another place, see my answer or if it is static, put it in configuration, see your comment. Thank you for pointing this out. – 4k4 Aug 9 '17 at 20:24
1

After many hours i finally found solution. I dynamically created options for multi select field and got error message on submit that choosen select in wrong option.

It requires add new options to allowed_values for that field. Here is the solution:

 //load your field
 $field_purchasers = FieldStorageConfig::loadByName('user', 'field_xx');
 //subscribe new options to this field
$field_purchasers->setSetting('allowed_values_function','module_name_allowed_values_function' );
//save configuration
$field_purchasers->save();

In your .module file write in callback function :

function module_name_allowed_values_function(FieldStorageConfig $definition, ContentEntityInterface $entity = NULL, $cacheable) {
  $options = [
    1 => 'My new option 1',
    2 => 'My new option 2',
    3 => 'My new option 3',
   ];
  return $options;
}
  • That first part, why do like that, I think just modify the yml file with the function and re-import the config. – klidifia Jun 10 at 1:07
-4

You should override the allowed values of the storage in your form alter:

// Retrieve the storage.
$fieldStorage = \Drupal\field\Entity\FieldStorageConfig::loadByName('node', 'local_market');

// Retrieve the current allowed field values.
$allowedValues = $fieldStorage->getSetting('allowed_values');

// Set your new allowed field values.
$allowedValues['field_time_zone'] = $zones;
$fieldStorage->setSetting('allowed_values', $allowedValues);

// Save.
$fieldStorage->save();
-4

Thanks, @Gun5m0k3. This works great. Here's a slightly adapted, more generic version.

In your form_alter:

// Define your options.
$my_options = ['foo' => 'foo', 'bar' => 'bar'];

// Add the options to the field widget.
$form['field_my_field']['widget']['#options'] = array_merge(
  $form['field_my_field']['widget']['#options'],
  $my_options
);

// Ensure that the new options are also added to the allowed_values list
$fieldStorage = \Drupal\field\Entity\FieldStorageConfig::loadByName('node', 'field_my_field');
$fieldStorage->setSetting('allowed_values', $my_options);
$fieldStorage->save();

Is there a good reason why setting fieldStorage within a form_alter is a bad idea? It seems to work perfectly, so I wonder why this isn't the go-to solution as it's the easiest and most straightforward to implement.

J.

  • 1
    The official way is to use the API of this module options.api.php (in /core/modules/options), which provides callback_allowed_values_function(). Saving a config entity involves a lot of overhead and might not be a good idea in normal page requests. That is why there is the API in the first place, to make such dynamic changes more efficient. – 4k4 Jul 28 '17 at 12:33
  • Changing config at run time is a bad practice not only for performance reasons, but also because it means your configuration is no longer reflecting reality. Which means you can't actually rely on your config anymore, and for example audits become meaningless. Plus, if you do change the allowed values in Field UI, that'd be automatically overwritten again. – Wim Leers Aug 9 '17 at 17:44
  • On top of that: if you interact with this entity via the PHP API or the REST API, and not via a form, it won't have this updated configuration. At least … not until you've used the form at least once. – Wim Leers Aug 9 '17 at 17:46
  • Finally: this is clearly a case of en.wikipedia.org/wiki/Side_effect_(computer_science), which is pretty much always going to haunt you :) – Wim Leers Aug 9 '17 at 17:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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