AJAX formulář s dynamickým počtem řádků… zase
- pako3
- Člen | 18
Tak už jsem se opět zasekl, budu vděčný za každou radu.
Mám požadavek udělat formulář, kde půjde libovolně přidat nebo smazat
řádek, prohledal jsem všechny možné thready tady na foru a dospěl jsem do
této fáze:
- Mám formulář v továrničce, který si vytvoří řádky podle hodnoty uložené v session.
- při přidávání řádku, se zvýší hodnota v session a formulář by se měl překreslit
Jenže, když kliknu poprvé na ‚Přidat řádek‘, tak se s formulářem
nic nestane, hodnota v session se zvýší ⇒ jakoby se nezavolala
továrnička. Když klikám dál, tak už se řádky přidávají, ale pořád
ten jeden chybí. Pokud stránku obnovím, tak se zobrazí i ten
chybějící… což je dost nemilé.
Možná mi něco důležitého uchází… nevím, každopádně už nevím co
s tím.
takhle nejak vypada tovarnicka:
<?php
public function createComponentShopForm()
{
$namespace = Environment::getSession('products');
if( !isset($namespace->products))
{
$namespace->products = 1;
}
$form = new AppForm;
$form->getElementPrototype()->class('ajax');
$form->addSubmit('odesli', 'Pokračovat');
$form->addSubmit('storno', 'Zrušit')->setValidationScope(NULL);
$form->addSubmit('addRow', 'Přidat další řádek')->setValidationScope(NULL);
$default = array();
for ( $i = 1; $i <= $namespace->products; $i++ )
{
$form->addGroup('Produkt č.'.$i.':');
...
$default['count'.$i] = 1;
}
$form->setDefaults($default);
$form->onSubmit[] = callback($this, 'processShopForm');
return $form;
}
?>
A tady je invalidace formulare:
<?php
public function processShopForm($form)
{
if( $form['odesli']->isSubmittedBy())
{
...
$this->redirect('this');
}
elseif ( $form['addRow']->isSubmittedBy())
{
$namespace = Environment::getSession('products');
if ( !isset($namespace->products))
{
$namespace->products = 1;
}
else
{
$namespace->products+=1;
}
if( !$this->isAjax())
{
...
$this->redirect('this');
}
else
{
...
$this->invalidateControl('shop');
}
}
else
{
...
$this->redirect('Default:');
}
}
?>
Děkuji všem :)
- Ola
- Člen | 385
Oh, myslím, že vím proč tomu tak je. Ta továrnička se zavolá, ale již při volání signálu submit, tj. příliš brzy. Pak se form připojí k presenteru a zavolá se signál submit, který zvýší hodnotu session (pozdě).
Zkus po tom zvýšení session zavolat
unset($presenter["shopForm"]);
Editoval Ola (10. 5. 2010 19:53)
- pako3
- Člen | 18
Hmm, takže v tom je problém…
Když tam dám unset(…), tak už se ten formulář neinvaliduje… asi bych ho měl pak do šablony poslat znova, pokud to správně chápu?
Edit: ještě mě napadlo, zkusit „Přidat řádek“ dát mimo ten formulář, jako normální odkazy, aby posílaly ajaxové signály. Ale to nevím jestli by byla správná cesta, chovalo se to víceméně stejně. :D
Díky ;)
Editoval pako3 (10. 5. 2010 22:57)
- pako3
- Člen | 18
Děkuji ‚Ola‘ za pomoc, je to vyřešeno.
Takže kdyby někdo měl stejný problém:
zrušil jsem widget v šabloně a vypisuji formulář normálně:
<?php
{!$shopForm}
?>
a při odeslání požadavku na přidání řádku se formulář vymaže z presenteru jak psal Ola a znovu vytvoří:
<?php
unset($presenter['shopForm']);
//... zvysit pocet radku v session
$this->template->shopForm = $this->createComponentShopForm();
?>
Už to šlape jak má, díky :)
- pako3
- Člen | 18
Nechtěl jsem zakládat nové téma, je to velmi podobný problém…
Mám takový jednoduchý editační formulářek, který se objeví po
kliknutí na ‚Upravit‘:
Tohle funguje naprosto v pořádku:
<?php
{snippet name2}
{if $editName === 1}
{widget editNameForm}
{else}
... vypíše normálně data
{/if}
{/snippet}
?>
A teď se uplně stejným postupem snažím docílit takového editačního seznamu, kde jsou vypsány položky a u každé je možnost ji smazat nebo upravit. Bez ajaxu to funguje pekně:
<?php
{snippet productTable}
<div><table>
<tr> ... nadpisy ... </tr>
{for $i=1; isset($data1['name'.$i]); $i++}
{if $editProduct == $i}
{widget editProductForm}
{else}
<tr> ... vypíše řádek s daty položky... </tr>
{/if}
{/for}
</table></div>
{/snippet}
?>
Ale s ajaxem to nejede. PHP strana se mi zdá ok, protože to vrátí JSON se správným obsahem ( ráno ho sem přidám ), ale editovaný řádek se, namísto zobrazení formuláře, nevykreslí vůbec. Takže vidím chybu na straně JS, ale bohužel nejsem s JS velký kamarád, takže bych poprosil někoho znalého o radu.
Používám klasicky jQuery, jquery.nette v0.2, jquery.ajaxform v0.1 a ajax.js s tímto obsahem:
<script>
$("a.ajax, .paginator a").live("click", function (event) {
event.preventDefault();
$.get(this.href);
});
/* AJAXové odeslání formulářů s třídou ajax */
$("form.ajax").live("submit", function () {
$(this).ajaxSubmit();
return false;
});
$("form.ajax :submit").live("click", function () {
$(this).ajaxSubmit();
return false;
});
</script>
Děkuji předem za jakékoli nápady :)
Editoval pako3 (21. 5. 2010 1:48)
- pako3
- Člen | 18
Zavináče by měly být ok, toto je celá šablona:
<?php
@{block #content}
<span> Hlavni nadpis</span>
<br />
<span> popis... </span>
<br />
{snippet flashmes}
{foreach $flashes as $flash}<div class="flash {$flash->type}">{$flash->message}</div>{/foreach}
{/snippet}
{snippet name2}
{if $editName === 1}
{widget editNameForm}
{else}
<div> ... vypíše data..</div>
{/if}
{/snippet}
<br />
<div>... nejake text ... </div>
<br />
{snippet productTable}
<div><table>
<tr> ... nadpisy...</tr>
{for $i=1; isset($data1['name'.$i]); $i++}
{if $editProduct == $i}
{var form[$i] => $presenter['editProductForm']}
{control $form[$i] begin}
... vypíše formulář
{control $form[$i] end}
{else}
<tr> ... vypíše řádek s daty ... </tr>
{/if}
{/for}
</table></div>
{/snippet}
{widget shopForm3}
?>
snippet ‚name2‘ funguje bez problemu…
snippet ‚productTable‘ se špatně aktualizuje.
Tady je JSON, který mi vrátí phpko:
{"state":[],"snippets":{"snippet--productTable":"<div><table>\n<tr><td>N\u00e1zev produktu<\/td><td>Specifikace produktu<\/td><td>Internetov\u00e1 adresa detailu zbo\u017e\u00ed (URL)<\/td><td>Po\u010det (ks)<\/td><td>Cena za kus ($)<\/td><td>Cena celkem ($)<\/td><\/tr>\n<form action=\"\/mailbox\/shop-for-me\/step-three\/?do=editProductForm-submit\" method=\"post\" id=\"frm-editProductForm\" class=\"ajax\" onsubmit=\"return nette.validateForm(this)\"><tr><td><label class=\"required\" for=\"frmeditProductForm-name\">N\u00e1zev produktu<\/label><br \/><input type=\"text\" class=\"text\" name=\"name\" id=\"frmeditProductForm-name\" value=\"sadwds\" \/><\/td><td><label class=\"required\" for=\"frmeditProductForm-specs\">Specifikace produktu<\/label><br \/><input type=\"text\" class=\"text\" name=\"specs\" id=\"frmeditProductForm-specs\" value=\"akwdoakd\" \/><\/td><td><label for=\"frmeditProductForm-count\">Po\u010det (ks)<\/label><br \/><input type=\"text\" class=\"text\" name=\"count\" id=\"frmeditProductForm-count\" value=\"1\" \/><\/td><\/tr>\n<tr><td><label class=\"required\" for=\"frmeditProductForm-url\">Internetov\u00e1 adresa detailu produktu (URL)<\/label><br \/><input type=\"text\" class=\"text\" name=\"url\" id=\"frmeditProductForm-url\" value=\"dawdw.ht\" \/><\/td><td><label class=\"required\" for=\"frmeditProductForm-price\">Cena za kus ($)<\/label><br \/><input type=\"text\" class=\"text\" name=\"price\" id=\"frmeditProductForm-price\" value=\"150\" \/><\/td><td><input type=\"submit\" class=\"button\" name=\"odesli\" id=\"frmeditProductForm-odesli\" value=\"Zm\u011bnit\" \/><\/td><\/tr>\n<\/form>\n<!-- Nette Form validator -->\r\n\r\n<script type=\"text\/javascript\">\/*<![CDATA[*\/var nette=nette||{};nette.getValue=function(a){if(a){if(!a.nodeName){for(var b=0,d=a.length;b<d;b++)if(a[b].checked)return a[b].value;return null}if(a.nodeName.toLowerCase()===\"select\"){b=a.selectedIndex;var c=a.options;if(b<0)return null;else if(a.type===\"select-one\")return c[b].value;b=0;a=[];for(d=c.length;b<d;b++)c[b].selected&&a.push(c[b].value);return a}if(a.type===\"checkbox\")return a.checked;return a.value.replace(\/^\\s+|\\s+$\/g,\"\")}};\nnette.getFormValidators=function(a){a=a.getAttributeNode(\"id\").nodeValue;return this.forms[a]?this.forms[a].validators:[]};nette.validateControl=function(a){var b=this.getFormValidators(a.form)[a.name];return b?b(a):null};nette.validateForm=function(a){var b=a.form||a,d=this.getFormValidators(b);for(var c in d){var e=d[c](a);if(e){b[c].focus&&b[c].focus();alert(e);return false}}return true};nette.toggle=function(a,b){if(a=document.getElementById(a))a.style.display=b?\"\":\"none\"};\/*]]>*\/<\/script>\r\n\r\n<script type=\"text\/javascript\">\r\n\/* <![CDATA[ *\/\r\n\r\nnette.forms = nette.forms || { };\r\n\r\nnette.forms[\"frm-editProductForm\"] = {\r\n\tvalidators: {\r\n\t\t\"name\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tval = nette.getValue(form[\"name\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit n\\u00e1zev produktu.\";\n\t\t},\r\n\t\t\"specs\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tval = nette.getValue(form[\"specs\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit specifikace produktu.\";\n\t\t},\r\n\t\t\"count\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tres = \/^-?[0-9]+$\/.test(val = nette.getValue(form[\"count\"]));\n\t\t\tif (!res) return \"Po\\u010det kus\\u016f mus\\u00ed b\\u00fdt \\u010d\\u00edseln\\u00fd.\";\n\t\t},\r\n\t\t\"url\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tres = \/^.+\\.[a-z]{2,6}(\\\/.*)?$\/i.test(val = nette.getValue(form[\"url\"]));\n\t\t\tif (!res) return \"\\u0160patn\\u00fd form\\u00e1t URL.\";\n\t\t\tval = nette.getValue(form[\"url\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit URL s detaily produktu.\";\n\t\t},\r\n\t\t\"price\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tval = nette.getValue(form[\"price\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit cenu.\";\n\t\t\tres = \/^-?[0-9]+$\/.test(val = nette.getValue(form[\"price\"]));\n\t\t\tif (!res) return \"Cena mus\\u00ed b\\u00fdt \\u010d\\u00edseln\\u00e1.\";\n\t\t}\r\n\t},\r\n\r\n\ttoggle: function(sender) {\r\n\t\tvar visible, res, form = sender.form || sender;\r\n\t}\r\n}\r\n\r\n\r\n\r\n\/* ]]> *\/\r\n<\/script>\r\n\r\n<!-- \/Nette Form validator -->\r\n\n<\/table><\/div>\n"}}
Dovolím si vytáhnout tady tento kousek, tohle je onen formulář, takže v JSONu se vrátí zprávně obsah jaký požaduji, ale nevykreslí se :(
<form action=\"\/mailbox\/shop-for-me\/step-three\/?do=editProductForm-submit\" method=\"post\" id=\"frm-editProductForm\" class=\"ajax\" onsubmit=\"return nette.validateForm(this)\">
<tr><td><label class=\"required\" for=\"frmeditProductForm-name\">N\u00e1zev produktu<\/label><br \/>
<input type=\"text\" class=\"text\" name=\"name\" id=\"frmeditProductForm-name\" value=\"sadwds\" \/><\/td>
<td><label class=\"required\" for=\"frmeditProductForm-specs\">Specifikace produktu<\/label><br \/>
<input type=\"text\" class=\"text\" name=\"specs\" id=\"frmeditProductForm-specs\" value=\"akwdoakd\" \/><\/td>
<td><label for=\"frmeditProductForm-count\">Po\u010det (ks)<\/label><br \/>
<input type=\"text\" class=\"text\" name=\"count\" id=\"frmeditProductForm-count\" value=\"1\" \/><\/td><\/tr>\n
<tr><td><label class=\"required\" for=\"frmeditProductForm-url\">Internetov\u00e1 adresa detailu produktu (URL)<\/label><br \/>
<input type=\"text\" class=\"text\" name=\"url\" id=\"frmeditProductForm-url\" value=\"dawdw.ht\" \/><\/td>
<td><label class=\"required\" for=\"frmeditProductForm-price\">Cena za kus ($)<\/label><br \/>
<input type=\"text\" class=\"text\" name=\"price\" id=\"frmeditProductForm-price\" value=\"150\" \/><\/td>
<td><input type=\"submit\" class=\"button\" name=\"odesli\" id=\"frmeditProductForm-odesli\" value=\"Zm\u011bnit\" \/><\/td><\/tr>\n
<\/form>
pokud stránku teď obnovím, tak se to zobrazí správně
- pako3
- Člen | 18
No server vrací to co má, aspoň myslím.
Tohle je odezva a vidím tam správně ten formulář:
{"state":[],"snippets":{"snippet--productTable":"<div><table>\n<tr><td>N\u00e1zev produktu<\/td><td>Specifikace produktu<\/td><td>Internetov\u00e1 adresa detailu zbo\u017e\u00ed (URL)<\/td><td>Po\u010det (ks)<\/td><td>Cena za kus ($)<\/td><td>Cena celkem ($)<\/td><\/tr>\n<form action=\"\/mailbox\/shop-for-me\/step-three\/?do=editProductForm-submit\" method=\"post\" id=\"frm-editProductForm\" class=\"ajax\" onsubmit=\"return nette.validateForm(this)\"><tr><td><label class=\"required\" for=\"frmeditProductForm-name\">N\u00e1zev produktu<\/label><br \/><input type=\"text\" class=\"text\" name=\"name\" id=\"frmeditProductForm-name\" value=\"sadwds\" \/><\/td><td><label class=\"required\" for=\"frmeditProductForm-specs\">Specifikace produktu<\/label><br \/><input type=\"text\" class=\"text\" name=\"specs\" id=\"frmeditProductForm-specs\" value=\"Specifikace\" \/><\/td><td><label for=\"frmeditProductForm-count\">Po\u010det (ks)<\/label><br \/><input type=\"text\" class=\"text\" name=\"count\" id=\"frmeditProductForm-count\" value=\"1\" \/><\/td><\/tr>\n<tr><td><label class=\"required\" for=\"frmeditProductForm-url\">Internetov\u00e1 adresa detailu produktu (URL)<\/label><br \/><input type=\"text\" class=\"text\" name=\"url\" id=\"frmeditProductForm-url\" value=\"srgdsrgv.th\" \/><\/td><td><label class=\"required\" for=\"frmeditProductForm-price\">Cena za kus ($)<\/label><br \/><input type=\"text\" class=\"text\" name=\"price\" id=\"frmeditProductForm-price\" value=\"150\" \/><\/td><td><input type=\"submit\" class=\"button\" name=\"odesli\" id=\"frmeditProductForm-odesli\" value=\"Zm\u011bnit\" \/><\/td><\/tr>\n<\/form>\n<!-- Nette Form validator -->\r\n\r\n<script type=\"text\/javascript\">\/*<![CDATA[*\/var nette=nette||{};nette.getValue=function(a){if(a){if(!a.nodeName){for(var b=0,d=a.length;b<d;b++)if(a[b].checked)return a[b].value;return null}if(a.nodeName.toLowerCase()===\"select\"){b=a.selectedIndex;var c=a.options;if(b<0)return null;else if(a.type===\"select-one\")return c[b].value;b=0;a=[];for(d=c.length;b<d;b++)c[b].selected&&a.push(c[b].value);return a}if(a.type===\"checkbox\")return a.checked;return a.value.replace(\/^\\s+|\\s+$\/g,\"\")}};\nnette.getFormValidators=function(a){a=a.getAttributeNode(\"id\").nodeValue;return this.forms[a]?this.forms[a].validators:[]};nette.validateControl=function(a){var b=this.getFormValidators(a.form)[a.name];return b?b(a):null};nette.validateForm=function(a){var b=a.form||a,d=this.getFormValidators(b);for(var c in d){var e=d[c](a);if(e){b[c].focus&&b[c].focus();alert(e);return false}}return true};nette.toggle=function(a,b){if(a=document.getElementById(a))a.style.display=b?\"\":\"none\"};\/*]]>*\/<\/script>\r\n\r\n<script type=\"text\/javascript\">\r\n\/* <![CDATA[ *\/\r\n\r\nnette.forms = nette.forms || { };\r\n\r\nnette.forms[\"frm-editProductForm\"] = {\r\n\tvalidators: {\r\n\t\t\"name\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tval = nette.getValue(form[\"name\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit n\\u00e1zev produktu.\";\n\t\t},\r\n\t\t\"specs\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tval = nette.getValue(form[\"specs\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit specifikace produktu.\";\n\t\t},\r\n\t\t\"count\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tres = \/^-?[0-9]+$\/.test(val = nette.getValue(form[\"count\"]));\n\t\t\tif (!res) return \"Po\\u010det kus\\u016f mus\\u00ed b\\u00fdt \\u010d\\u00edseln\\u00fd.\";\n\t\t},\r\n\t\t\"url\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tres = \/^.+\\.[a-z]{2,6}(\\\/.*)?$\/i.test(val = nette.getValue(form[\"url\"]));\n\t\t\tif (!res) return \"\\u0160patn\\u00fd form\\u00e1t URL.\";\n\t\t\tval = nette.getValue(form[\"url\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit URL s detaily produktu.\";\n\t\t},\r\n\t\t\"price\": function(sender) {\r\n\t\t\tvar res, val, form = sender.form || sender;\r\n\t\t\tval = nette.getValue(form[\"price\"]); res = val!='' && val!=\"\";\n\t\t\tif (!res) return \"Mus\\u00edte vyplnit cenu.\";\n\t\t\tres = \/^-?[0-9]+$\/.test(val = nette.getValue(form[\"price\"]));\n\t\t\tif (!res) return \"Cena mus\\u00ed b\\u00fdt \\u010d\\u00edseln\\u00e1.\";\n\t\t}\r\n\t},\r\n\r\n\ttoggle: function(sender) {\r\n\t\tvar visible, res, form = sender.form || sender;\r\n\t}\r\n}\r\n\r\n\r\n\r\n\/* ]]> *\/\r\n<\/script>\r\n\r\n<!-- \/Nette Form validator -->\r\n\n<\/table><\/div>\n"}}