How to create dependent fields in Paragraph Entity using hooks in Drupal 9 & 10

24 / Dec / 2023 by shubham.joshi 0 comments

Introduction

When working with complex forms, you often have fields whose state depends on the input values of other fields in the form. For example, you might have a select list of options, the options for which depend upon the value selected for another field.

In this blog, I present one case study of my Drupal project where I had to achieve dependent fields in Paragraph Entity. So, in Paragraph Entity, the fields must use the widget “Select list.” On selecting options from the select list, we have to show or hide the other corresponding fields in the same Paragraph Entity.

Problem Statement

We already have the Dependent Field module, which is a contributed module and provides dependent field functionality. But this module doesn’t provide support with Paragraph entities. So, we use hooks to solve the problem.

Initial Requirements

We have to install the Paragraph module, which is a contributed module that helps us provide new ways of content creation. It allows you to make things cleaner so that you can give more editing power to your end users.

For this example, we have created a paragraph entity name – a gallery that contains 3 fields. The first field will be a select list with two options- image and document. Other fields will be image and file fields. We integrate the gallery paragraph in the Basic Page content type for representing the demo. Below are the screenshots for the paragraph and content type.

Screen 1 – Paragraph Entity with fields.

Screen 2 – We’ve created an entity reference field to link paragraphs in the Basic Page content type for the demo.

Screen 3 – When we go to add a basic page, it will look like the one below.

Now, we have to create a dependent field while selecting the option from the select list.

In Drupal 9, we use hook_field_widget_WIDGET_TYPE_form_alter in our custom module.

Below is a reference code from a custom module.

/**
* @file
* Dependent fields module.
*/


use Drupal\Core\Form\FormStateInterface;


/**
* Implements hook_field_widget_WIDGET_TYPE_form_alter().
*/
function demo_module_field_widget_paragraphs_form_alter(&$element, FormStateInterface $form_state, $context) {
 /** @var \Drupal\field\Entity\FieldConfig $fieldDefinition */
 $fieldDefinition = $context['items']->getFieldDefinition();
 $paragraphEntityReferenceFieldName = $fieldDefinition->getName();


 if ($paragraphEntityReferenceFieldName == 'field_attach_gallery') {
   /** @see \Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget::formElement() */
   $widgetState = \Drupal\Core\Field\WidgetBase::getWidgetState($element['#field_parents'], $paragraphEntityReferenceFieldName, $form_state);


   /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
   $paragraphInstance = $widgetState['paragraphs'][$element['#delta']]['entity'];
   $paragraphType = $paragraphInstance->bundle();


   // Determine which paragraph type is being embedded.
   if ($paragraphType == 'gallery') {
     $dependeeFieldName = 'field_choose_type';
     $selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraphEntityReferenceFieldName, $element['#delta'], $dependeeFieldName);
    // Dependent fields.
     $element['subform']['field_document']['#states'] = [
       'visible' => [
         $selector => ['value' => 'file'],
      ],
     ];
     $element['subform']['field_image']['#states'] = [
       'visible' => [
         $selector => ['value' => 'image'],
       ],
     ];
   }
 }
}

In Drupal 10, we use hook_field_widget_single_element_paragraphs_form_alter in our custom module.

Below is a reference code from a custom module.

/**
* Implements hook_field_widget_single_element_paragraphs_form_alter().
*/
function demo_module_field_widget_single_element_paragraphs_form_alter(&$element, FormStateInterface $form_state, $context) {
 /** @var \Drupal\field\Entity\FieldConfig $fieldDefinition */
 $fieldDefinition = $context['items']->getFieldDefinition();
 $paragraphEntityReferenceFieldName = $fieldDefinition->getName();


 if ($paragraphEntityReferenceFieldName == 'field_attach_gallery') {
   /** @see \Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget::formElement() */
   $widgetState = \Drupal\Core\Field\WidgetBase::getWidgetState($element['#field_parents'], $paragraphEntityReferenceFieldName, $form_state);


   /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
   $paragraphInstance = $widgetState['paragraphs'][$element['#delta']]['entity'];
   $paragraphType = $paragraphInstance->bundle();


   // Determine which paragraph type is being embedded.
   if ($paragraphType == 'gallery') {
     $dependeeFieldName = 'field_choose_type';
     $selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraphEntityReferenceFieldName, $element['#delta'], $dependeeFieldName);
    // Dependent fields.
     $element['subform']['field_image']['#states'] = [
       'visible' => [
         $selector => ['value' => 'image'],
      ],
     ];
     $element['subform']['field_document']['#states'] = [
       'visible' => [
         $selector => ['value' => 'file'],
       ],
     ];
   }
 }
}

After the implementation of the above hooks in respective versions, we can achieve depend on fields functionality so when you select an image from the select list, then the image field display and file field will be hidden, and if you select the file option from the select list then document field will display an image field will be hidden.

Conclusion

Drupal provides the best way by using hooks to make a few modifications to existing functionality. With the help of a few configurations, we can achieve complex forms and field dependency states with other field values quickly. Here, we provide hooks for Drupal 9 & Drupal 10 only. Maybe in Drupal 11 or later, hook changes.

Let us know if you have any queries, and please feel free to reach out via comments.

 

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *