Odesílání formulářů přes AJAX
- Panda
- Člen | 569
Protože tuto vlastnost (zatím) formuláře nemají, rozhodl jsem se podělit se o mé řešení, třeba se to někomu bude hodit…
Řešil jsem to přes rozšíření třídy AppForm
, ve které
překryji metodu RenderBegin
tak, aby se do onsubmit
dostalo volání AJAXu (a současně fungovala validace formuláře), a
přidání 2 metod do ‚objektu‘ nette
v nette.js
.
Řešení nepodporuje inputy s obrázkem, nepovažoval jsem je za
důležité.
Třída AjaxAppForm
:
class AjaxAppForm extends AppForm
{
/** @var bool Use AJAX for the form submission? */
public $useAjax = TRUE;
/** @var InstantClientScript Overrides original $js, which is private and cannot be used in derived classes */
private $js;
/**
* Renders form's start tag, enables AJAX
*/
public function renderBegin()
{
$this->js = new InstantClientScript($this);
$this->js->enable();
$element = $this->getElementPrototype();
if ($this->useAjax) {
if (empty($element->attrs['onsubmit']))
$element->onsubmit = 'return !nette.formAction(this, event);';
else
$element->onsubmit .= ' && !nette.formAction(this, event);';
}
echo $element->startTag();
}
/**
* Renders the rest of the form.
* This method must be overriden, because original $js is private
*
* @return void
*/
public function renderEnd()
{
echo $this->getElementPrototype()->endTag();
$this->js->renderClientScript();
}
}
Zde by možná stálo za uvážení, zda vlastnosti třídy Form jako je
$element
a $js
neudělat spíše protected
než private, ale to je na Davidovi…
2 metody do nette.js
:
formAction: function(form, event)
{
if (this.processing > 0) return true;
this.result = {};
// create new AJAX request
this.initAjax();
if (!this.ajax) return false;
var sender = document.activeElement || event.explicitOriginalTarget;
var action = form.action;
action += (action.indexOf('?') == -1) ? '?' : '&';
if (typeof(this.state) === 'object') {
action += this.buildQuery(this.state, '', '');
}
// create process indicator
try {
var img = document.getElementById(this.spinnerId);
if (sender && img) {
this.spinner = img.cloneNode(true);
this.spinner.style.display = 'inline';
sender.parentNode.insertBefore(this.spinner, sender.nextSibling);
}
} catch (e) {
}
try {
var url = action + '-r=' + Math.random();
var query = this.buildFormQuery(form, sender);
this.ajax.open("POST", url, true);
this.ajax.setRequestHeader("X-Requested-With", "XMLHttpRequest");
this.ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
this.ajax.onreadystatechange = function() { nette.ajaxHandler(); }
this.ajax.send(query);
this.processing = 1;
return true;
} catch (e) {
return false;
}
},
buildFormQuery: function(form, sender)
{
var s = '';
var amp = '';
for (var i in form.elements) {
switch (form.elements[i].tagName) {
case 'INPUT':
switch (form.elements[i].type) {
case 'text':
case 'password':
case 'hidden':
s += amp + encodeURIComponent(form.elements[i].name) +
"=" + encodeURIComponent(form.elements[i].value);
break;
case 'checkbox':
case 'radio':
if (form.elements[i].checked)
s += amp + encodeURIComponent(form.elements[i].name) +
"=" + encodeURIComponent(form.elements[i].value);
break;
}
break;
case 'TEXTAREA':
s += amp + encodeURIComponent(form.elements[i].name) +
"=" + encodeURIComponent(form.elements[i].value);
break;
case 'SELECT':
s += amp + encodeURIComponent(form.elements[i].name) +
"=" + encodeURIComponent(form.elements[i].options[form.elements[i].selectedIndex].value);
break;
}
amp = '&';
}
if (sender != null) {
s += '&' + encodeURIComponent(sender.name) + '=' + encodeURIComponent(sender.value);
}
return s.replace(/%20/g, '+');
}
V případě přidávání do nette.js
pozor na čárky –
v JavaScriptu jsou objetky v podstatě jen seznamy členů a metod oddělené
čárkami, takže pokud to například budete přidávat na konec celého
objektu, musíte ještě přidat čárku za tělo buildQuery
.
Určitě by to šlo udělat nějak lépe, ale myslím, že jako řešení do doby, než se nové Forms skamarádí s AJAXem, to stačí.
- David Grudl
- Nette Core | 8218
Od revize 63 je potřeba řešení upravit tak, aby se
rozšířila/vytvořila třída IFormRenderer a
nastavit $form->setRenderer($myRenderer)
- Jod
- Člen | 701
Rozšírený renderer:
<?php
class AjaxRenderer extends ConventionalRenderer
{
public $useAjax = true;
public function renderBegin()
{
$this->counter = 0;
foreach($this->form->getControls() as $control)
$control->setOption('rendered', FALSE);
$element = $this->form->getElementPrototype();
if ($this->useAjax)
if (empty($element->attrs['onsubmit']))
$element->onsubmit = 'return !nette.formAction(this, event);';
else
$element->onsubmit .= ' && !nette.formAction(this, event);';
return $element->startTag();
}
}
?>
Potom stačí na inštancii Form zavolať metódu setRenderer():
<?php
$renderer = new AjaxRenderer();
$form->setRenderer($renderer);
?>
Funguje na v.0.8 rev.106
Editoval Jod (12. 11. 2008 0:02)
- Ola
- Člen | 385
Nefunguje, mám stejnej problém jako když sem si to ubastlil sám :-/ Formulář se prostš neodešle potom, co tam přidám nette.js … bez něj se odešle, ale překreslí se celá stránka .. Nějakej větší sample by nebyl? Mam pocit, že prostě něco dělám blbě .. :/
EDIT: VŠE VYŘEŠEŠNO, MOC DÍKY!
Editoval Ola (12. 11. 2008 22:20)
- krajaac
- Člen | 45
Zdravim, zkousel jsem kod od Pandy s upravou od Joda(Jody?). Funguje to bez problemu az na jednu vec: kdyz potrebuju form odeslat ne pres SubmitButton, ale pri zmene na SELECTU. Pak se form sice odesle, ale ne AJAXove (standartne se znovu nactenim cele stranky).
Udalost na SELECTU jsem nastavil podle prikadu ve vlakne onClick(change) na selectboxu takto:
<?php
// FORM
$form = new Form('selectForm');
$form->addSelect('name', 'label', $records)
->controlPrototype->onChange('submit();');
$form->addSubmit('submit_name', 'submit_label')
->setValidationScope(FALSE);
// SUBMIT
$form->onSubmit[] = array($this, 'handleSelectNode');
// CUSTOM RENDERING
$form->setRenderer(new AjaxRenderer());
?>
Muzete mi nekde poradit, jak nastavit select box, aby se pri zmene cely form odeslal AJAXove? v JS celkem plavu, pokud je potreba neco upravit tam, jsem rad za kazdou radu. :)
Editoval krajaac (17. 1. 2009 19:04)
- krajaac
- Člen | 45
VYŘEŠENO:
Po přečtení vlánka Odeslani formulare pomoci selectu? mě trochu osvítilo a zkusil jsem následující konstrukci:
<?php
// PREPARE FORM
$form = new Form('selectForm');
$form->addSelect('name', 'label', $records)
//->controlPrototype->onChange('submit();');
->controlPrototype->onChange('this.form.onsubmit();');
$form->addSubmit('submit_name', 'submit_label')
->setValidationScope(FALSE);
// SUBMIT
$form->onSubmit[] = array($this, 'handleSelectNode');
// CUSTOM RENDERING
$form->setRenderer(new AjaxRenderer());
?>
Díky tomu, že se nad formulářem nezavolá klasický submit, ale kód,
který je v atributu onsubmit
:
<form onsubmit="return !nette.formAction(this, event);" method="post" action="">
tak se celý form odešle AJAXově při změně na SELECTu.
Editoval krajaac (19. 1. 2009 13:01)
- David Grudl
- Nette Core | 8218
Změnil jsem to i v odkazovaném threadu – místo onChange
by mělo být spíš onchange
- lopasovsky
- Člen | 17
Ešte doplním: v Internet Exploreri nefunguje JavaScriptové iterovanie prvkami formulára:
for (var i in form.elements) {
takže daný riadok z kódu (v buildFormQuery) treba nahradiť nasledujúcim:
for (var i = 0; i < form.elements.length; i++) {
- PetrP
- Člen | 587
lopasovsky napsal(a):
Ešte doplním: v Internet Exploreri nefunguje JavaScriptové iterovanie prvkami formulára:
for (var i in form.elements) {
Nekoukal jsem přímo na zde zmiňovaný kód, ale toto funguje v IE6.
Dokonce i když se nejedná o array.
var form = {elements: ['a','b','c']};
for (var i in form.elements) {
alert(i+' '+form.elements[i]);
}
var form = {elements: {a:'b'}};
for (var i in form.elements) {
alert(i+' '+form.elements[i]);
}
Možná je ale myšleno něco jiného, popřípadě jina verze IE ;]
- Ondřej Mirtes
- Člen | 1536
Řeším teď podobný problém – mám select box, v něm seznam měsíců a v komponentě metodu handleMonth, která určuje, jaký měsíc se vykreslí a invaliduje oblast se články z minulého vybraného měsíce. Potřebuji tedy AJAXově odeslat ten formulář – do jeho události onsubmit nějak dostat {ajaxlink}, který odešle signál, jaký měsíc si uživatel vybral. A zároveň v případě nepřítomnosti Javascriptu, přidat k tomu selectboxu nějaké submitovací tlačítko, které zařídí, že při klasickém submitování formuláře se dojde k tomu samotnému výsledku jako přes AJAX (pro což bude hádám stačit dát do action formuláře správný link a správně pojmenovat <select> – aby se při odeslání methodou post vytvořil stejný link na výsledek jako v případě odeslání signálu přes AJAX).
Zatím mám toto:
<form class="monthinator" action="{link month ?}" onsubmit='{ajaxlink month '?vybraný option?'}' method="post"><fieldset>
<legend>Výběr měsíce</legend>
<select name="monthinator" onchange="this.form.onsubmit();">
{foreach $months as $month}
<option value="{$iterator->getCounter()}">{$month}</option>
{/foreach}
</select>
</fieldset></form>
- Honza Marek
- Člen | 1664
Možná zkus toto. Jestli jsem to dobře pochopil, tak potřebuješ prostě odeslat formulář po změně selectu.
Takže by javacript (s jQuery) vypadal asi nějak takto:
<script>
// spustit po načtení celého htmlka stránky
$(function () {
// navěsit funkci po změně
$("css selektor k tvému selectu").change(function () {
// ajaxové odeslání formuláře
$(this.form).netteAjaxSubmit();
});
// a schovat tlačítko
$("css selektor k tlačítu").hide();
});
</script>
- Ondřej Mirtes
- Člen | 1536
On se mi po změně odešle, v tom není problém, ale nevím, jak mám předat komponentě signál – value vybraného <option> z toho selectu…
- Honza Marek
- Člen | 1664
Co zavolat tu handle funkci komponenty přímo v nějaké onSubmit funkci formuláře?
- Ondřej Mirtes
- Člen | 1536
Problém je, že já netuším jak. Přece když dám <form onsubmit=„{ajaxlink month}“ …>, tak se nezavolá handleMonth se správným předaným parametrem…
Co se týče Javascriptu, potřebuju úplně dovést za ručičku k cíli :( Ajax v PHP a snippety jsem pochopil, vytvořil jsem si na tom už dvě funkční komponenty, ale v tomhle případě si nevím rady. Potřebuji zkrátka zavolat handleMonth($month) v komponentě, kde $month bude value z vybraného <option>.
Nepochopil jsem, jak mi s tím má pomoct „nette.js s jQuery“. Nebo je to „řešítko“ právě na tenhle případ? Ale stejně nevím, jak ho implementovat a s jakými ho volat parametry…
- Ondřej Mirtes
- Člen | 1536
Uff, tak jsem nejspíš pokročil.
Mám následující kód (render v Controlu):
$this->form = new Form('addCommentForm');
$this->form->addText("name", "Jméno", "10", "32");
$this->form->addTextArea("text", "text", "70", "5");
$this->form->addSubmit("ok", " ")->getControlPrototype()->onclick[] = "this.form.onsubmit();";
$this->form->onSubmit[] = array($this, 'handleAddComment');
$this->form->setRenderer(new AjaxRenderer());
V template z toho vznikne (kouknul jsem, co mi vygeneruje samotný NForms a pak jsem to ručně okopíroval, vím, prasárna – nevěděl jsem, jak si poradit s napasováním formuláře do vlastního HTML kódu, NForms mi generovalo nějaké tabulky a já to potřeboval napasovat do těchto divů…):
<form action="" method="post" onsubmit="return !nette.formAction(this, event);">
<fieldset><legend>Komentáře</legend>
<div class="heading">
<h3 class="left">Komentáře</h3>
<div class="right">
<label for="frmaddCommentForm-name">Jméno</label>
<input type="text" maxlength="32" name="name" id="frmaddCommentForm-name" value="" />
<input type="submit" onclick="this.form.onsubmit();" name="ok" id="frmaddCommentForm-ok" alt="OK" value=" " />
</div>
</div>
<div class="text">
<textarea cols="70" rows="5" name="text" id="frmaddCommentForm-text"></textarea>
<p>Komentáře podporují <a href="https://texy.info/cs/syntax">Texy!</a> syntaxi.</p>
<p>Např.: "text odkazu":odkaz; <strong>**tučně**</strong>; <em>*kurzíva*</em></p>
</div>
</fieldset></form>
Po klepnutí na submit mi Firebug zaznamená nějaký POST požadavek.
Z příkladu jsem pochopil, že po tom odeslání už převezme kontrolu
metoda handleAddComment. Jenže nevím, jestli má přijímat nějaký parametr
($form
?) a nefunguje mi (zkouším v ní invalidovat Control a
Firebug stejně nezaznamenává nějaké načítání, ten POST požadavek má
60 bajtů).
POST fungujícího AJAXu se mi odkazuje na tuto adresu:
test?poll-vote=2&do=poll-vote&-r=0.1446965222317057
Kdežto ten od toho formuláře vygeneruje adresu bez názvu signálu:
test?-r=0.20044537208007351&=&name=dsadas&ok=%C2%A0&text=dsad
Co dělám špatně? :)
Editoval LastHunter (15. 2. 2009 11:29)
- Ondrej
- Člen | 110
LastHunter napsal(a):
Co dělám špatně? :)
Form zadne signaly sam o sobe nezpracovana. Pokud mu chces vnutit signal do
tveho controlu, tak mu jen nastav do action pres
$this->link(‚signal‘)
V metode handleAddComment() mas pristup ke vsem FormControlum a jeho hodnotam.
Nekde predtim ale musis zavolat $form->isSubmitted(), aby si formular nacetl
hodnoty z requestu.
- Ondřej Mirtes
- Člen | 1536
Nemůžu to přece dávat do action, když to chci odesílat AJAXově (k čemu by pak byla celá ta třída ze začátku tohoto vlákna?). Toto mi tedy taky nefunguje (vyhodí to server error):
<form action="" method="post" onsubmit="{ajaxlink addComment}">
- Ondřej Mirtes
- Člen | 1536
Uff, začínám v tom mít bordel.
Když definuju v ArticleControl ten formulář až v renderArticle, musím pak tu jeho definici zkopírovat taky do toho handleComment? Mám ho sice jako objekt třídy, ale ten se nastavuje až v renderArticle a to se volá až po handle… Zkusil jsem to a padá mi tam Apache :D
Ukážu kód:
class Article extends BaseControl {
var $form;
var $article;
public function __construct($presenter) {
parent::__construct($presenter, "a");
}
public function handleComment() {
$this->invalidateControl("komentare");
if ($this->form->isSubmitted() && $this->form['ok']->isSubmittedBy() && $this->form->isValid()) {
$model = new ArticleModel("news");
$model->addComment($article->id, $this->form["name"], $this->form["text"]);
}
}
public function renderArticle($article) {
$template = parent::createMyTemplate(dirname(__FILE__) . '/' . 'Article' . '.phtml');
$authorsModel = new StaffModel("staff");
$template->article = $article;
$this->article = $article;
$template->authors = $authorsModel->getStaff();
$model = new ArticleModel("news");
$template->model = $model;
$template->comments = $model->getComments($article->id);
$this->form = new Form('addCommentForm');
$this->form->addText("name", "Jméno", "10", "32");
$this->form->addTextArea("text", "text", "70", "5");
$this->form->addSubmit("ok", " ")->getControlPrototype()->onclick[] = "this.form.onsubmit();";
$this->form->onSubmit[] = array($this, 'handleComment');
$this->form->setRenderer(new AjaxRenderer());
$template->form = $this->form;
$template->render();
}
}
Když to mám takhle definované, tak mi to hlásí
Call to a member function isSubmitted() on a non-object
, protože
v tu chvíli tam ten form ještě není :( A Control nemá žádné
prepareView, do kterého bych to napral a zaregistrovalo by se to ještě před
obsluhou signálu.
(Stejný problém tam je i s $article->id, také v tu chvíli ještě
neexistuje).
Kam tedy nacpat definici toho formuláře, aby ho ten handleComment už znal + to samé s $article?
Editoval LastHunter (15. 2. 2009 13:34)
- Ondrej
- Člen | 110
LastHunter napsal(a):
Kam tedy nacpat definici toho formuláře, aby ho ten handleComment už znal + to samé s $article?
Ja definici formulare davam do konstruktoru. Ale kdyby David udelal nejaky zivotni cyklus pro komponenty, tak bych se nezlobil :) Viz. https://forum.nette.org/…iewtopic.php?…
Neni mi jasne kde definujes $this->article, pravdepodobne ho predavas z presenteru, takze k dispozici musi byt. (v handleComment mas preklep, ma tam byt $this->article)
Editoval Ondrej (15. 2. 2009 14:03)
- Ondřej Mirtes
- Člen | 1536
To je hroznej porod :)
Už mi to funguje, až na to, že se mi to nepřekreslí (invalidace nezafunguje) :/ Zkrátka to už nevidím.
Signal handler (když do něj přidám echo, tak se to echo vypíše taky dvakrát, tudíž chyba není v modelu):
public function handleComment() {
if ($this->form->isSubmitted()) {
$model = new ArticleModel("news");
$values = $this->form->getValues();
$model->addComment($this->article->id, $values["name"], $values["text"]);
$this->invalidateControl();
}
}
Formulář (i když odkomentuju/zakomentuju tu onsubmit část, i když vypnu/zapnu javascript, furt se to odesílá 2×, chyba bude tedy někde v PHP, nejspíš):
<form action="{link comment}" method="post"<!-- onsubmit="return !nette.formAction(this, event); "-->>
<fieldset><legend>Komentáře</legend>
<div id="komentare" class="heading">
<h3 class="left">Komentáře</h3>
<div class="right">
<label for="frmaddCommentForm-name">Jméno</label>
<input type="text" maxlength="32" name="name" id="frmaddCommentForm-name" value="" />
<input type="submit" name="ok" id="frmaddCommentForm-ok" alt="OK" value=" " />
</div>
</div>
<div class="text">
<textarea cols="70" rows="5" name="text" id="frmaddCommentForm-text"></textarea>
<p>Komentáře podporují <a href="https://texy.info/cs/syntax">Texy!</a> syntaxi.</p>
<p>Např.: "text odkazu":odkaz; <strong>**tučně**</strong>; <em>*kurzíva*</em></p>
</div>
</fieldset></form>
Kód v presenteru:
public function prepareArticle($seo)
{
$model = new ArticleModel("news");
$this->template->articleControl = new Article($this->getPresenter());
$article = $model->getArticle($seo);
$this->template->articleControl->article = $article;
}
Vykreslení komponenty v šabloně presenteru:
@{?$articleControl->renderArticle()}
Editoval LastHunter (15. 2. 2009 20:03)
- Ondřej Mirtes
- Člen | 1536
Jojo, je tam :) Updatnul jsem ten předchozí příspěvek o zdrojáky a fakt se stydím, že potřebuju takhle vodit za ručičku. Ve výsledku se ale ze mě snad stane pohotový Nette uživatel :)
- Jarda
- Člen | 25
ahoj, potřeboval bych poradit s problémem při odesílání formuláře ajaxem. Upravil jsem všechny soubory a třídy dle návodů – AjaxAppForm, AjaxRenderer, nette.js
Problém mám ten, že se mi formulář postne 2x – když koukám na firebug konzoli, tak tam v nette.js vyskočí výjimka. Bohužel se hned potom odešle form klasicky, takže se konzola vyčistí pro novou stránku (nepřišel jsem na to, jak ve firebugu trasovat) nicméně se mi podařilo chybu vyfotit a hlásí to následující:
[Exception... "Component returned failure code: 0x80040111(NS_ERROR_NOT_AVAILABLE)
[nsIXMLHttpRequest.statusText]" nsresult: "0x80040111(NS_ERROR_NOT_AVAILABLE)"
location: "JS frame :: http://.../nette.js :: anonymous :: line 186" data: no]
- this.onError(this.ajax.status + " " ...Text + "\n\n" + this.ajax.responseText);
řádek funkce formAction: function(form, event)
v nette.js,
který vyvolal výjimku obsahuje:
<script>
try {
var url = action + '-r=' + Math.random();
var query = this.buildFormQuery(form, sender);
this.ajax.open("POST", url, true);
this.ajax.setRequestHeader("X-Requested-With", "XMLHttpRequest");
this.ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
this.ajax.onreadystatechange = function() { nette.ajaxHandler(); }
tady to padne-> this.ajax.send(query);
this.processing = 1;
return true;
}
</script>
hlásí to sice chybu, ale požadavek se odešle a událost handleAddItem() se provede a následně v důsledku chyby při ajaxu se provede klasicky, tudíž se mi položka přidá 2×.
Budu moc vděčný, když mi někdo dokáže poradit.
pro další informace přidávám i zdrojáky:
komponenta
<?php
class TDList extends Control
{
/** @var bool */
public $useAjax = true;
/** @persistent */
public $showAddForm = FALSE;
protected $tddata;
public function __construct()
{
parent::__construct();
require_once dirname(__FILE__) . '/../models/TDData.php';
$this->tddata = new TDData();
}
public function handleShowAddForm()
{
$this->showAddForm = $this->showAddForm ? false : true; //zobrazeni nebo skryti formuláře
$this->invalidateControl('addForm');
}
public function handleMoveUp($item_id){
$this->tddata->moveItemUp($item_id);
$this->invalidateControl('itemsList');
}
public function handleAddItem(){
$form = $this->getComponent("addItemForm");
if ($form->isSubmitted()) {
$formVals = $form->getValues();
$this->invalidateControl();
$this->handleShowAddForm();
$this->tddata->createItem(array("subject"=>$formVals["subject"]));
}
}
public function renderToDoList(){
$td_list = $this->tddata->getItemsList();
$template = $this->createTemplate();
$template->useAjax = $this->useAjax;
$template->setFile(dirname(__FILE__) . '/TDList.phtml');
$template->showAddForm = $this->showAddForm;
$template->td_list = $td_list;
$template->addItemForm = $this->getComponent("addItemForm");
$template->render();
}
protected function createComponentAddItemForm()
{
$form = new AjaxAppForm($this, $name);
$renderer = new AjaxRenderer();
$form->setRenderer($renderer);
$form->addText("subject", "Subject: ")
->addRule(Form::FILLED, 'Please enter a subject.');
$form->addSubmit('submit1', 'Add Item');
$form->onSubmit[] = array($this, 'handleAddItem');
}
}
?>
šablona komponenty
<?php
{snippet addForm}
{if !$showAddForm}<a href="{link ShowAddForm}"{if $useAjax}onclick="return !nette.action(this)"{/if}>Přidat položku</a>{/if}
{if $showAddForm}
{!$addItemForm}
{/if}
{/snippet}
{snippet itemsList}
<ul>
{? $pos = 0;}
{foreach $td_list as $id=>$item}
<li>
{$id} {$item} {if $pos>0}<a href="{link MoveUp $id}"{if $useAjax}onclick="return !nette.action(this)"{/if}>↑ UP</a>{/if}
</li>
{? $pos++;}
{/foreach}
</ul>
{/snippet}
?>
@ v template view i layoutu mám.
Jen pro představu, co to má dělat. Snažím se udělat seznam položek, u kterých mohu měnit pořadí přesouváním položky o jednu výš a přidávat další položky pomocí jednoduchého formuláře, který se zobrazí až po kliknutí na odkaz pro zobrazení formu. Vše funguje hezky ajaxově, kromě přidání položky formulářem.
A ještě jedna a poslední záhada, kterou pozoruji. Při načtení formuláře je sice připojen js pro validaci formuláře, ale js ho nezvaliduje. Když odešlu prázdný formulář, validuje až server, ale když se pokusím o znovuodeslání špatně vyplněného formu, tak už vyskočí js alert. Je to zkrátka samá záhada :).
- PHP 5.2.6
- Nette Framework 0.8 (revision 220 released on 2009/02/25 19:45:34)
- Jarda
- Člen | 25
díky za tip! sice to úplně nepomohlo, ale aspoň jsem se kousek pohnul a našel jsem zdroj problému.
- když jsem zaimplementoval jquery, tak se to stále ukládalo 2×, ale když jsem nejprve zkusil odeslat prázdný form, server provedl validaci, vypsal hlášku a znovu zobrazil formulář. Pak už to takhle jednou zvalidovaný formulář odesílalo pouze ajaxově, ale nevyskakoval alert o prázdném poli. Když jsem něco zadal, položka se ajaxově 1× přidala a formulář zmizel – tudíž očekávané chování, ale teprve u servervem zvalidovaného formuláře :(
- to mě přivedlo k tomu, abych z formuláře zkusil odebrat validační pravidlo a hle – formulář funguje ajaxově jak má. Jak přes jquery, tak i klasicky jen s nette.js.
Otázkou však zůstává, jak zaonačit, aby fungovala validace před odesláním formuláře? Poradí, prosím, někdo?
- Jarda
- Člen | 25
hurrá, tak se mi to podařilo rozchodit… po celodenním seznamování se s jQuerry to lítá jak má vč. validace formuláře pomocí js.
Nakonec jsem skončil u následující sestavy:
Pro generování formuláře používám standardní AppForm a defaultní
renderer, tak jak je v distribuci.
Pro vytváření ajaxových odkazů v šabloně používám pouze
{if $useAjax}class="ajaxlink"{/if}
Pro zajaxovatění používám jQuery plugin od Honzy M. Díky za něj!
K tomu jsem si vytvořil (tedy spíše vykombinoval) tidyUp fci, která se volá při načtení dokumentu a po výměně snipetů, což je důležité, aby případně nově došlé klasické formuláře a odkazy zase zajaxovatěly.
<script>
var tidyUp = function(){
$(function () {
// přiřaď všem současným i budoucím odkazům s třídou ajaxlink po kliknutí tuto funkci
$("a.ajaxlink").live("click", function () {
$.netteAjax(this.href);
return false;
});
});
$(function () {
// odeslání na formulářích
$("form").submit(function () {
$(this).netteAjaxSubmit();
return false;
});
// odeslání pomocí tlačítek
$("form :submit").click(function () {
$(this).netteAjaxSubmit();
return false;
});
});
//tohle je taková moje vybastlenost pro zobrazení selectového
//formuláře a jeho odeslání po změně hodnoty
//nemá to obecné použití, nechávám pro inspiraci
//takto mi funguje odesílání při změně selectboxu
$("a.status").click(function(){
$(this).hide();
$($(this).attr("href")).show();
$($(this).attr("href")+" select").change(function () {
// ajaxové odeslání formuláře
$(this.form).netteAjaxSubmit();
});
});
//ostatní drobnosti, které potřebuji udělat při úklidu
$('.hidden').hide();
$("table tr:even").addClass("evenrow");
}
</script>
Omluvte, prosím, tento zápis. Mám takové tušení, že to není úplně
jQuery košér,
že tam možná i něco přebývá, nebo je tam zbytečné. V jQuery jsem
dneska dělal proprvé.
Nicméně tuto fci volám při načtení dokumentu a při dokončení ajaxového požadavku:
<script>
$(function () {
$(document).ajaxStop(function () {
tidyUp();
});
});
</script>
Tak třeba to někomu pomůže, tak jako mně zde uvedené příklady, ze kterých se mi podařilo postupně vyzobat fungující řešení. Díky všem!
PS: nevím, v čem je chyba, že texy uvedlo oba kody v jednom bloku a zařadilo do toho i text, který do toho nepatří…
- Jarda
- Člen | 25
máš pravdu… na to tvé řešení jsem koukal… ale v jQuery zatím dost plavu a nepodařilo se mi to funkčně naimplementovat, i když je to určitě čistší řešení, než jsem použil…
Na fuknci live() jsem také koukal, že má umět obstarat i následně vytvořené elementy, ale právě bohužel neumí obsloužit vše, no časem to snad trochu učešu a případně postnu… ted jsem rád, že jsem rád :) když se mi to po celodenním úsilí podařilo zprovoznit, prostě euforie :D