1

I have used 'use-ajax' class to render login form in a modal. I want to handle validation errors on same modal without closing it. On successful login it is redirecting correctly, but when an error occurs it closes modal and redirecting to login page i.e user/login and displaying errors on that page. I tried to use ajax callback to display error on modal itself by altering the form which is working. But, it is giving me drupal ajax error. Here is my code :

$form['#prefix'] = '<div id="modal-form">';
$form['#suffix'] = '</div>';
$form['status_messages'] = [ 
    '#type' => 'status_messages',
    '#weight' => -10,
];
//$form['actions']['submit']['#limit_validation_errors'] = array();
$form['actions']['submit']['#ajax'] = array(
    'callback' => 'setMessage',
    'wrapper' => 'modal-form',
);

function setMessage(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {

    $response = new AjaxResponse();

    if ($form_state->hasAnyErrors()) {
        $response->addCommand(new ReplaceCommand('#modal-form', $form));
    }
    else {
        $command = new CloseModalDialogCommand('#modal-form', FALSE);
        $response->addCommand($command);
    }
    return $response;

}

The above code giving me session id also but due to drupal ajax error it does not redirect on success by closing modal.

1
  • If I go with non-ajax ie. if I remove the ajax callback function it works on success but errors are not displaying on modal. Apr 29, 2019 at 14:32

2 Answers 2

0

I have resolved it by commenting redirection code from hook_login and added redirection code related changes in ajax callback function itself. Here is my code.

function setMessage(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {

     $response = new AjaxResponse();
     $current= \Drupal::currentUser();
     if ($form_state->hasAnyErrors()) {
         $response->addCommand(new ReplaceCommand('#modal-form', $form));

     }
     else if (!$current->id()) {
         $response->addCommand(new ReplaceCommand('#modal-form', $form));
     }
     else {
         $command = new RedirectCommand(' ');

         return $response->addCommand($command);
     }
     return $response;
}
0

Here is snippet code to display the error message in popup: (Core: Login form)

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\RedirectCommand;


function login_popup_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'user_login_form') {
    // Check if the current request is for an Ajax modal/dialog.
    if (login_popup_is_dialog() == TRUE) {
      // Add a wrapper around the form so that we can replace it.
      $form['#prefix'] = '<div id="modal_user_login_form">';
      $form['#suffix'] = '</div>';
      // The status messages that will contain any form errors.
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#weight' => -10,
      ];
      // Add form validation to the submit btn & make it Ajax.
      $form['actions']['submit']['#validate'] = $form['#validate'];
      $form['actions']['submit']['#attributes']['class'][] = 'use-ajax';
      $form['actions']['submit']['#ajax'] = [
        'callback' => 'login_popup_submit_modal_form_ajax',
        'event' => 'click',
      ];
    }
  }
}

/**
 * AJAX callback that displays the form errors or redirects to page.
 */
function login_popup_submit_modal_form_ajax(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  // If there are any form errors, re-display the form.
  if ($form_state->hasAnyErrors()) {
    $response->addCommand(new ReplaceCommand('#modal_user_login_form', $form));
  }
  else {
    // On successfully form submission close dialog & redirect to the user page.
    $response->addCommand(new CloseModalDialogCommand());
    $uid = \Drupal::currentUser()->id();
    $redircet_path = Url::fromRoute('entity.user.canonical', ['user' => $uid])->toString();
    $response->addCommand(new RedirectCommand($redircet_path));
  }

  return $response;
}


* Is the current request for an Ajax modal/dialog.
 *
 * @return bool
 *   TRUE if the current request is for an Ajax modal/dialog.
 */
function login_popup_is_dialog() {
  $wrapper_format = \Drupal::request()->query
    ->get(MainContentViewSubscriber::WRAPPER_FORMAT);
  return (in_array($wrapper_format, [
    'drupal_ajax',
    'drupal_modal',
    'drupal_dialog',
    'drupal_dialog.off_canvas',
  ])) ? TRUE : FALSE;
}

Note:

#1 This below code is required so that the core(login) form validation fire in popup,otherwise inbuilt validation of core(login) form will not fire/display in popup.

$form['actions']['submit']['#validate'] = $form['#validate'];

Explanation: Any core/contrib(inbuilt) form that we want to just display in popup, but face problem that validation error not display in popup:

To reuse form validation instead of writing duplicate code, solution behind this problem:

Get the validation definition of core/contrib(login) form in hook_form_alter > set the validation definition in the "#validate" variable in submit handler of popup form.

#2 login_popup is module name, can update "login_popup" as per your module name.

#3 login_popup_is_dialog : Custom function used to determine whether form is open in modal or not, if form is not opened is modal then is no point to add this code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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