logo

Types de blocs supplémentaires (EBT) – Nouvelle expérience de Layout Builder❗

Types de blocs supplémentaires (EBT) – types de blocs stylisés et personnalisables : diaporamas, onglets, cartes, accordéons et bien d’autres. Paramètres intégrés pour l’arrière-plan, la boîte DOM, les plugins JavaScript. Découvrez dès aujourd’hui le futur de la création de mises en page.

Démo des modules EBT Télécharger les modules EBT

❗Types de paragraphes supplémentaires (EPT) – Nouvelle expérience Paragraphes

Types de paragraphes supplémentaires (EPT) – ensemble de modules basé sur les paragraphes analogiques.

Démo des modules EPT Télécharger les modules EPT

Défilement
07/07/2025, by Ivan

Menu

Dans cet article, nous allons continuer à comprendre le Form API dans Drupal 8 et créer un formulaire multi-étapes. Nous avons déjà créé un formulaire de configuration classique pour le module, le formulaire multi-étapes est créé de manière similaire en utilisant $form_state pour stocker les données entre les étapes du formulaire.

Des exemples de code sont disponibles sur GitHub :

https://github.com/levmyshkin/drupalbook8

Pour un formulaire multi-étapes, vous devez ajouter une classe de formulaire :

/modules/custom/drupalbook/src/Form/MultiStepForm.php

<?php

/**
 * @file
 * Contient Drupal\drupalbook\Form\MultiStepForm.
 */

namespace Drupal\drupalbook\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class MultiStepForm extends FormBase
{

  protected $step = 1;

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames()
  {
  }

