Invalidace snippetu s formulářem zruší JS validaci
- cuga
- Člen | 210
Dělám teď jednoduchý průchod košíkem… po uživateli nevyžaduju přihlášení i v případě, že je již zaregistrovaný (stejně většinou zapomene heslo)… jako první položka formuláře je Email, na základě kterého dohledám data zadaná při poslední objednávce… momentálně mám dummy řešení:
Šablona
{snippet formSnippet}
{control $form begin}
{control $form errors}
<div>
<p>{$form['email']->label} {$form['email']->control}</p>
</div>
...
{control $form end}
{/snippet}
<script>
$(document).ready(function(){
$('#frmorderForm-email').change(function() {
var sel = $(this);
$.get("?do=loadData", {"value": sel.val()});
});
});
</script>
V presenteru mam:
public function actionCheckout()
{
$cart = Environment::getSession('cart');
if(!$cart->cartContent)
$this->redirect('default');
...
$this->template->form = $this['checkoutForm'];
}
public function handleLoadData($value)
{
$form = $this->template->form;
$form['invoice']->setDefaults(array('full_name' => 'Franta Vochmelka', 'country' => 1));
$this->template->form = $form;
if ($this->isAjax()) {
$this->invalidateControl('formSnippet');
}
}
když zapíšu mail, do pole pro jméno se mi zapíše Franta Vochmelka, ale zruší se mi JS validace z netteForms.js a používám i DependentSelectBox, jehož JS se taky neaplikuje… Jak na to, ať se nově překleslenému formuláři nastaví validace?
- arron
- Člen | 464
tipnul bych si, ze to bude tim, ze inicializace prislusneho JS se provadi pouze pri udalosti ‚load‘, ktera se vola IMHO jenom po prvnim nahrani stranky do prohlizece…ale kdyztak me opravte:-)
Resenim by bylo udelat inicializaci treba pres livequery a podobne utilitky.
Editoval arron (16. 12. 2010 16:57)
- arron
- Člen | 464
Stáhni si jquery doplnek livequery a zkus to prepsat takhle:
<script>
$(document).ready(function(){
$('#frmorderForm-email').livequery(function(){ //tady je zmena z live na livequery
var sel = $(this);
$.get("?do=loadData", {"value": sel.val()});
});
});
</script>
Mam takovy subektivni dojem, ze obecne lide nemaji livequery prilis v lasce a snazi se mu vyhybam. Nevim moc proc (mozna protoze ze ma byt pomaly??), ale neznam jine reseni, ktere by se dalo pouzit. Joooo, mozna by se to dalo vymyslet pres udalosti tj. rozsirit updatovani snippetu o vyvolani udalosti (to je cca 1 radek kodu, osobne me prekvapuje, ze to tam jeste neni, ja si to do toho JSka dopsal) a pak na ten formular zavesit zpracovani te udalosti a v nem to vsechno udelat.
<script>
//uprava soboru jquery.nette.js.
updateSnippet: function (id, html) {
var el = $("#" + id);
jQuery.nette.changeContent(el, html);
el.trigger('snippedUpdated', [el]);
},
//uprava predchoziho javascriptu
$(document).ready(function(){
$('#frmorderForm-email').bind('snippedUpdated', function(){
var sel = $(this);
$.get("?do=loadData", {"value": sel.val()});
});
});
</script>
Pisu to z hlavy, bude to chtit otestovat, pripadne lehce doupravit:-)
- Mikulas Dite
- Člen | 756
Livequery je zbytečné, ne? Od verze 1.3 má jQuery live()
a
má sice občas problém, ale se selektem přes id by to fungovat mělo.
- cuga
- Člen | 210
zkusil sem upravit na
<script>
$(document).ready(function(){
$('#frmorderForm-email').live('snippedUpdated', function(){
var sel = $(this);
$.get("?do=loadData", {"value": sel.val()});
});
});
</script>
ale pokud to chapu dobre, tak se live navesuje na trigger snippedUpdated, tzn. nejdriv se musi updatnout snippet a pak se tohle zavola… akorat ze ja to potrebuju naopak, ne? nejdriv provest zmeny a po nich at se zavola snippetUpdate…
Eventualne, jak je to s JSON odpovedi?
- bojovyletoun
- Člen | 667
tak já jsem měl problém. snippet a v něm odkazy. po refreshi snippetu
nfungovalo.
řešení bylo takto?
$('a.confifrm').live('click', function(event) {
event.preventDefault();
if(!window.confirm("Opravdu smazat?"))return false;
if ($.active) return;
$.post(this.href, $.nette.success);
$.nette.spinner.css({
position: 'absolute',
left: event.pageX+20,
top: event.pageY+80
});
});
Editoval bojovyletoun (8. 3. 2011 11:19)
- arron
- Člen | 464
Problem .live
je prave hlavne v tom, ze je potreba mit dany
callback navazany na nejaky konkretni event (popr. na nekolik eventu). Ja jsem
presne tohle resil v pripade Gridita a vyresil jsem to prave pres
livequery
, ktere se mi jednak postara o pocatecni inicializaci,
ale hlavne, kdykoliv se na strance objevi nejaky element, ktery vyhovuje danemu
jQuery selectoru, tak livequery hned spusti danou funkci, takze probehne
opetovna inicializace daneho elementu. Zatim se mi to nepovedlo vyresit nejak
elegantneji, ale pokud to nekdo vi, jak to udelat pres .live
, tak
se rad poucim :-)
Ono se to celkove resi ponekud komplikovane (tedy alespon me, protoze se s JS moc nekamaradime). Ja jsem si tak trochu prepsal Gridito, a abych ho donutil delat to, co si predstavuju, tak jsem musel zkombinovat vyuziti livequery, jQuery doplnku regex a prave vlastni udalosti pri updatovani snippetu.
Editoval arron (22. 12. 2010 0:19)
- Oggy
- Člen | 306
arron napsal(a):
//uprava soboru jquery.nette.js. updateSnippet: function (id, html) { var el = $("#" + id); jQuery.nette.changeContent(el, html); el.trigger('snippedUpdated', [el]); },
Můžu tě poprosit o bližší rozbor tohohle kódu?
co to jsou za metody changeContent a snippedUpdated?
Hledám taky řešení jak navázat netteForms na livequery, aby formuláře js validoval i po update snipetu.
Editoval Oggy (24. 12. 2010 0:26)
- arron
- Člen | 464
Ajta, koukam, ze jsem toho zmenil vic:-) Ale byl to jenom takovy neskodny refactoring. Ale pro prehlednost sem postnu jak se to cele zmenilo a proc:-)
V puvodnim jquery.nette.js bylo tohle (pouze relevantni kus kodu):
updateSnippet: function (id, html) {
$("#" + id).html(html);
},
Ja jsem to upravil naslednovne:
updateSnippet: function (id, html) {
var el = $("#" + id);
jQuery.nette.changeContent(el, html);
el.trigger('snippedUpdated', [el]);
},
changeContent: function (element, content) {
element.html(content);
},
Funkce changeContent
je jenom vyrefactorovane samotne zmeneni
dat, aby se ev. dalo jednoduse prepsat na neco jineho (treba nejaky hezky
efekt).
Takze funkce updateSnippet
udela nasledujici:
- nejdrive si zjisti spravny element podle id
- zavola funkci pro zmenu obsahu daneho elementu
- odpali udalost „snippedUpdated“ na danem elementu, aby se kdyztak mohly spustit dalsi akce, ktere se maji stat po updatovani snippetu. Takova obsluha teto udalosti vypada treba takhle (je to vytrzene z kontextu – konkretne z me upravy Gridita – ale pro nazornost by to melo stacit):
//funkci obslujujici udalost se predava i jQuery instance elementu, na kterem byla udalost vyvolana
$(this).bind('snippedUpdated', function (event, element) {
_this.loadDialog('Dialog', element);
});
No a to je vsechno :-) Urcite by se to dalo udelat i nejak hezceji, ale moje schopnosti programovani v JS jsou omezene:-)
- cuga
- Člen | 210
pokud to dobře chápu, tak v tvojem řešení se pořád děje tohle…
- něco updatuje snippet, což vyvolá událost snippedUpdated
- JS v šabloně $(…).live(‚snippedUpdated‘..); odchytne výskyt události a načte data
akorát, že bych to potřebovat naopak
- po napsání mailu do text inputu se zavolá handleLoadData(…)
- v handle se mi naplní novými daty formulář a invaliduje se snippet
- něco zjistí, že se snippet invalidoval, a po jeho překreslení znovu provede kód v netteForms.js
ví někdo, jak na to?
- arron
- Člen | 464
cuga napsal(a):
Pokud Ti spravne rozumim, tak nemas tak uplne pravdu:-)
To co jsem popsal funguje nasledovne:
1) Neco invaliduje snippet
2) jquery.nette.js nahraje data a prekresli snippet tak, jak to dela normalne,
plus jeste k tomu na prislusnem elementu (zpravidla divu) zavola udalost
‚snippedUpdated‘. A prave tady si myslim, ze by se dalo na tuhle udalost
navesit nejake nove zavolani Nette.initForm
z netteForms.js.
Pak me jeste napada dalsi moznost, prepsat tu inicializaci primo v netteForms.js na livequery, popripade proste nejak jinak :-)
- cuga
- Člen | 210
zkusil sem zavolet Nette.initForm viz.
<script>
$(document).ready(function(){
$('#frmorderForm-email').change(function() {
var sel = $(this);
$.get("?do=loadData", {"value": sel.val()});
Nette.initForm($(this).parents("form")[0]);
});
});
</script>
initForm se mi provede, ale bez výsledku, žádné pravidla se nenavěsí, pole, které mají být viditelné až po zaškrtnutí políčka jsou viditelné…
- arron
- Člen | 464
Uz jsem vycerpal moznosti…a nejsem si jisty, jestli si nejakou z nich vyzkousel (zejmena livequery je v tomhle hodne spolehlive). Co se tyka toho Tveho kodu v #17, tak budes muset debugovat (ve firebugu se js debuguje velmi dobre) a zjistit, co je spatne, ze se tam nic nenavesi…
- Avalakazar
- Člen | 3
Na tento nedostatek jsem také narazil a musím uznat, že to je achylovou patou Nette 2.0. V podstatě to výrazně a téměř omezuje sílu a využití snippetů.
Po celodením trápení jsem si pro svou aplikaci našel jisté řešení, které se zdá být funkční. Bohužel to není v core Nette a je to pouze nadstavba v mé aplikaci.
Použité instalace: Apache 2.2, PHP5.3, Nette2.0alfa, vývojové prostředí NetBeans, …
To co jsem potřeboval zajistit a jak je zde i správně zmíněno, je znovu načtení inicializace pro formuláře, které se volá pouze při prvním nahrávání stránky, a to pokaždé, kdy dojde k využití snippetů.
Upravil jsem proto v netteForms.js
<script>
// Funkce je vyuzivana k zajisteni reinicializace validatoru po
// prekresleni snippetu.
Nette.reinitializeForms = function() {
for (var i = 0; i < document.forms.length; i++) {
Nette.initForm(document.forms[i]);
}
}
// puvodni zmenena definice, neni nutna.
Nette.addEvent(window, 'load', function () {
Nette.reinitializeForms();
});
</script>
Následně jsem pak vytvořil novou třídu, která dědí z AppForm.
<?php
/**
* Nova trida pro vytvareni formularu. Jen pro upravu renderovani.
*/
class MyAppForm extends NAppForm {
/**
* Redefine render metody pro vykresleni formulare.
*/
public function render() {
parent::render();
echo $this->renderJavaScripts();
}
/**
* Invalidace snippetu s formulářem zruší JS validaci.
* Toto je metoda, ktera zajisti znovu nacteni validaci pro formulare na strance.
* Metoda se bude volat na zaver renderu formulare v ramci prekresleni ve snippetu.
* Dokud to nebude vyreseno jinak, v ramci frameworku Nette.
*/
public function renderJavaScripts() {
$java_scripts = "
<script language='javascript' type='text/javascript'>
Nette.reinitializeForms();
</script>
";
return $java_scripts;
}
}
?>
To je praktický celé. Teď už jen vytvářím formuláře z nové třídy MyAppForm. Nyní se při každém překreslení formuláře inicializují všechny na stránce zavoláním Nette.reinitializeForms();
- Avalakazar
- Člen | 3
Chbox napsal(a):
nestačí přes livequery zavolat Nette.addEvent ?
Používám JQuery 1.4, a pokud jsem to dobře pochopil, livequery již není třeba. Takže ho nevyužívám. Každopádně jsem s tím experimentoval celý den a zmíněný způsob zkoušel také. Bohužel to mělo negativní efekt, že se formuláře překreslovali 2×, nebo se validační podmínka vyhodila 2×, adt…
To co jsem uvedl, bylo to nejelegantnější co jsem za ten den vyplodil a jediné fukční. Stála mi na tom celá funkčnost mé aplikace a jsem rád, že se mohu pustit do dalšího vývoje.
- Chbox
- Člen | 125
live() nefunguje úplně 100%, taky jsem s tím měl problém a po pročtení fora používám už jen livequery, to problem vyřešilo spolehlivě. 2× překreslení nebo validace se mi nějak nezdá.
Nehledě na to, že potřebuješ Nette.addEvent nabindovat při reloadu a ne až po nějaké události a to live() myslím neumí.
Editoval Chbox (1. 2. 2011 21:37)
- ji_ri_k
- Člen | 44
Zdravím, s tímto jsem se také potýkal, pro sebe jsem si udělal „dočasné“ řešení, třeba se bude hodit i někomu dalšímu. Je třeba mít naincludované jak jQuery.nette.js, tak netteForm.js.
Upravil jsem si skript jQuery.nette.js od Honzy Marka – kde jsem přidal tento kód do funkce updateSnippet – do části success (provede se až když se updatne snippet). JavaScriptová validace pak funguje i po invalidaci snippetu.
updateSnippet: function (id, html) {
$("#" + id).html(html);
},
success: function (payload) {
// redirect
if (payload.redirect) {
window.location.href = payload.redirect;
return;
}
// snippets
if (payload.snippets) {
for (var i in payload.snippets) {
jQuery.nette.updateSnippet(i, payload.snippets[i]);
}
// ---------------------------------------------------
for (var i = 0; i < document.forms.length; i++) {
Nette.initForm(document.forms[i]);
}
// ---------------------------------------------------
}
}
- ji_ri_k
- Člen | 44
PS: stačit to bude i takto – inicializují se pouze všechny formy, které se nacházejí v invalidovaném snippetu
if (payload.snippets) {
for (var i in payload.snippets) {
jQuery.nette.updateSnippet(i, payload.snippets[i]);
jQuery("#" + i + ' form').each(function(i, val) {
Nette.initForm(val);
});
}
}
}
// edit: opravena chybička
Editoval ji_ri_k (11. 2. 2011 22:11)
- carera
- Člen | 1
Zdravím,
mám stejný problém. Vámi přikládané kódy re-inicializují JS validaci
formuláře. Problém je v tom, že špatně vyplněný formulář
v invalidovaném snippetu není validovaný ani na straně serveru. Respektive
je, ale nehlásí chybové hlášky.
EDIT: My bad, chyba byla jen v nevhodném vykreslování formuláře. Problem solved :)
Editoval carera (24. 3. 2011 10:43)
- bojovyletoun
- Člen | 667
- VaKvas
- Začátečník | 111
Diky..
Confirm jsem upravil, ale jak upravit toto, prosim :
Nekde jsem videl ukazku .live(‚each‘, function() … ale to nezabere…
Dekuji !!
$("input.date").each(function () { // input[type=date] does not work in IE
var el = $(this);
var value = el.val();
var date = (value ? $.datepicker.parseDate($.datepicker.W3C, value) : null);
var minDate = el.attr("min") || null;
if (minDate) minDate = $.datepicker.parseDate($.datepicker.W3C, minDate);
var maxDate = el.attr("max") || null;
if (maxDate) maxDate = $.datepicker.parseDate($.datepicker.W3C, maxDate);
el.get(0).type = "text"; // changing via jQuery is prohibited, because of IE
el.datepicker({
minDate: minDate,
maxDate: maxDate
});
el.val($.datepicker.formatDate(el.datepicker("option", "dateFormat"), date));
});