Formulář v bootstrap 4 modalu – modal se znovu neotevře při neúspěšné validaci

pata.kusik111
Člen | 78
+
0
-

Ahoj, myslím si, že problém je jasný už z popisku.

Mám formulář v Bootstrap 4 modalním okně.

Mám také nějakou složitější validaci, které nejde úplně lehce udělat přímo na frontendu.

Můj problém je v tom, že když se formulář odešle a znovu se načte stránka, tak se modal znovu neotevře, takže uživatel nedostane zpětnou vaznu na to, že je chyba ve validaci. Maximum, co bych mohl udělat je na tu samotnou stránku hodit nějaký flashMessage s oznámením, ale podlě mě by bylo lepší, kdyby se rovnou otevřel ten modal a on by hnedka viděl přímo ty $form->addError zprávičky.

Nevíte někdo, jak na to? Neřešili jste to už?

F.Vesely
Člen | 369
+
+1
-

Budto muzes jit cestou znovu otevreni modalu, pokud je ve formulari nejaka chyba. Coz se dela pomoci JS

	$('#myModal').modal();

Nebo muzes pouzit AJAX a snippety viz https://doc.nette.org/…ication/ajax

{snippet form}
	{control form}
{/snippet}
$form->onError[] = function() {
	$this->redrawControl('form');
}
Allconius
Člen | 317
+
0
-

Ahoj, řeším podobný problém, mám to přes snippet, ale podle mě se tím redrawControl jen překreslí ten snippet, ale to modální okno už se neotevře, volám ho takto:

<td><a class="ajax" n:href="userdetail! $post['id']" style="cursor: pointer;" data-bs-toggle="modal" data-bs-target="#userModal">{$post["login"]}</a></td>

a modální okno:

            <div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
                <div class="modal-dialog modal-lg">

                    <div n:snippet="userData">

takže ten snippet je „userData“ a to okno „userModal“ a nevím co mám zavolat. Potřeboval bych při chybě znovu otevřít to modální okno a ne jen překreslit data ve snippetu, takže něco jako:

$form->onError[] = function() {
	$this->openControl('userModal');
};

nebo to jde jen tím JS?

$('#userModal').modal('show');
Kamil Valenta
Člen | 815
+
+2
-

Allconius napsal(a):

nebo to jde jen tím JS?

$('#userModal').modal('show');

Pokud používáš JS knihovnu, v které můžeš vytvořit event na „after-redraw“ (např. Naja), tak tam tohle navěs.
Pokud nemůžeš, tak to dej jako inline script do překreslovaného snippetu.

Allconius
Člen | 317
+
-1
-

A jak se dělá ten inline script ? Potřeboval bych aby se modalní okno znovu otevřelo jen při erroru:

        if (count($result)>0) {
            $err = 'Tato e-mailová adresa už byla použita!';
            $form->addError($err);
            $this->redrawControl('userData');
        }

takže jen to

            $this->redrawControl('userData');

nějak nahradit tím inline s otevřením okna :

            $('#userModal').modal('show');
Kamil Valenta
Člen | 815
+
0
-
$form->onError[] = function() {
	$this->redrawControl('userData');
};
{snippet userData}
...
{if $form->hasErrors()}
    $('#userModal').modal('show');
{/if}
...
{/snippet}
Allconius
Člen | 317
+
0
-

Kamil Valenta napsal(a):

{snippet userData}
...
{if $form->hasErrors()}
    $('#userModal').modal('show');
{/if}
...
{/snippet}

Ahoj, díky a jak předám ten $form->hasErrors do šablony ? To

{if $form->hasErrors()}

mi píše:

Undefined variable $form
Allconius
Člen | 317
+
0
-

Resp. pokud to dám takto:

<div n:snippet="userData">

    <form n:name="userForm"  class="d-flex">

        <script>
            $(document).ready(function() {
                {if $form->hasErrors()}
                $('#userModal').modal('show');
                {/if}
            });

        </script>

tak se sice modal při chybě znovu otevře ale už to nevypíše co bylo za chybu.

Kamil Valenta
Člen | 815
+
+2
-

V útržku kódu, který jsi poskytl, také nikde chyby nevypisuješ.

Allconius
Člen | 317
+
0
-

