Managed File conflicts with Custom Ajax Elements

Created on 10 July 2022, over 2 years ago
Updated 13 May 2024, 8 months ago

Problem/Motivation

I am working with a Custom form. Form contains following Elements :
- Select field (invokes Ajax on change and responsible to Update container with multiple text fields)
- Managed File Field
- Container with multiple Textfields

Ajax works well to add/remove "biz_wrapper" container on the basis of Selected Options. But on the final submission of the form, biz_wrapper values are missing inside the form_states. After debugging, I realise that this Ajaxify element is conflicting with Managed_file field. Code attached and steps explained below:

Steps to reproduce

Case1:

  • Select any value from ('joint_tenants', 'tenants_in_common', 'trust') for Account Type
  • Fill the newly added fields
  • Upload file to managed_file field (named as Identification)
  • Submit the form and check the formState values logger in Drupal logs
  • You can see that there are no records for biz_wrapper

Case2:

  • Select any value from ('joint_tenants', 'tenants_in_common', 'trust') for Account Type
  • Fill the newly added fields
  • Choose file to managed_file field (named as Identification), but don't upload
  • Submit the form and check the formState values logger in Drupal logs
  • You can see this time the records are there for biz_wrapper

Code Snippet:

<?php

namespace Drupal\account_updates\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Form\FormStateInterface;

class AccountSetupForm2 extends MultistepFormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'account_setup_form_2';
  }
  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['#tree'] = TRUE;
    $atypes = [
      'personal' => 'Individual',
      'joint_tenants' => 'Joint Tenants',
      'tenants_in_common' => 'Tenants in Common',
      'trust' => 'Trust/Entity'
    ];

    $form['field_account_type'] = [
      '#type' => 'select',
      '#title' => 'Account Type',
      '#options' => $atypes,
      '#empty_option' => t('- Select -'),
      '#ajax' => [
        'callback' => '::accountTypeDropdownCallback',
        'wrapper' => 'biz-wrapper',
        'event' => 'change',
      ]
    ];

    $form['biz_wrapper'] = [
      '#type' => 'container',
      '#prefix' => '<div id="biz-wrapper">',
      '#suffix' => '</div>',
    ];

    if(!empty($form_state->getValue('field_account_type') && in_array($form_state->getValue('field_account_type'), ['joint_tenants', 'tenants_in_common', 'trust']))) {
      $form['biz_wrapper']['#prefix'] = '<div id="biz-wrapper"><div class="fields-inner"><h2>Authorized person OR Principal</h2>';
      $form['biz_wrapper']['#suffix'] = '</div></div>';
      $form['biz_wrapper']['field_business_name'] = [
        '#type' => 'textfield',
        '#title' => 'Business Name',
      ];

      $form['biz_wrapper']['field_tax_id'] = [
        '#type' => 'textfield',
        '#title' => 'Tax Id'
      ];
    }

    $form['field_identification'] = [
      '#type' => 'managed_file',
      '#title' => $this->t('Identification'),
      '#multiple' => TRUE,
      '#upload_validators' => [
        'file_validate_extensions' => ['jpg png jpeg pdf doc docx'],
        'file_validate_size' => [2*1024*1024],
      ],
    ];

    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => 'Save',
    );
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    \Drupal::logger(__FUNCTION__)->info('<pre>' . print_r($values, true) . '</pre>');
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    \Drupal::logger(__FUNCTION__)->info('<pre>' . print_r($values, true) . '</pre>');
  }

  /**
   * {@inheritdoc}
   */
  public function accountTypeDropdownCallback(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand('#biz-wrapper', $form['biz_wrapper']));
    return $response;
  }
}

Thank you in Advance!!

💬 Support request
Status

Closed: outdated

Version

9.5

Component
Ajax 

Last updated 1 day ago

Created by

🇮🇳India aneehD Punjab

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇺🇸United States smustgrave

    There was no patch to review and a response was made in #4

    Moving to PNMI to see if that addressed the issue or more info can be provided

    Thanks!

  • Status changed to Closed: outdated over 1 year ago
  • Make sure that changes made to the form via AJAX are properly tracked in the form state. In Drupal, if a part of the form is added dynamically (like your biz_wrapper), its values might not be properly included in the form state unless the form structure is adequately managed across callbacks.

    //
    use Drupal\Core\Ajax\AjaxResponse;
    use Drupal\Core\Ajax\ReplaceCommand;
    public function accountTypeDropdownCallback(array &$form, FormStateInterface $form_state) {
    $form_state->setRebuild(true);
    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand('#biz-wrapper', $form['biz_wrapper']));
    return $response;
    }

Production build 0.71.5 2024