Partage
  • Partager sur Facebook
  • Partager sur Twitter

Flash message timeout avec bootstrap 5

Symfony 5 - bootstrap 5

Sujet résolu
4 octobre 2021 à 17:16:35

Bonjour,

Avec bootstrap 4.x et jquery il était assez facile de faire disparaître automatiquement un message flash de Symfony au bout de quelques secondes.

Exemple de code :

$("alert").alert();
window.setTimeout(function() {
$(".alert").alert('close'); }, 5000);


Avec bootstrap 5 si on ne veut plus utiliser jquery cela a l'air d'être bien plus compliqué ... du moins pour moi.

Par exemple ce post semble indiquer une solution

https://stackoverflow.com/questions/67031188/how-to-auto-dismiss-a-bootstrap-5-alert-without-jquery

mais si on prend le block twig indiqué dans la doc Symfony 5 (idem Symfony 4 d'ailleurs) alors cela pose problème puisque l'élément html du message (la div) n'existe qu'au moment du message donc le selector échoue.

{# read and display all flash messages #}
{% for label, messages in app.flashes %}
    {% for message in messages %}
        <div class="flash-{{ label }}">
            {{ message }}
        </div>
    {% endfor %}
{% endfor %}

==> quelqu'un a une solution opérationnelle ?

A+

-
Edité par monkey3d 4 octobre 2021 à 17:18:14

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 17:27:13

Salut

Et si tu mélanges avec un truc genre document.querySelectorAll('[class^="alert-"]'), une boucle et que dans celle-ci tu déclenches le compte a rebours pour chacun des éléments séparément ?

Je ne sais jamais comment ça se passe pour boucler avec les résultats de querySelectorAll(), mais je pense à quelque chose comme ça :

const alerts = document.querySelectorAll('[class^="alert-"]');
for (const alert of alerts) {
    setTimeout( function(alert) {
        bootstrap.Alert.getInstance(alert);
        alert.close();
    }, 5000);
}

Edit

Tout ça aurait probablement eu mieux sa place dans le forum JavaScript  :p

-
Edité par Ymox 4 octobre 2021 à 17:27:39

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 17:38:14

Merci Ymox pour ta réponse.

Le problème c'est que la div qui contient le flash message dans la partie twig n'existe que lors de la présence d'un flash message donc le querySelectorAll ne va rien trouver au chargement de la page si aucun flash message en cours.

C'est vrai que le forum js pourrait être sollicité mais c'est quand même bien lié au couplage avec la gestion Symfony des flash message donc je crains une réponse comme celle indiquée dans le lien de mon post d'origine.

C'est curieux que ce besoin ne trouve pas une réponse directe alors que cela fonctionnait facilement avec bootstrap 4 et ... jquery !

Et pour l'instant je ne me décide pas à remettre jquery.

A+

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 17:42:15

Tu as des messages flash qui s'affichent dans la page lors de rechargements AJAX ?
A noter que querySelectorAll() ne retourne pas rien, mais sauf erreur un tableau vide si rien ne colle au sélecteur.

Je ne comprends pas trop le souci, en fait. Normalement, les messages flash étant gérés par Symfony, ils sont présents dans le DOM au chargement de l'une ou l'autre page, pour moi ça devrait le faire. Qu'est-ce que j'ai loupé ?

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 17:53:59

En fait je mets le block twig de la doc Symfony dans le template base.html.twig et ensuite j'étends mes différentes vues à partir de ce block.

Donc par exemple ...  je fais une action de modifier sur un objet et dans le contrôleur je déclenche un message flash avant de retourner vers la route qui va afficher la page de list et là le message s'affiche. (pas d'ajax dans cet exemple simple)

J'ai toujours fait ainsi dans mes différents dev et cela fonctionnait au poil avec bootstrap 4.x.

Oui SelectorAll retourne un tableau bien-sûr mais encore faut-il que la balise html existe dans la page ...

Tu n'as pas ce type de besoin : afficher l'état de l'action à un user et faire disparaître le message sur tempo en utilisant bootstrap 5 ?

A+

-
Edité par monkey3d 4 octobre 2021 à 17:55:06

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 18:03:43

Non, je n'ai jamais eu ce besoin.

Voici un truc que je viens de tester avec succès sur la page de documentation de Bootstrap 5.0 sur les alerts.

const alerts = document.querySelectorAll('[class*="alert-"]')
for (const alert of alerts) {
    setTimeout( function() {
        const bootstrapAlert = bootstrap.Alert.getOrCreateInstance(alert);
        bootstrapAlert.close();
    }, 5000);
}

-
Edité par Ymox 4 octobre 2021 à 18:04:59

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 18:22:50

Ok Ymox mais nous ne devons pas nous comprendre.

Le query selector ne va trouver le tag de classe alert que si une alerte Symfony est dans le pipe donc au chargement d'une page il n'y a rien donc la boucle for ne se fait pas.

Tu as du faire ton test avec un élément html statique comme dans la doc bootstrap 5.

Je pense qu'il faudrait plutôt déclencher sur un event type onchange avec un listener js ... ce que faisait peut-être la librairie jquery.

Je pense que la nuit porte conseil ... ;)

A+

-
Edité par monkey3d 4 octobre 2021 à 18:23:54

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 18:26:20

Justement, comment génères-tu ces alerts ? Dans ton exemple, elles sont dans le DOM, ce script fonctionne sur des éléments qui sont dans le DOM.

Effectivement, je ne comprends pas.

Edit

Aah, je crois que je finis par comprendre.

Tu as ton script dans <head>, et du coup, effectivement, tu n'as pas le reste du DOM quand le script est exécuté. Et donc tu as besoin de l'équivalent pur JavaScript de $(document).ready() ?

-
Edité par Ymox 4 octobre 2021 à 18:30:41

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 18:32:31

Je vais faire reposer tout cela car je sens que je m'embrouille peut-être les neurones en étant parti sur la solution type bootstrap 4.

Merci pour ta contribution Ymox.

Je posterai le résultat opérationnel car je ne doute pas qu'il en existe au mois un.

A+

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 18:40:50

Je suis désolé, mais je ne comprends toujours pas le problème… tu n'as ni acquiescé ni infirmé les propositions que j'ai données quant au fonctionnement que tu souhaites… et n'a pas non plus répondu à certaines de mes questions.

Edit

Ou tu as loupé certains de mes ajouts après édition ? Bref.

-
Edité par Ymox 4 octobre 2021 à 18:48:19

  • Partager sur Facebook
  • Partager sur Twitter
4 octobre 2021 à 20:32:44

J'avais loupé tes éditions. :euh:

Donc je génère les alertes dans le contrôleur via un classique : 

$request->getSession()->getFlashBag()->add

Non, le block twig de message flash du template base n'est pas dans le <head>.

J'ai mis ton code ci-dessus entre 2 balises <script> dans le block javascript du template base et ... cela fonctionne !

Je suis à la fois satisfait :D et penaud  :o car j'ai quand même pas mal cherché, testé en lisant la doc bootstrap et des posts.

De plus j'ai raconté des c*** car quand la page est lancé s'il y a un message flash en attente alors la class alert existe.

Même s'Il est vrai que ce besoin n'a rien d'absolu par rapport à d'autres points comme l'authentification Symfony - Ldap qui est fondamentale pour le projet, le fait d'afficher les messages durant quelques secondes suite à une action utilisateur est apprécié.

Je te remercie grandement Ymox.

Je passe en résolu.

Bye

-
Edité par monkey3d 4 octobre 2021 à 20:39:40

  • Partager sur Facebook
  • Partager sur Twitter