Ahoj, mám to takto:
PRESENTER:


    public function renderUsers(int $page=1, int $trideni=1, int $asc=1): void
    {


        //PAGINATOR
        $articles = $this->database->table('uzivatele')
            ->order('uzivatele.aktivni DESC, uzivatele.prijmeni ASC');
        $lastPage = 0;
        $itemsPerPage = 50;
        $this->template->articles = $articles->page((int)$page, $itemsPerPage, $lastPage);
        $this->template->page = $page;
        $this->template->trideni = $trideni;
        $this->template->asc = $asc;
        $this->template->lastPage = $lastPage;
        $this->template->i = $itemsPerPage*($page-1) + 1;

    }

    public function actionUsers(int $page=1, int $trideni=1, int $asc=1)
    {

        $this->createLog('Backend','users', 'users', 'add', 1);

    }

    public function handleUserDetail(int $id): void
    {

        $result = $this->database->table('uzivatele')
            ->where('uzivatele.id = ?', $id);

        foreach ($result as $id => $row) {
            $id = $row->id;
            $jmeno = $row->jmeno;
            $prijmeni = $row->prijmeni;
            $email = $row->email;
            $login = $row->login;
            $role = $row->role;

        }

        $this['userForm']->setValues(array(
            "id" => $id,
            "jmeno" => $jmeno,
            "prijmeni" => $prijmeni,
            "email" => $email,
            "login" => $login,
            "role" => $role

        ), true);


        $this->redrawControl('userData');
    }

    protected function createComponentUserForm()
    {

        $form = new Form;
        $form->addProtection();

        $form->addGroup('');

        $form->addText('id', 'id');

        $form->addText('jmeno', 'Jméno:', 30, 250)
            ->setRequired('Vaše jméno musí být vyplněno.');

        $form->addText('prijmeni', 'Příjmení:', 30, 250)
            ->setRequired('Vaše příjmení musí být vyplněno.');


        $form->addText('email', 'E-mail:', 30, 250)
            ->setRequired('Zadejte prosím Vaši E-mailovou adresu.')
            ->addRule($form::EMAIL, 'Zadejte prosím Váš e-mail ve správném formátu.');

        $form->addText('login', 'Login:', 30, 250)
            ->setDisabled();

        $form->addPassword('password', 'Heslo:', 30, 250)
            ->addCondition(Form::FILLED)
            ->addRule($form::MinLength, '%label musí být delší než %d znaků', 10)
            ->addRule($form::MaxLength, '%label nemůže být delší než %d znaků', 250)
            ->addRule($form::Pattern, '%label musí obsahovat číslo', '.*[0-9].*')
            ->addRule($form::Pattern, '%label musí obsahovat velké písmeno', '.*[A-Z].*')
            ->addRule($form::Pattern, '%label musí obsahovat malé písmeno', '.*[a-z].*')
            ->addRule($form::Pattern, '%label musí obsahovat symbol', '.*[!"#$%&’()*+,-./:;<=>?@[\]^_\'{|}~].*')
            ->setRequired('%label musí být vyplněno.');

        $result = $this->database->fetchAll('SELECT name FROM role ORDER BY name');
        $role = array();
        foreach ($result as $row) {
            $role[$row->name] = $row->name;
        }

        $form->addSelect('role', 'Role:', $role);


        $form->addSubmit('submit', 'Uložit');

        $form->onValidate[] = [$this, 'userValidateForm'];

        $form->onError[] = function() {
            $this->redrawControl('userData');
        };

        $form->onSuccess[] = [$this, 'userFormSucceeded'];

        return $form;

    }

    public function userValidateForm(Form $form, \stdClass $data): void
    {

        $result = $this->database->table('uzivatele')
            ->where('uzivatele.email = ?', $data->email)
            ->where('uzivatele.id <> ?', $data->id);

            if (count($result) > 0) {
                $err = 'Tato e-mailová adresa už byla použita!';
                $form->addError($err);
            }

            list($user, $domain) = explode('@', $data->email);

            if (checkdnsrr($domain) === FALSE) {
                $err = 'Tato e-mailová adresa neexistuje!';
                $form->addError($err);
            }


    }

    public function userFormSucceeded(Form $form, $data)
    {

        $data = $form->getValues();

        if (empty($data->password)){
            $this->database->query('UPDATE uzivatele SET', [
                'jmeno' => $data->jmeno,
                'prijmeni' => $data->prijmeni,
                'email' => $data->email,
                'role' => $data->role,
            ], 'WHERE id = ?', $data->id);


        }else{

            $passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);
            $hash = $passwords->hash($data->password);

            $this->database->query('UPDATE uzivatele SET', [
                'jmeno' => $data->jmeno,
                'prijmeni' => $data->prijmeni,
                'email' => $data->email,
                'password' => $hash,
                'role' => $data->role,
            ], 'WHERE id = ?', $data->id);


        }


        $this->redirect('Backend:users');
        exit;
    }


Allconius
Člen | 317
+
0
-

SABLONA:


    <div class="container">
        <h3>Administrace uživatelů</h3>


        {if $user->isAllowed('users', 'add')}
            <div class="menu">:: <a n:href="Backend:users 0">Přidej nový záznam</a></div>
        {/if}


