Form ERROR pri pouziti AJAX + SNIPPET
- balicekt
- Člen | 52
Zdarvim, mam dotaz ohledne vykreslovani chyb ve formulari pri pouzivani AJAXU.
Pokud udelam
<?php
$form->addError("moje chyba");
?>
Musim dat snippet kolem celeho formulare v sablone tedy:
<?php
{snippet mujerrornippet}
{form mujform}
..inputy..
<div class="error-message" n:if="$form->hasErrors()">
<div class="alert alert-danger" role="alert" n:foreach="$form->errors as $error">{$error}</div>
</div>
{/form}
{/snippet}
?>
Pokud to mam takto tedy obalen komplet cely formular snippetem vse funguje OK. ALe tim padem se zmeni DOM celeho formulare a prestanou fungovat jQuery naseptavace ktere mam navesene na inputy. Kdyz tedy dam snippet jen kolem error hlasky v sablone viz nize. Tak mi to hlasi undefined variable $form.
<?php
{form mujform}
..inputy..
{snippet mujerrornippet}
<div class="error-message" n:if="$form->hasErrors()">
<div class="alert alert-danger" role="alert" n:foreach="$form->errors as $error">{$error}</div>
</div>
{/snippet}
{/form}
?>
Existuje tedy neajke jine reseni jak tohle udelat. Nebo spise proc se nemuzou vypsat pouze chyby a musi se invalidovat komplet cely formular a tim tedy zmenit DOM celeho formulare?
Diky za info
Editoval balicekt (22. 4. 2018 22:21)
- balicekt
- Člen | 52
Zdeno1981 napsal(a):
Ahoj @balicekt,
zkus přes render poslat ten parametr ‚form‘ do šablony
<?php $this->template->form = $this['factory']; // Sem zadej svůj název továrničky ?>
takhle to řeším já, když mám obalené snipetem message errory u formulářů.
Diky tohle funguje, sice se mi to reseni moc nelibi, ale lepsi nez vyuzivat misto toho flashmessages :)
- Šaman
- Člen | 2664
balicekt napsal(a):
… tobe to funguje se snippetArea?
Funguje. Používám to na závislé inputy. Nette 2.4. Nejsou už potřeba
hacky s předáváním $_control
a $_form
apod.
Je potřeba invalidovat celou textareu a pak teprve snippet, který chceš
překreslit. (Textarea slouží k tomu, abys označil další kód, který je
nutný k úspěšnému překreslení snippetu. Takže potřebuješ $form, abys
mohl načíst jeho chyby. Ale vykreslovat budeš jen ty chyby.)
Dále je nutné mít obsluhu úspěšného i chybového odeslání a v ní ty
chyby překreslit.
Posílám ukázku se závislými inputy. U tebe to bude jednodušší,
nepotřebuješ ten JS a handleInvalidateTestForm
. Ale jinak to bude
podobné.
<?php
namespace App\Presenters;
use Nette\Application\UI\Form;
class DependentInputsPresenter extends BasePresenter
{
var $countries = ['cz' => 'Česká Republika', 'sk' => 'Slovenská republika'];
var $cities = [
'cz' => ['jbc' => 'Jablonec nad Nisou', 'lbc' => 'Liberec', 'pha' => 'Praha'],
'sk' => ['ko' => 'Košice', 'po' => 'Poprad']
];
protected function createComponentTestForm($name)
{
$form = new Form($this, $name);
$form->getElementPrototype()->addAttributes(['class' => 'ajax', 'novalidate' => 'novalidate']);
$form->addSelect('country', 'Země:', $this->countries)
->setAttribute('data-link', $this->link("invalidateTestForm!"))
->setPrompt('- vyberte zemi -')
->setRequired('vyberte zemi');
$cities = $form['country']->value ? $this->cities[ $form['country']->value ] : [];
$form->addSelect('city', 'Město:', $cities)
->setPrompt('- vyberte město -')
->setRequired('vyberte město');
$form->addSubmit('ok', 'Odeslat');
$form->onSuccess[] = [$this, 'testFormSuccess'];
$form->onError[] = [$this, 'testFormError'];
return $form;
}
public function testFormSuccess(Form $form, $values)
{
if ($this->isAjax()) {
$this->flashMessage('Data odeslána: ' . implode(', ', array_values($form->getValues(TRUE))) . '.');
// bdump('onSuccess ajax');
$this->redrawControl('flashMessages');
$this->redrawControl();
}
else {
$this->flashMessage('Data odeslána: ' . implode(', ', array_values($form->getValues(TRUE))) . '.');
// bdump('onSuccess no-ajax');
$this->redirect('this');
}
}
public function testFormError(Form $form)
{
if ($this->isAjax()) {
$this->flashMessage('Data nebyla odeslána: ' . implode(', ', array_values($form->getValues(TRUE))) . '.');
// bdump('onError ajax');
$this->redrawControl('flashMessages');
$this->redrawControl('testFormArea');
$this->redrawControl('form-errors');
}
else {
$this->flashMessage('Data nebyla odeslána: ' . implode(', ', array_values($form->getValues(TRUE))) . '.');
// bdump('onError no-ajax');
$this->redirect('this');
}
}
public function handleInvalidateTestForm($country)
{
if( in_array($country, array_keys($this->countries)) ) {
$this['testForm']['city']->setItems($this->cities[$country]);
}
else {
$this['testForm']['city']->setItems([]); # uživatel vybere prompt (nulovou) hodnotu
}
$this->redrawControl('testFormArea');
$this->redrawControl('inputCity');
}
}
?>
{block title}Závislé inputy{/block}
{block content}
{snippetArea testFormArea}
{form testForm}
{snippet form-errors}
{var $form = $control['testForm']}
<ul class="errors" n:if="$form->hasErrors()">
<li n:foreach="$form->errors as $error">{$error}</li>
</ul>
{/snippet}
<table>
<tr>
<th>{label country}</th>
<td>{input country}</td>
</tr>
<tr>
<th>{label city}</th>
<td>{snippet inputCity}{input city}{/snippet}</td>
</tr>
<tr>
<th></th>
<td>{input ok}</td>
</tr>
</table>
{/form}
{/snippetArea}
{/block content}
{block scripts}
<script>
$(function () {
var link = $('#frm-testForm-country').data('link');
$('#frm-testForm-country').on('change', function () {
$.nette.ajax({
url: link,
data: {
'country': $('#frm-testForm-country').val()
}
});
});
});
</script>
{/block scripts}
Editoval Šaman (23. 4. 2018 12:05)
- Šaman
- Člen | 2664
Aha, tak na to už jsem zapomněl. Myslel jsem, že tyhle hacky už nejsou
potřeba, ale když to tam mám, tak asi jo. Hrál jsem si s tím docela
dlouho, abych nemusel předávat nic do šablony a zároveň aby mi fungovaly
flashmessages, errory a závislé inputy.
Tak aspoň že sis to tam našel :)
- Šaman
- Člen | 2664
Není to jedno, pokud máš víc formulářů.
Ano, snippetArea
v tomto případě není nutná (i když
teoreticky by měla stačit ta snippetArea a ne tenhle hack). Když si to ale
načteš v šabloně, tak:
- Nezatěžuješ presenter tím, že tohle ještě snippetArea neumí. Až to bude umět, stačí upravit šablonu.
- Ale hlavně v případě více formulářů si v té šabloně načteš do
lokální proměnné
$form
vždy ten aktuální formulář (není úplně čisté ho volat jménem, ale vzhledem k tomu, že to samé jméno se používá i dva řádky nad tím, tak to snad tak nevadí).