Makina Blog
Drupal 8 : Dynamiser vos contenus à l'aide des formulaires AJAX
Utiliser les AjaxCommands de l'API de Drupal 8 pour agir sur le Markup
On voit souvent des articles et tutoriels sur la Form API et l'AJAX API de Drupal 8 pour agir sur le formulaire en lui-même (validation à la volé [en], ajout conditionnel de champs [en]…). Il est plus rare de trouver des ressources sur les AjaxCommands
de l'API Drupal pour modifier le Markup d'un élément lambda. C'est l'objet de cet article.
L'exemple que nous allons prendre n'a pas vraiment d'intérêt dans la vraie vie, mais a l'avantage de bien illustrer les possibilités de la commande `ReplaceCommand`.
Nous allons développer un module définissant une page contenant un formulaire. Ce formulaire permettra d'aller chercher le contenu d'un nœud à partir de son ID et de l'afficher.
Développement du formulaire
Dans un module Custom, on crée un nouveau formulaire Drupal en instanciant une classe étendant la classe FormBase
dans le fichier src/Form/MonFormulaire.php
On pourra s'aider dans la console Drupal 8 pour générer le module et le formulaire :
drupal generate:module
drupal generate:form
A la différence d'un formulaire classique, dans la fonction buildForm
, on remplace l'élément de type submit
par un élément de type button
. Cela a pour effet d'éviter de passer par la fonction submitForm
au moment où l'on cliquera sur le bouton, tout en conservant le passage par la fonction validateForm
.
Sur cet élément de type button
, on rajoute un attribut '#ajax'
contenant le nom du callback à appeler (ici '::loadNode'
).
On déclare ensuite notre fonction de callback loadNode
.
<?php
namespace Drupal\monmodule\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\ChangedCommand;
use Drupal\node\Entity\Node;
/**
* Class MonFormulaire.
*/
class MonFormulaire extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'mon_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['node_id'] = [
'#type' => 'number',
'#title' => $this->t('Node Id'),
];
$form['submit'] = [
'#type' => 'button',
'#value' => $this->t('Submit'),
'#ajax' => [
'callback' => '::loadNode',
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// On a rien de plus à faire ici.
}
/**
* Notre callback.
*/
public function loadNode(array &$form, FormStateInterface $form_state) {
// On récupère le RenderArray du noeud demandé par l'utilisateur.
$node_id = $form_state->getValue('node_id');
$node = Node::load($node_id);
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
$render_array = $view_builder->view($node, 'full');
// On rajoute un élément div autour du RenderArray de manière à pouvoir le recibler
// si la callback est appelée à nouveau.
$render_array['#prefix'] = '<div id="div-cible">';
$render_array['#suffix'] = '</div>';
// On crée notre AjaxResponse.
$response = new AjaxResponse();
// Puis on ajoute une ReplaceCommand à notre AjaxResponse.
// Le premier argument du constructeur d'une ReplaceCommand est le sélecteur CSS de
// l'élément à remplacer, le second est le RenderArray que l'on souhaite retourner.
$response->addCommand(new ReplaceCommand('#div-cible', $render_array));
// Pour l'accessibilité de notre site, on ajoute une ChangedCommand pour notifier
// les lecteurs d'écran d'un changement sur la page.
response->addCommand(new ChangedCommand('#div-cible'));
return $response;
}
}
Définition de notre page personnalisée
On crée maintenant une page personnalisée dans laquelle on affichera notre formulaire.
On commence par définir sa route dans monmodule.routing.yml
monmodule.ma_page:
path: 'ma-page'
defaults:
_controller: '\Drupal\monmodule\Controller\MaPageController::maPage'
_title: 'Ma Page'
requirements:
_permission: 'access content'
Le Controller associé dans src/Controller/MaPageController.php
:
<?php
namespace Drupal\monmodule\Controller;
use Drupal\Core\Controller\ControllerBase;
class MaPageController extends ControllerBase {
/**
* Display MaPage.
*
* @return array
*/
public function maPage() {
// Building type project selection form.
$monFormulaire = \Drupal::formBuilder()->getForm('Drupal\monmodule\Form\MonFormulaire');
return [
'#title' => \Drupal::config('system.site')->get('name'),
'#theme' => 'ma_page',
'#mon_formumlaire' => $monFormulaire,
];
}
}
On déclare le thème dans un hook_theme
dans monmodule.module
:
<?php
/**
* Implements hook_theme().
*/
function monmodule_theme() {
return [
'ma_page' => [
'variables' => [
'mon_formumlaire' => NULL,
],
],
];
}
Et le template dans templates/ma-page.html.twig
:
<h1>Ma Page</h1>
{{ mon_formulaire }}
<div id="div-cible">
{# C'est ce div qui sera remplacé par notre AjaxCommand #}
</div>
Et voilà !
Maintenant, n'oubliez pas d'installer votre module, de vider le cache de Drupal et allez visiter notre nouvelle page.
Rentrez l'ID d'un nœud que vous avez déjà contribué et validez le formulaire, vous devriez voir apparaître votre contenu sous le formulaire.
Note: Pour simplifier je n'ai pas mentionné l'étape de validation du formulaire. Dans notre exemple, il faudrait bien sûr vérifier qu'il existe bien un nœud correspondant à l'ID rentré par l'utilisateur dans la fonction validateForm
.
Pour aller plus loin
Ici, nous nous sommes contentés de remplacer un élément div
. Mais il est bien sûr possible d'ajouter autant de commandes que l'on souhaite à l'objet AjaxResponse
.
On peut alors imaginer remplacer d'autre éléments du DOM en ajoutant d'autres ReplaceCommand
. On peut également effectuer d'autres actions en utilisant d'autres types d'AjaxCommand
comme :
SettingsCommand
pour envoyer des DrupalSettings au JavascriptAddCssCommand
pour ajouter du style- Et bien d'autres à découvrir dans la documentation de l'API AJAX de Drupal 8
Maintenant à vous de jouer !
Vous rencontrez des problèmes ? Vous souhaitez approfondir le sujet ?
Demandez-nous des informations sur notre formation Drupal 9 développeur !
Formations associées
Actualités en lien
Migration d'un site Drupal 7 en Drupal 11
Trucs, astuces et "bouts" de code pour migrer votre site web de Drupal 7 à Drupal 11. Compte-rendu d'une conférence donnée au Drupalcamp Rennes 2024.
Makina Corpus, partenaire du DrupalCamp 2024
Nous sommes fiers d’annoncer que Makina Corpus est le sponsor du DrupalCamp à Rennes. Notre expert vous y propose une conférence « migrer de Drupal 7 à Drupal 10 ».