{if $user->isAllowed('users', 'edit')}
        <div class="table-responsive">
            <table class="table table-striped table-hover" id="table-prehled">
                <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">Jméno</th>
                    <th scope="col">Příjmení</a></th>
                    <th scope="col">Login</th>
                    <th scope="col">E-mail</th>
                    <th scope="col">Odbor</th>
                    <th scope="col">Aktivita</th>
                </tr>
                </thead>
                <tbody>
                {foreach $articles as $post}
                    <tr>
                        <th scope="row">{$i++}</th>
                        <td>{$post["jmeno"]}</td>
                        <td>{$post["prijmeni"]}</td>
                        <td><a class="ajax" n:href="userdetail! $post['id']" style="cursor: pointer;" data-bs-toggle="modal" data-bs-target="#userModal">{$post["login"]}</a></td>
                        <td>{$post["email"]}</td>
                        <td>{$post["odbor"]}</td>
                        <td>{$post["aktivni"]}</td>
                    </tr>
                {/foreach}
                </tbody>
            </table>
        </div>


            <div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
                <div class="modal-dialog modal-lg">

                    <div n:snippet="userData">

                        <form n:name="userForm"  class="d-flex">

                            <script>
                                $(document).ready(function() {
                                    {if $form->hasErrors()}
                                    $('#userModal').modal('show');
                                    {/if}
                                });

                            </script>

                            <div class="modal-content">
                                <div class="modal-header bg-warning">
                                    <h1 class="modal-title fs-5 text-uppercase" id="userModalLabel">Editace uživatele</h1>
                                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                </div>
                                <div class="modal-body">
                                    <div class="p-2">
                                        <input n:name="id" id="id" hidden="on">
                                        <label n:name=jmeno class="form-label mb-0">Jméno:</label>
                                        <input n:name=jmeno title="Jméno" class="form-control rounded-0 mt-0" style="height: 2.5rem;" autofocus>
                                        <label n:name=prijmeni class="form-label mb-0">Příjmení:</label>
                                        <input n:name=prijmeni title="Příjmení" class="form-control rounded-0 mt-0" style="height: 2.5rem;" autofocus>
                                        <label n:name=email class="form-label mb-0">E-mail:</label>
                                        <input n:name=email title="E-mail" class="form-control rounded-0 mt-0" style="height: 2.5rem;" autofocus>
                                        <label n:name=login class="form-label mb-0">Login:</label>
                                        <input n:name=login title="login" class="form-control rounded-0 mt-0" style="height: 2.5rem;" autofocus>
                                        <label n:name=password class="form-label mb-0">Heslo:</label>
                                        <input n:name=password title="Heslo" class="form-control rounded-0 mt-0" style="height: 2.5rem;" autofocus>
                                        <label n:name=role class="form-label mb-0">Role:</label>
                                        <select n:name=role title="Role" class="form-control rounded-0 mt-0" style="height: 2.5rem;" autofocus></select>
                                    </div>
                                </div>
                                <div class="modal-footer" style="justify-content: space-between; padding: .75rem 1.25rem">
                                    <button type="button" class="btn btn-secondary rounded-0" data-bs-dismiss="modal">Zavřít</button>
                                    <input id="ulozitZmeny" n:name="submit" type="submit" class="search-submit btn btn-outline-success rounded-0" />
                                </div>
                            </div>

                        </form>
                    </div>
                </div>
            </div>


        <div class="pagination">
            {if $page > 1}
                <a n:href="Backend:users, 1, $trideni, $asc">První</a>
                &nbsp;|&nbsp;
                <a n:href="Backend:users, $page - 1, $trideni, $asc">Předchozí</a>
                &nbsp;|&nbsp;
            {/if}

                Stránka {$page} z {$lastPage}

            {if $page < $lastPage}
                &nbsp;|&nbsp;
                <a n:href="Backend:users, $page + 1, $trideni, $asc">Další</a>
                &nbsp;|&nbsp;
                <a n:href="Backend:users, $lastPage, $trideni, $asc">Poslední</a>
            {/if}
        </div>

        {/if}

    </div>

Jde mi o to userValidateForm kde mám $form->addError($err);

Kamil Valenta
Člen | 815
+
+2
-

dtto
Pokud v šabloně chyby formu nevypisuješ, nemůžeš očekávat, že se někde samy objeví.

Např.

<div class="modal-body">
{if $form->hasErrors()}
	{foreach $form->getErrors() as $err}
		<div class="alert alert-danger">{$err}</div>
	{/foreach}
{/if}
    <div class="p-2">
        <input n:name="id" id="id" hidden="on">
        ...

Editoval Kamil Valenta (12. 7. 2023 13:09)

Allconius
Člen | 317
+
0
-

Kamil Valenta napsal(a):

dtto
Pokud v šabloně chyby formu nevypisuješ, nemůžeš očekávat, že se někdy samy objeví.

Např.

<div class="modal-body">
{if $form->hasErrors()}
	{foreach $form->getErrors() as $err}
		<div class="alert alert-danger">{$err}</div>
	{/foreach}
{/if}
    <div class="p-2">
        <input n:name="id" id="id" hidden="on">
        ...

Ajo to mi nedošlo, to je pak jasný :-) Díky moc za pomoc.