Lekce 23 - Bootstrap - Modální dialogy
V minulé lekci, Bootstrap - Paginace, Upozornění a Drobečková navigace, jsme pokračovali v přehlídce Bootstrap komponent Pagination, Alerts a Breadcrumb.
V následujícím tutoriálu CSS frameworku Bootstrap se budeme věnovat modálním dialogům.
Ačkoli pop-upy, překryvný obsah, se na web úplně nehodí, občas se mu
nevyhneme. Jedná se například o situaci, kdy se chceme uživatele zeptat, zda
si skutečně přeje zavřít záložku, protože má rozdělanou práci. K
tomuto účelu bychom sice mohli použít nativní JavaScriptové dialogy
(confirm()
, prompt()
, alert()
), ale ty
většinou nevypadají zrovna nejlépe a nelze je přizpůsobovat. Pop-upy se
často používají také například k otevření zvětšeniny obrázku nebo
videa, aby se zabránilo zbytečnému přesměrování na jinou stránku.
Známé jsou také pod označením lightbox.
Modální dialogy v Bootstrapu
Modální dialogy tvoříme pomocí JavaScriptu. Budeme k nim tedy opět potřebovat načíst Bootstrap JavaScript plugin.
Jako první ukázku do stránky vložíme tlačítko, které po stisknutí vyvolá modální dialog:
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#dialog"> Otevřít dialog </button> <div class="modal fade" id="dialog" tabindex="-1" aria-labelledby="dialog-label" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="dialog-label">Titulek</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"> </button> </div> <div class="modal-body"> <p>Text</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Zavřít</button> </div> </div> </div> </div>
Dialogy budeme na rozdíl od naprosté většiny komponent spouštět v praxi
spíše JavaScriptem. V ukázce výše je dialog otevřený pomocí elementu
<button>
a data atributem
data-bs-toggle="modal"
. Pomocí atributu
data-bs-target
uvedeme selektor na dialog, který má tlačítko
otevřít. Výsledek v prohlížeči:
Pro dialog nejprve vkládáme poloprůhlednou šedou vrstvu přes stránku
jako element <div>
se třídou .modal
. K
dosažení efektu animace přidáváme ještě třídu .fade
, pokud
bychom animaci z nějakého důvodu nechtěli, tak třídu jednoduše
nepřidáme. K vyloučení vybrání vrstvy klávesou Tab uvádíme
atribut tabindex="-1"
. A konečně k dosažení podpory hlasových
čteček přidáváme atributy aria-labelledby="dialog-label"
a
aria-hidden="true"
. Samotný dialog poté vkládáme jako další
<div>
se třídou .modal-dialog
. Ten rozdělíme
na divy se třídami .modal-header
, .modal-body
a
.modal-footer
. Za povšimnutí stojí ještě vložení křížku k
uzavření dialogu v jeho hlavičce.
Do dialogu můžeme vložit libovolný HTML obsah včetně formulářů. Ovšem pozor, nepoužívejme dialogy na reklamní sdělení, která se otevřou hned po navštívení stránky, Google takové weby penalizuje.
Při zobrazení pop-upu se na element <body>
automaticky
aplikuje třída .modal-open
, která mu odstraní scrollbary. Není
třeba ji implementovat ručně. Můžeme tak scrollovat obsahem pop-upu, pokud
se na stránku nevejde, místo abychom rolovali stránkou. Bootstrap modal se
zavře kliknutím mimo něj. V jednu chvíli můžeme zobrazit pouze jeden
takový dialog. Protože se modální dialogy zobrazují s fixní pozicí, měli
bychom modální obsah umístit nad obsah stránky, aby nedošlo k překrytí
modálního obsahu nějakou částí obsahu na stránce. V modálních
dialozích nebude fungovat atribut autofocus
. Pokud bychom do
dialogu umístili formulář a chtěli atributu využít, musíme místo něj
sáhnout po JavaScriptu:
var myModal = document.getElementById('myModal') var myInput = document.getElementById('myInput') myModal.addEventListener('shown.bs.modal', function () { myInput.focus() })
Jak již bylo řečeno, do dialogů můžeme vložit prakticky cokoli včetně popovers nebo gridu, viz dále v kurzu.
Předvyplnění obsahu
Modální dialogy můžeme předvyplnit nebo i lehce pozměnit jejich obsah v závislosti na události, při jaké byly otevřené. Můžeme tedy používat jeden modální dialog pro více podobných účelů.
V ukázce níže vyplníme text do inputu v závislosti na stisknutém tlačítku:
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#dialog" data-bs-whatever="funkce">Navrhnout novou funkci</button> <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#dialog" data-bs-whatever="bug">Nahlásit bug</button> <div class="modal fade" id="dialog" tabindex="-1" aria-labelledby="dialog-label" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="dialog-label">Vývoj systému</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <form> <div class="mb-3"> <label for="typ-pozadavku" class="col-form-label">Typ požadavku</label> <input type="text" class="form-control" id="typ-pozadavku"> </div> <div class="mb-3"> <label for="text-pozadavku" class="col-form-label">Text</label> <textarea class="form-control" id="text-pozadavku"></textarea> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary">Odeslat</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Zavřít</button> </div> </div> </div> </div>
K předvyplnění dialogu využijeme JavaScript:
var MyModal = document.getElementById('dialog') MyModal.addEventListener('show.bs.modal', function (event) { var button = event.relatedTarget // Získáme tlačítko, kterým jsme dialog otevřeli var recipient = button.getAttribute('data-bs-whatever') // Získáme info z data-bs-whatever atributu var modalBodyInput = MyModal.querySelector('.modal-body input') // Přiřadíme hodnotu do inputu modalBodyInput.value = recipient })
V JavaScriptu bychom samozřejmě mohli upravit jakoukoli část dialogu,
načíst do něj něco AJAXem a podobně. Klíčová je reakce na událost
show.bs.modal
.
Výsledek v prohlížeči:
Výška dialogu
Dialog se vycentruje v závislosti na jeho výšce, která se vypočítá
při jeho zobrazení. Pro dynamickou změnu obsahu a následnou aktualizaci
pozice modálního okna použijeme metodu myModal.handleUpdate()
na
instanci modálního dialogu vytvořeného pomocí JavaScriptu:
var myModal = new bootstrap.Modal(document.getElementById('dialog')); myModal.handleUpdate();
Velikosti
I dialogy můžeme vyvolat v několika velikostech a to přidáním třídy
elementu <div>
se třídou .modal-dialog
, tedy
druhému vnořenému divu:
.modal-sm
- malý dialog,- bez třídy pro výchozí velikost,
.modal-lg
- větší dialog,.modal-xl
- velký dialog.
JavaScript
Jak již bylo řečeno, JavaScript bude u modálních dialogů naším přítelem. Kromě vyvolání tlačítky s data atributem můžeme dialog vyvolat pomocí JavaScriptu jako:
var myModal = new bootstrap.Modal(document.getElementById('myModal'), options)
Tento přístup je alternativou k použití data atributů v HTML pro spouštění modálního okna. To je užitečné v situacích, kde potřebujeme více kontroly nad chováním modálního okna, než jakou poskytují standardní data atributy.
Vlastnosti dialogu
Pomocí data atributů s prefixem data-bs-
nebo pomocí
následujících javascriptových vlastností na dialogu lze měnit jeho
chování. Objekt s těmito vlastnostmi můžeme předat konstruktoru výše
jako parametr:
backdrop
- Hodnotatrue
způsobí překrytí stránky poloprůhledným šedým pozadím. Hodnotastatic
navíc neumožní dialog zavřít kliknutím na toto pozadí. S hodnotoufalse
se tato překryvná vrstva nezobrazí.keyboard
- Na základě hodnottrue
nebofalse
dojde, resp. nedojde, k uzavření dialogu po stisknutí klávesy Esc.focus
- Přesune focus na dialog po jeho otevření, výchozí hodnota jetrue
.
Metody dialogu
Všechny metody jsou volané asynchronně a předávají řízení ještě předtím, než dojde k dokončení animace (transition). Pokud zavoláme metodu na dialogu, který právě přehrává transition, bude toto volání metody ignorováno.
Objekt s nastavenými vlastnostmi tak, jak jsme si je popsali výše, voláme například jako:
var myModal = new bootstrap.Modal(document.getElementById('myModal'), { keyboard: false })
Metody pro ovládání dialogu jsou pak tyto:
toggle()
- Otevře/skryje dialog a předá řízení dříve, než dojde k jeho skutečnému zobrazení/skrytí.show()
- Otevře dialog a předá řízení dříve, než dojde k jeho skutečnému zobrazení.hide()
- Zavře dialog a předá řízení dříve, než dojde k jeho skutečnému zmizení.handleUpdate()
- Přepozicuje dialog na základě jeho výšky. Voláme, pokud se jeho výška změnila.dispose()
- Zničí dialog.getInstance()
- Statická metoda, která umožní získat modální instanci spojenou s prvkem DOM.getOrCreateInstance()
- Statická metoda, která umožní získat modální instanci přidruženou k prvku DOM nebo vytvořit novou v případě, že nebyla inicializována.
Události
Všechny modální události jsou spouštěny na samotný modal (tj. na
<div class="modal">
):
show.bs.modal
- Vyvolá se po otevření dialogu, ale ještě před jeho zobrazením, protože stále může probíhat animace. Pokud byl dialog otevřen pomocí tlačítka, nalezneme tento element ve vlastnostirelatedTarget
této události.shown.bs.modal
- Vyvolá se jakmile je dialog zobrazený, tedy po dokončení jeho animace. Pokud byl dialog otevřen pomocí tlačítka, nalezneme tento element ve vlastnostirelatedTarget
této události.hide.bs.modal
- Vyvolá se po uzavření dialogu, ale ještě před tím, než dialog opravdu zmizí.hidden.bs.modal
- Vyvolá se až poté, co uzavřený dialog přestane být viditelný.hidePrevented.bs.modal
- Událost se spustí, když je zobrazen dialog a jeho pozadí je statické při kliknutí mimo dialog nebo při stisknutí klávesy Esc nebo nastavenímdata-bs-keyboard
nafalse
.
Reakce na událost vypadá například takto:
const myModalEl = document.getElementById('myModal') myModalEl.addEventListener('hidden.bs.modal', event => { // Nějaká reakce na událost... })
V příští lekci, Bootstrap - Popovers, se budeme věnovat komponentám Popovers.