Jednoduchá implementace Bootstrap Modalu do Nette

před 2 lety

medhi
Bronze Partner | 189
+
+10
-

Rád bych se podělil o způsob řešení bootstrapovských modal oken v Nette, ke kterému jsem časem dospěl. Možná se bude někomu hodit, možná někdo navrhne nějaké vylepšení (sem s ním).

Výhody

  • Jednoduché a přehledné
    • Odkazy spouštějící modal jsou obyčejné signály bez dalších HTML parametrů
    • Definice modalu v šabloně a presenteru je minimální
  • Univerzální: v modálním okně lze zobrazit libovolný obsah včetně proměnných z presenteru závislých na tom kterém modalu.
  • Přístupné: na otevřené modální okno vede i přímý odkaz (nápad @FilipProcházka).
  • Modal footer je nepovinný (při vkládání formulářů do modalu footer nepoužívám, protože by bylo složité oddělit formulářové tlačítko).

Nevýhody

  • Při zavírání okno zmizí rychle a plynule neodjede, protože se nejdřív překreslí snippet a obsah zmizí. Až potom (již neviditelné) okno odjíždí. Pokud máte nápad jak to vyřešit, podělte se. Muselo se překreslení snippetu pozdržet až do události $('#modal').on('hidden.bs.modal', ...);.
main.js (předpokládá se použití nette.ajax.js)
$.nette.ext('bs-modal', {

    init: function() {
        // if the modal has some content, show it when page is loaded
        var $modal = $('#modal');
        if ($modal.find('.modal-content').html().trim().length !== 0) {
            $modal.modal('show');
        }
    },
    success: function (jqXHR, status, settings) {

        if (typeof settings.responseJSON.snippets != 'undefined') {
            var $snippet = settings.responseJSON.snippets['snippet--modal'];
        }
        if (!$snippet) {
            return;
        }

        var $modal = $('#modal');
        if ($modal.find('.modal-content').html().trim().length !== 0) {
            $modal.modal('show');
        } else {
            $modal.modal('hide');
        }
    }
});
BasePresenter.php
public function handleModal($modalId)
{
    $this->template->modal = $modalId;
    $this->redrawControl('modal');
}
@layout.latte

Klasická Bootstrap definice modalu, doplněná o jeden snippet, podmíněné vykreslení obsahu a tři podmíněné includy blocků (hlavičky, těla a patičky).

<div class="modal fade" id="modal">
        <div class="modal-dialog">
            <div class="modal-content" n:snippet="modal">
                {ifset $modal}
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal">×</button>
                        <h4 class="modal-title">
                            {ifset #modal-$modal-title}{include #"modal-$modal-title"}{/ifset}
                        </h4>
                    </div>
                    <div class="modal-body">
                        {ifset #modal-$modal-body}{include #"modal-$modal-body"}{/ifset}
                    </div>
                    {ifset #modal-$modal-footer}
                        <div class="modal-footer">
                            {include #"modal-$modal-footer"}
                        </div>
                    {/ifset}
                {/ifset}
            </div>
        </div>
    </div>
myPage.latte

Šablona, kde chci zobrazit jednoduchý modal.

{block content}
    <a n:href="modal! 'mujModal'" class="ajax">Zobraz modal</a>
{/block}

{* Definice modalu, samozřejmě jich takto můžeme definovat za sebou libovolný počet: *}

{define modal-edit-title}
    Nadpis modal okna
{/define}
{define modal-edit-body}
    Libovolný obsah modal okna
{/define}
{define modal-edit-footer}
    Nepovinný footer modal okna <button>OK</button>
{/define}

Toto stačí pro zobrazování modal oken se statickým obsahem (bez dat závislých na konkrétním modal okně).

Zavření okna

Okno můžeme zavřít buď klasickým způsobem jak navádí dokumentace Bootstrapu nebo pomocí opětovného zavolání $this->redrawControl('modal');. To je vhodné umístit například do funkce, kde je úspěšně zpracován formulář a okno se může zavřít.


Někdy je potřeba při zobrazení modalu načíst nějaká data

Například na stránce se seznamem článků chceme kliknout u libovolného článku na UPRAVIT a chceme zobrazit modální okno s předvyplněným formulářem pro editaci toho článku.

Articles/default.latte

Stránka se seznamem všech článků.

{block content}
    {foreach $articles as $article}
        ...
        <a n:href="editArticle! $article->id" class="ajax">Edituj článek</a>
        ...
    {/foreach}
{/block}
{define modal-edit-title}
    Upravit článek
{/define}
{define modal-edit-body}
    {control editArticleForm}
{/define}
ArticlesPresenter.php
public function handleEditArticle($articleId)
{
    $this->article = $this->sourceFacade->getByUserAndId($this->userEntity, $sourceId);
    if ( ! $this->article) {
        throw new BadRequestException();
    }

    // otevřeme modal přes signál v BasePresenteru
    parent::handleModal('edit');

    // nebo si modal otevřeme sami:
    $this->template->modal = 'edit';
    $this->redrawControl('modal');
}


// $this->article již můžeme použít ve formuláři v presenteru pro načtení výchozích hodnot nebo předat továrničce na formulář apod.

Editoval medhi (6. 3. 2017 11:30)