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

Flask Message Flashing: Заменить Bootstrap Alerts на Toasts

Показывать уведомления в фиксированном положении поверх содержимого экрана, а не где-то втиснутыми в наш макет.

25 июля 2022
post main image
https://www.pexels.com/nl-nl/@goumbik

Когда у вас есть приложение Flask с Bootstrap, вы, вероятно, используете Bootstrap Alerts , чтобы показать flashed messages. Я использую их, и они работают, но я не очень доволен. По умолчанию они выглядят некрасиво и в большинстве случаев занимают много места на экране. И вы действительно хотите, чтобы уведомления типа "вы вошли в систему" были Bootstrap Alert , которые должны закрываться user? Добавив таймаут, мы можем автоматически удалить Bootstrap Alert , но это еще более некрасиво!

Bootstrap Toasts

С помощью Bootstrap Toasts мы можем создавать уведомления, которые размещаются в фиксированной позиции поверх содержимого экрана, а не где-то втиснуты в наш макет. Мы используем 'position-fixed' в 'toast-container', чтобы сделать toast видимым в viewport. Я поместил свой toasts вверху справа, но с некоторым смещением от верхней части экрана. Мне также пришлось увеличить 'z-index', чтобы убедиться, что toast всегда находится сверху.

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

Если у вас несколько toasts, вам, вероятно, не нужны toasts , расположенные друг над другом, но сложенные в стопку:

  • Второй toast показан ниже первого.
  • Третий toast показан ниже второго.
  • И т.д.

Это означает, что когда мы хотим показать toast, нам нужен некоторый код Javascript / JQuery, чтобы:

  • Создайте toast HTML из шаблона.
  • Добавить сообщение toast
  • Добавить сообщение toast HTML к нашему сообщению toast-container
  • Сообщите Bootstrap , что у нас есть новый toast
  • Заставьте Bootstrap показать toast

Вы, вероятно, уже используете Flask Message Flashing с категориями:

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

Ниже я определил toast-container и два шаблона toast , один шаблон для категории 'error' и один шаблон для категории 'info'. 'error' toast требует user для его закрытия, 'info' toast автоматически закрывается через несколько секунд.
Шаблон категории идентифицируется атрибутом 'data-stack-toast-category', мы хотим избежать дублирования идентификаторов.

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

Вот код для добавления toast, который будет добавлен в файл Javascript вашего сайта:

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

Теперь вы, вероятно, захотите добавить две кнопки 'show toast' и некоторый код, чтобы проверить, что это работает.

Изменение базового шаблона

У вас, вероятно, есть базовый шаблон с чем-то вроде следующего кода для показа flashed messages с оповещениями 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 -%}

Чтобы использовать Bootstrap toasts, мы изменим этот код. Я использую здесь JSON , чтобы избежать ошибок 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 -%}

А затем добавьте следующий код в файл Javascript вашего сайта:

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

});

Резюме

Мы заменили Bootstrap Alerts на Bootstrap Toasts Flask Message Flashing. Это хорошо, но нам, вероятно, нужен более тонкий контроль. Мы можем добавить дополнительные категории для случаев, когда нам все еще нужны оповещения Bootstrap , например:

  • 'error-alert'
  • 'info-alert'

Мы также можем переопределить функцию 'flash()' и добавить такие параметры, как:

  • тип_уведомления
  • автоскрытие

Но прежде чем снова изобретать колесо, мы, вероятно, захотим сначала проверить, как уведомления и предупреждения отображаются на мобильных телефонах. В другой раз ...

Ссылки / кредиты

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

Оставить комментарий

Комментируйте анонимно или войдите в систему, чтобы прокомментировать.

Комментарии

Оставьте ответ

Ответьте анонимно или войдите в систему, чтобы ответить.