angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Flask Message Flashing: Bootstrap Alerts vervangen door Toasts

Toon meldingen op een vaste positie bovenop de scherminhoud, niet ergens geperst in onze lay-out.

25 juli 2022
post main image
https://www.pexels.com/nl-nl/@goumbik

Wanneer je een Flask applicatie hebt met Bootstrap, gebruik je waarschijnlijk Bootstrap Alerts om flashed messages te laten zien. Ik gebruik ze, en ze werken, maar ik ben er niet echt gelukkig mee. Standaard zien ze er niet mooi uit en in de meeste gevallen nemen ze veel ruimte in op het scherm. En wil je echt dat meldingen als 'u bent ingelogd' een Bootstrap Alert zijn die door de user gesloten moet worden? Door een timeout toe te voegen kunnen we de Bootstrap Alert automatisch verwijderen, maar dit is nog lelijker!

Bootstrap Toasts

Met Bootstrap Toasts kunnen we meldingen maken die op een vaste plaats bovenop de scherminhoud worden geplaatst, niet ergens geperst in onze layout. We gebruiken 'position-fixed' in de 'toast-container' om de toast zichtbaar te maken in de viewport. Ik heb mijn toasts rechtsboven gezet, maar met enige afwijking van de bovenkant van het scherm. Ik moest ook de 'z-index' verhogen om er zeker van te zijn dat de toast altijd bovenaan staat.

<style>
.toast-container-extra {
    top: 30px;
    z-index: 10000;
}
</style>

Als u meerdere toasts heeft, wilt u waarschijnlijk geen toasts boven op elkaar, maar gestapeld:

  • De tweede toast staat onder de eerste
  • De derde toast staat onder de tweede
  • Enz.

Dit betekent dat wanneer we een toast willen laten zien, we wat Javascript / JQuery code nodig hebben om:

  • Maak de toast HTML van een sjabloon
  • Voeg het toast bericht toe
  • Voeg de toast HTML aan onze toast-container toe
  • Vertel Bootstrap dat we een nieuwe toast hebben
  • Laat Bootstrap de toast tonen

U gebruikt waarschijnlijk al Flask Message Flashing met categorieën:

flash('Invalid password provided', 'error')
...
flash('Invalid password provided', 'info')

Hieronder heb ik de toast-container en twee toast sjablonen gedefinieerd, één sjabloon voor de categorie 'error' en één sjabloon voor de categorie 'info'. De 'error' toast vereist de user om deze te sluiten, de 'info' toast sluit automatisch na een paar seconden.
Het categorie sjabloon wordt geïdentificeerd door het 'data-stack-toast-category' attribuut, we willen dubbele Id's vermijden.

{# 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 #}

Hier is de code om een toast toe te voegen, toe te voegen aan uw website Javascript bestand:

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;
}

Nu wilt u waarschijnlijk twee 'toon toast' knoppen toevoegen en wat code om te controleren dat dit werkt.

Aanpassen van het basissjabloon

U heeft waarschijnlijk een basistemplate met iets als de volgende code om de flashed messages te tonen met Bootstrap Alerts:

{% 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 -%}

Om Bootstrap toasts te gebruiken, wijzigen we deze code . Ik gebruik hier JSON om Content Security Policy (CSP) fouten te vermijden.

{% 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 -%}

En voeg dan de volgende code toe aan uw website Javascript bestand:

$(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);
    }    

});

Samenvatting

We hebben Bootstrap Alerts vervangen door Bootstrap Toasts met Flask Message Flashing. Dat is mooi, maar we willen waarschijnlijk een fijnmaziger controle. We zouden extra categorieën kunnen toevoegen voor gevallen waarin we nog steeds Bootstrap Waarschuwingen willen, bijvoorbeeld:

  • "error-alert
  • info-alert

Wij zouden ook de 'flash()' functie kunnen overriden en parameters toevoegen zoals:

  • melding_type
  • auto_verbergen

Maar, voordat we het wiel opnieuw uitvinden, willen we waarschijnlijk eerst nagaan hoe meldingen en waarschuwingen worden getoond op mobiele telefoons. Een andere keer ...

Links / credits

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

Laat een reactie achter

Reageer anoniem of log in om commentaar te geven.

Opmerkingen

Laat een antwoord achter

Antwoord anoniem of log in om te antwoorden.