web-dev-qa-db-fra.com

Comment faire une redirection matérielle sous forme ajaxifiée?

J'ai un formulaire en plusieurs étapes ajax et je souhaite rediriger l'utilisateur vers un itinéraire spécifique lorsque certaines conditions sont remplies (en particulier si l'utilisateur est inactif pendant plus de N secondes et que le formulaire est soumis après cette limite).

Je voulais faire la redirection dans le gestionnaire de validation mais pas de chance. J'ai donc essayé de soumettre le gestionnaire, mais toujours pas de chance. Je suis assez bouleversé.

J'ai essayé de renvoyer la redirection de redirection, j'ai essayé de définir la réponse de redirection sur l'état du formulaire, j'ai essayé de définir la redirection sur l'état du formulaire, j'ai essayé de désactiver l'état de formulaire reconstruit, j'ai essayé de copier la logique d'action goto et d'utiliser le répartiteur d'événements , J'ai essayé de désinstaller la\Drupal\Core\Form\FormBuilderInterface :: AJAX_FORM_REQUEST de la demande mais toujours pas de chance.

Je pourrais peut-être retourner la redirection dans le rappel ajax en tant que commande de redirection, mais je veux que cela fonctionne avec js désactivé, donc invoquer window.location ne serait pas suffisant.

5
user21641

Après assez quelques expérimentations, je suis arrivé à cette solution de travail.

La condition doit être au début du gestionnaire de soumission:

  if ($condition) {
    $form_state->setRedirect('foo.bar')->disableRedirect(FALSE)->setRebuild(FALSE);
    // Return here so the code that activates form rebuilding for ajax or any data processing logic is not invoked.
    return;
  }

Et le rappel ajax doit être formaté comme ceci:

public static function ajaxRebuildForm(array $form, FormStateInterface $form_state) {
    /** @var \Drupal\Core\Form\FormSubmitterInterface $submitted */
    $submitter = \Drupal::service('form_submitter');
    /** @var \Symfony\Component\HttpFoundation\RedirectResponse $redirect */
    $redirect = $submitter->redirectForm($form_state);
    if ($redirect) {
      return (new AjaxResponse())->addCommand(new RedirectCommand($redirect->getTargetUrl()));
    }

    return $form;
  }

Cela fonctionne pour les environnements js-enabled et js-disabled. Si JS est activé, le rappel ajax détectera la redirection définie et renverra la réponse ajax avec la commande de redirection au lieu du tableau de rendu (qui est également transformé en interne en réponse ajax). Si js est désactivé, la redirection est traitée comme une réponse de redirection lorsque le formulaire est soumis.


Edit: J'ai trouvé que ce n'est pas une solution 100% fonctionnelle. J'ai un contrôleur d'itinéraire qui renvoie le formulaire ou la redirection perofrms. Une fois que je suis dans le formulaire ajaxifié et que le contrôleur fait la redirection (c'est-à-dire que certaines conditions n'étaient pas remplies), je suis bloqué sur le formulaire et je ne peux rien faire car le rappel ajax n'est pas déclenché, donc je fais essentiellement des demandes de page qui renvoie des redirections et aucune logique de formulaire n'est plus invoquée. Ce qui signifie que je dois implémenter une logique supplémentaire, encore une fois, dans le contrôleur, pas seulement dans le formulaire, car l'API de formulaire a gagné 'a une chance d'être invoquée et de traiter le formulaire en premier lieu.

J'ai dû implémenter cela dans mon contrôleur:

  if ($request->request->get(AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER)) {
    return (new AjaxResponse())
      ->addCommand(
        new RedirectCommand(
          $this->redirect(
            $this->currentRouteMatch->getRouteName()
          )->getTargetUrl()
        )
      );
  }
4
user21641

Dans mon cas (D8), je devais juste implémenter le RedirectCommand dans mon AjaxSubmit:

Code du bouton d'envoi:

$form['submit_' . $this->uniqueIdentifier] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#attributes' => [
    'class' => ['btn', 'btn-primary']
  ],
  '#ajax' => [
    'callback' => [$this, 'submitModalFormAjax'],
    'event' => 'click',
  ],
];

Code du rappel de soumission:

public function submitModalFormAjax(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();

  if ($form_state->hasAnyErrors()) {
    // Do validation stuff here
    // ex: $response->addCommand(new ReplaceCommand... on error fields
  }

  else {
    // Do submit stuff here

    $url = Url::fromRoute('page_route');
    $command = new RedirectCommand($url->toString());
    $response->addCommand($command);
  }

  return $response;
}

N'oubliez pas de déclarer:

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Url;
5
romain ni