Sometimes we need to add validation in a nested widget form like in a hook_field_widget_WIDGET_TYPE_form_alter for example and maybe take advantage of the awesome Form API #states features that Drupal Form API provides us.
Here are 2 examples on how to use the Form API #states nested within a paragraph form and how to add validation within this paragraph's widget form.
Note that if you are using the "Paragraphs EXPERIMENTAL" widget instead of "Paragraphs Classic", then the widget type is just paragraphs instead of entity_reference_paragraphs or if you are using paragraphs browser like I do here in the example the widget type is paragraphs_browser instead of paragraphs.
/**
* Implements hook_field_widget_WIDGET_TYPE_form_alter().
*/
function pixelthis_field_widget_paragraphs_browser_form_alter(&$element, &$form_state, $context) {
/** @var \Drupal\field\Entity\FieldConfig $field_definition */
$field_definition = $context['items']->getFieldDefinition();
$paragraph_entity_reference_field_name = $field_definition->getName();
if ($element['#paragraph_type'] == 'latest_posts') {
$dependee_field_name = 'field_display_type';
$selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraph_entity_reference_field_name, $element['#delta'], $dependee_field_name);
// Dependent fields.
$element['subform']['field_post']['#states'] = [
'visible' => [
$selector => ['value' => 'node_list'],
],
];
$element['subform']['field_category']['#states'] = [
'required' => [
$selector => ['value' => 'node_category'],
],
'visible' => [
$selector => ['value' => 'node_category'],
],
];
$element['subform']['field_total']['#states'] = [
'visible' => [
$selector => ['value' => 'node_category'],
],
];
$element['subform']['field_category']['widget']['#element_validate'][]
= '_pixelthis_custom_validation';
}
}
/*
* Check if the field category is empty when the display_type === _category.
*/
function _pixelthis_custom_validation($element, $form_state) {
$page_components = $form_state->getValue('field_page_components');
if (isset($page_components[0]['subform']['field_category']) &&
isset($page_components[0]['subform']['field_display_type']) &&
$page_components[0]['subform']['field_display_type'] === '_category' &&
empty($page_components[0]['subform']['field_category'])) {
$form_state->setErrorByName('field_page_components][0][subform][field_category', t('Please select a category'));
}
}