  /**
   * {@inheritdoc}
   */
  public function getFormID()
  {
    return 'multi_step_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state)
  {
    //$form = parent::buildForm($form, $form_state);

    // Ajout d'un div wrapper pour que le Form API puisse mettre à jour le formulaire en AJAX
    $form['#prefix'] = '<div id="ajax_form_multistep_form">';
    $form['#suffix'] = '</div>';

    if ($this->step == 1) {
      $form['message-step'] = [
        '#markup' => '<div class="step">' . $this->t('Étape 1 sur 2') . '</div>',
      ];
      $form['message-title'] = [
        '#markup' => '<h2>' . $this->t('Qui êtes-vous ?') . '</h2>',
      ];
      $form['first_name'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Prénom'),
        '#placeholder' => $this->t('Prénom'),
        '#required' => TRUE,
      ];
      $form['last_name'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Nom'),
        '#placeholder' => $this->t('Nom'),
        '#required' => TRUE,
      ];
    }

    if ($this->step == 2) {
      $form['message-step'] = [
        '#markup' => '<div class="step">' . $this->t('Étape 2 sur 2') . '</div>',
      ];
      $form['message-title'] = [
        '#markup' => '<h2>' . $this->t('Merci d’entrer vos coordonnées ci-dessous :') . '</h2>',
      ];
      $form['phone'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Téléphone'),
        '#placeholder' => $this->t('Téléphone'),
        '#required' => TRUE,
      ];
      $form['email'] = [
        '#type' => 'email',
        '#title' => $this->t('Adresse e-mail'),
        '#placeholder' => $this->t('Adresse e-mail'),
        '#attributes' => ['class' => ['mail-first-step']],
        '#required' => TRUE,
      ];
      $form['subscribe'] = [
        '#type' => 'checkbox',
        '#title' => $this->t('S’abonner à la newsletter'),
      ];
      $form['agree'] = [
        '#markup' => '<p class="agree">' . $this->t('En vous inscrivant, vous acceptez les <a href="@terms">Conditions générales</a> et la <a href="@policy">Politique de confidentialité</a>',
            ['@terms' => '/terms-and-conditions', '@policy' => '/privacy-policy']) . '</p>',
      ];
    }

    if ($this->step == 3) {
      $form['message-step'] = [
        '#markup' => '<p class="complete">' . $this->t('- Terminé -') . '</p>',
      ];
      $form['message-title'] = [
        '#markup' => '<h2>' . $this->t('Merci') . '</h2>',
      ];
    }

    if ($this->step == 1) {
      $form['buttons']['forward'] = [
        '#type' => 'submit',
        '#value' => t('Suivant'),
        '#prefix' => '<div class="step1-button">',
        '#suffix' => '</div>',
        '#ajax' => [
          // Wrapper créé au début du formulaire
          'wrapper' => 'ajax_form_multistep_form',
          // Callback pour recharger le formulaire via AJAX
          'callback' => '::ajax_form_multistep_form_ajax_callback',
          'event' => 'click',
        ],
      ];
    }
    if ($this->step == 2) {
      $form['buttons']['forward'] = [
        '#type' => 'submit',
        '#value' => t('Envoyer'),
        '#ajax' => [
          'wrapper' => 'ajax_form_multistep_form',
          'callback' => '::ajax_form_multistep_form_ajax_callback',
          'event' => 'click',
        ],
      ];
    }

    $form['#attached']['library'][] = 'drupalbook/multistep_form';
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    return parent::validateForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    if ($this->step == 2) {
      $values = $form_state->getValues();
      $email = $values['email'];
      // Sauvegarder les données ou envoyer un e-mail ici.
    }

    $this->step++;
    $form_state->setRebuild();
  }

  public function ajax_form_multistep_form_ajax_callback(array &$form, FormStateInterface $form_state) {
    return $form;
  }

}

Ensuite, nous allons expliquer ce que fait chaque ligne. En attendant, créons une route pour notre formulaire :
/modules/custom/drupalbook/drupalbook.routing.yml :

drupalbook.multistep_form:
  path: '/multistep-form'
  defaults:
    _form: '\Drupal\drupalbook\Form\MultiStepForm'
    _title: 'S’abonner à la newsletter'
  requirements:
    _permission: 'access content'

Cela créera un formulaire accessible à l’adresse /multistep-form :

search

Pour que ce formulaire s’ouvre dans une fenêtre popup modale, vous devez ajouter un bloc ou simplement un texte avec une classe use-ajax spécifique et l’attribut data-dialog-type="modal", avec un lien vers la page du formulaire. Vous devrez également activer les bibliothèques suivantes : core/drupal.dialog.ajax, core/jquery.form. Si vous faites cela via un bloc, vous obtiendrez le code suivant pour le bouton ouvrant le formulaire dans la popup : modules/custom/drupalbook/src/Plugin/Block/SubscribeFormButton.php

<?php

namespace Drupal\drupalbook\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Fournit un bouton d’inscription à la newsletter.
 *
 * @Block(
 *   id = "drupalbook_subsribe_form_button",
 *   admin_label = @Translation("S’abonner à la newsletter"),
 * )
 */
class SubscribeFormButton extends BlockBase {
  /**
   * {@inheritdoc}
   */
  public function build() {
    $text = '<a href="/multistep-form" class="use-ajax" data-dialog-type="modal">S’abonner</a>';

    return [
      '#markup' => $text,
      '#attached' => [
        'library' => [
          'core/drupal.dialog.ajax',
          'core/jquery.form',
        ],
      ],
    ];
  }

}

Le formulaire dans la popup ressemblera à ceci :

newsletter

J’ai aussi connecté une bibliothèque personnalisée depuis le fichier drupalbook.libraries.yml :

modules/custom/drupalbook/drupalbook.libraries.yml

multistep_form:
  css:
    css/multistep_form.css: {}
  js:
    scripts/multistep_form.js: {}
  dependencies:
    - core/jquery
    - core/jquery.once

Il est nécessaire de styliser le formulaire et d’y connecter les plugins jQuery nécessaires. Vous devrez donc créer d’autres fichiers :

modules/custom/drupalbook/css/multistep_form.css
modules/custom/drupalbook/scripts/multistep_form.js

Des exemples de code sont disponibles sur GitHub :
https://github.com/levmyshkin/drupalbook8