Score:0

How to set widget for a field on a custom form?

us flag

How do I set the widget to be used for a field on a custom form?

I am surprised I haven't been able to find something covering this. Sort of expected it to be something like:

$form['interest'] = [
  '#type' => 'checkbox',
  '#title' => t('Are you interested?'),
  '#widget' => 'my_custom_boolean_widget',
]

But nothing in the FormAPI regarding anything to do with widgets.

Score:2
id flag

The form API is the most basic way to define custom forms in Drupal. It is using form elements to show HTML controls for form fields.

(Field) Widgets on the other hand are part of the entity fields API:

Field API widgets specify how fields are displayed in edit forms. [...] Widgets are Form API elements with additional processing capabilities.

They control how the form elements of fields attached to entities are rendered and how data provided by the user is written back to the respective fields. Remember, entity fields might have a cardinality. So Widgets must be able to not only provide a simple checkbox, but also form elements for multiple boolean values on the same entity field. They are basically another abstraction layer on top of the form API, and thus not known to the form API itself, which you'd use to create your custom forms.

To use the very same HTML controls in an entity field widget and for the value of a plain form API form field, you'd first have to create an according custom form element (which then could be included in your form via the #type property), and use this element in a custom field widget as well. This is how you'd do it for very complex elements like file upload elements with drag'n'drop functionality and so on.

More often, using the generic form API controls and adding CSS classes (#attributes), custom process (#process) or pre-render functions (#pre_render) in conjunction with a bit custom CSS and/or JavaScript is sufficient to achieve similar UI behavior between field widgets and their custom form element counterparts. You might even be able to re-use JavaScript or CSS provided by a library attached to a widget when adding the very same CSS classes to the form element and attaching the widget library to your form. A look into the source code of the widget you'd love to use in your form might give you an according idea.

liquidcms avatar
us flag
Thanks for that explanation and I was getting that idea. Certainly a failing in FormAPI that this can be done through the entity UI but not more easily through the FormAPI. This link: https://www.webomelette.com/how-render-entity-field-widgets-inside-custom-form-drupal-8 provides an interesting "hack" to be able to set up a "dummy" entity and use its fields and widgets in your custom form.
Mario Steinitz avatar
id flag
@liquidcms I wouldn't call it a failure of the Form API. It does what it was designed for. And it has been doing that very well ever since Drupal 7. Field widgets are just a different concept (and use the form API as well to render their widget form element(s)). - Please be so kind to accept the answer, if you found it useful and fitting your question.
liquidcms avatar
us flag
I did accept your answer although the link i posted is a better answer as to how to accomplish what i wanted to do. I would not think that the Widget modifies the data format stored in the db. If that is the case it seems "misplaced" to be part of the Entity API and does seem to be a failing in the FormAPI to not be able to select which widget it displays.
Score:0
us flag

Although I selected Mario's answer as "correct". It is only telling me that I cannot do what I want to do. The webomelette link I posted however does provide a neat "trick" to accomplish what I need to accomplish. It allows "grabbing" fields (and their selected widget) from entity forms and using them on your custom form.

The simplified code from that post is basically this in your custom buildForm():

// Fields pulled from Widgets entity to use Field widget
$widget_fields = [array of field names I want to pull from the entity];
$extra_fields = [];
foreach ($form_display->getComponents() as $name => $component) {
  if (!in_array($name, $widget_fields)) continue;
  $widget = $form_display->getRenderer($name);
  if (!$widget) continue;
  $items = $entity->get($name);
  $items->filterEmptyItems();
  $extra_fields[$name] = $widget->form($items, $form, $form_state);
  $extra_fields[$name]['#access'] = $items->access('edit');
}

I used Console to create a custom entity (Widgets) solely for the purpose of grabbing fields/widgets for my custom forms.

I then just grab fields from $extra_fields to add to my custom form.

$form['my_field'] = $extra_fields['field_my_entity_field'];

As Marios explains, field widgets are part of the EntityAPI and therefore require entity context to associate a field with a widget. This technique uses a "fake" entity to tie EntityAPI and FormAPI together.

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.