Flask Message Flashing : Remplacer Bootstrap Alerts par Toasts
Afficher les notifications à une position fixe, au-dessus du contenu de l'écran, et non pas à un endroit où elles sont comprimées dans notre mise en page.
Lorsque vous avez une application Flask avec Bootstrap, vous utilisez probablement Bootstrap Alerts pour afficher flashed messages. Je les utilise, et ils fonctionnent, mais je ne suis pas vraiment satisfait. Par défaut, elles ne sont pas jolies et, dans la plupart des cas, elles prennent beaucoup de place sur l'écran. Et voulez-vous vraiment que des notifications comme "vous êtes connecté" soient une Bootstrap Alert qui doit être fermée par la user ? En ajoutant un délai d'attente, nous pouvons supprimer automatiquement la Bootstrap Alert mais c'est encore plus moche !
Bootstrap Toasts
Avec Bootstrap Toasts , nous pouvons créer des notifications qui sont placées à une position fixe au-dessus du contenu de l'écran, et non pas quelque part dans notre mise en page. Nous utilisons 'position-fixed' dans 'toast-container' pour rendre la toast visible dans la viewport. J'ai placé ma toasts en haut à droite mais avec un certain décalage par rapport au haut de l'écran. J'ai également dû augmenter la valeur de 'z-index' pour être sûr que la toast soit toujours en haut.
<style>
.toast-container-extra {
top: 30px;
z-index: 10000;
}
</style>
Si vous avez plusieurs toasts, vous ne voulez probablement pas que les toasts soient superposés, mais empilés :
- La deuxième toast est présentée sous la première.
- La troisième toast est présentée sous la deuxième.
- Etc.
Cela signifie que lorsque nous voulons afficher un toast, nous avons besoin d'un code Javascript / JQuery pour :
- Créer le toast HTML à partir d'un modèle.
- Ajouter le message toast
- Ajoutez le toast HTML à notre toast-container
- Dites à Bootstrap que nous avons un nouveau toast.
- Faites en sorte que Bootstrap affiche la toast.
Vous utilisez probablement déjà les Flask Message Flashing avec des catégories :
flash('Invalid password provided', 'error')
...
flash('Invalid password provided', 'info')
J'ai défini ci-dessous le modèle toast-container et deux modèles toast , un modèle pour la catégorie 'error' et un modèle pour la catégorie 'info'. Le 'error' toast nécessite le user pour le fermer, le 'info' toast se ferme automatiquement après quelques secondes.
Le modèle de catégorie est identifié par l'attribut 'data-stack-toast-category', nous voulons éviter les doublons.
{# stacked toasts container - start #}
<div class="toast-container position-fixed end-0 p-3 pt-0 toast-container-extra" id="toast-stack-container">
</div>
{# stacked toasts container - end #}
{# stacked toast error template - start #}
<div
class="toast mt-0"
role="alert"
aria-live="assertive"
aria-atomic="true"
data-bs-autohide="false"
data-stack-toast-category="error">
<div class="toast-header border-bottom border-white">
<strong class="me-auto">
Error
</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body toast-message"></div>
</div>
{# stacked toast error template - end #}
{# stacked toast info template - start #}
<div class="toast mt-0"
role="status"
aria-live="polite"
aria-atomic="true"
data-stack-toast-category="info">
<div class="toast-header border-bottom border-white">
<strong class="me-auto">
Info
</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body toast-message"></div>
</div>
{# stacked toast info template - end #}
Voici le code pour ajouter un toast, à ajouter au fichier Javascript de votre site web :
const toast_stack_container_elem = document.getElementById('toast-stack-container');
const error_toast_template_elem = document.querySelector('[data-stack-toast-category="error"]');
const info_toast_template_elem = document.querySelector('[data-stack-toast-category="info"]');
function create_toast_add_to_stack(category, message){
var new_toast;
switch(category){
case 'error':
new_toast = error_toast_template_elem.cloneNode(true);
break;
default:
new_toast = info_toast_template_elem.cloneNode(true);
}
var toast_message_elem = new_toast.querySelector('.toast-message');
if(toast_message_elem){
toast_message_elem.innerHTML = message;
}
toast_stack_container_elem.append(new_toast);
const toast = bootstrap.Toast.getOrCreateInstance(new_toast);
toast.show();
return;
}
Maintenant, vous voulez probablement ajouter deux boutons "Afficher toast" et du code pour vérifier que cela fonctionne.
Modifier le modèle de base
Vous avez probablement un modèle de base avec quelque chose comme le code suivant pour afficher les alertes flashed messages avec Bootstrap :
{% with messages = get_flashed_messages(with_categories=true) -%}
{% for category, message in messages -%}
{% if category == 'error' -%}
{% set alert_class = 'alert-danger' -%}
{% else -%}
{% set alert_class = 'alert-info' -%}
{% endif -%}
<div class="alert {{ alert_class }} alert-dismissible mb-3" role="alert">
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
{{ message }}
</div>
{% endfor -%}
{% endwith -%}
Pour utiliser Bootstrap toasts, nous modifions ce code . J'utilise ici JSON pour éviter les erreurs Content Security Policy (CSP).
{% with messages = get_flashed_messages(with_categories=true) -%}
{% set flashed_messages_page_data_js={} -%}
{% set x=flashed_messages_page_data_js.__setitem__('messages', messages) -%}
<script type="application/json" data-selector="flashed-messages-page-data-js">
{{ flashed_messages_page_data_js|tojson }}
</script>
{% endwith -%}
Et ensuite, ajoutez le code suivant au fichier Javascript de votre site web :
$(document).ready(function(){
try {
if($('script[data-selector="flashed-messages-page-data-js"]').length){
var flashed_messages_page_data_js = JSON.parse($('script[data-selector="flashed-messages-page-data-js"]').html());
if(flashed_messages_page_data_js.hasOwnProperty('messages')){
var messages = flashed_messages_page_data_js.messages;
for(var i = 0; i < messages.length; i++){
var category = messages[i][0];
var message = messages[i][1];
create_toast_add_to_stack(category, message);
}
}
}
}
catch(error){
// no-op
console.log('flashed messages, error = ');
console.log(error);
}
});
Résumé
Nous avons remplacé Bootstrap Alerts par Bootstrap Toasts par Flask Message Flashing. C'est bien, mais nous voulons probablement un contrôle plus fin. Nous pourrions ajouter des catégories supplémentaires pour les cas où nous voulons toujours des alertes Bootstrap , par exemple :
- "alerte-erreur
- alerte-info
Nous pouvons également remplacer la fonction "flash()" et ajouter des paramètres tels que :
- notification_type
- auto_hide
Mais avant de réinventer la roue, nous devrions d'abord vérifier comment les notifications et les alertes sont affichées sur les téléphones portables. Une autre fois ...
Liens / crédits
Bootstrap - Alerts
https://getbootstrap.com/docs/5.1/components/alerts
Bootstrap - Toasts
https://getbootstrap.com/docs/5.2/components/toasts
Flask - Message Flashing
https://flask.palletsprojects.com/en/2.1.x/patterns/flashing
Inline Data With a Content Security Policy
https://itnext.io/inline-data-with-a-content-security-policy-ab30dde2feb3
Toasts
https://preview.keenthemes.com/start/documentation/base/toasts.html
Récent
- Masquer les clés primaires de la base de données UUID de votre application web
- Don't Repeat Yourself (DRY) avec Jinja2
- SQLAlchemy, PostgreSQL, nombre maximal de lignes par user
- Afficher les valeurs des filtres dynamiques SQLAlchemy
- Transfert de données sécurisé grâce au cryptage à Public Key et à pyNaCl
- rqlite : une alternative à haute disponibilité et dist distribuée SQLite
Les plus consultés
- Utilisation des Python's pyOpenSSL pour vérifier les certificats SSL téléchargés d'un hôte
- Utiliser UUIDs au lieu de Integer Autoincrement Primary Keys avec SQLAlchemy et MariaDb
- Connexion à un service sur un hôte Docker à partir d'un conteneur Docker
- Utiliser PyInstaller et Cython pour créer un exécutable Python
- SQLAlchemy : Utilisation de Cascade Deletes pour supprimer des objets connexes
- Flask RESTful API validation des paramètres de la requête avec les schémas Marshmallow