Invalidace snippetu s formulářem zruší JS validaci

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
cuga
Člen | 210
+
0
-

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
+
0
-

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)

cuga
Člen | 210
+
0
-

nejake podrobnejsi nakopnuti, jak/kde to livequery volat? s jQuery ani JS obecne si zatim moc nerozumime…

cuga
Člen | 210
+
0
-

zkusil sem

<script>
$(document).ready(function(){
    $('#frmorderForm-email').live('change', function(){
        var sel = $(this);
        $.get("?do=loadData", {"value": sel.val()});
    });
});
</script>

ale bez vysledku, funguje to porad stejne… jak znova aplikovat JS na formular?

arron
Člen | 464
+
0
-

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
+
0
-

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
+
0
-

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?

arron
Člen | 464
+
0
-

Ten kod, co jsi poslal, tak resi jenom co se stane po updatovani snippetu, ale neresi pocatecni inicializaci, to je pravda. Pri psani prospevku vyse mi to nedoslo…to by chtelo jeste nejak dotahnout…

bojovyletoun
Člen | 667
+
0
-

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)

Aurielle
Člen | 1281
+
0
-

CODE!

cuga
Člen | 210
+
0
-

zkusil jsem

<script>
$(document).ready(function(){
    $('#frmorderForm-email').live('change', function(){
        var sel = $(this);
        $.get("?do=loadData", {"value": sel.val()});
        $.post(this.href, $.nette.success);
    });
});
</script>

nemuzu rict, ze bych slavil velky uspech…

arron
Člen | 464
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

pokud to dobře chápu, tak v tvojem řešení se pořád děje tohle…

  1. něco updatuje snippet, což vyvolá událost snippedUpdated
  2. JS v šabloně $(…).live(‚snippedUpdated‘..); odchytne výskyt události a načte data

akorát, že bych to potřebovat naopak

  1. po napsání mailu do text inputu se zavolá handleLoadData(…)
  2. v handle se mi naplní novými daty formulář a invaliduje se snippet
  3. 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
+
0
-

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
+
0
-

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é…

cuga
Člen | 210
+
0
-

opravdu nikdo nevi, jak znovu spustit inicializaci JS v invalidovanem snippetu?

arron
Člen | 464
+
0
-

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
+
0
-

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();

Chbox
Člen | 125
+
0
-

nestačí přes livequery zavolat Nette.addEvent ?

Avalakazar
Člen | 3
+
0
-

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
+
0
-

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)

cuga
Člen | 210
+
0
-

avalakazar: diky za aspon nejake reseni, tez jsem zkousel s live i livequery vselijake kejkle a bezvysledne

ji_ri_k
Člen | 44
+
0
-

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
+
0
-

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
+
0
-

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)

VaKvas
Začátečník | 111
+
0
-

Nebyla by prosim jeste nejaka rada, pokud pouzivam addDatePicker ? stejne tak i prestane na strance fungovat i napr.

$('a[data-confirm]').click(function(e){
	if (!confirm($(this).data('confirm'))) {
	    e.stopImmediatePropagation();
	    return false;
	}
    });
bojovyletoun
Člen | 667
+
0
-

alien vs predator
Pozn. překladatele: .click(fnc); je jen kratčí zápis tohoto: .bind(‚click‘,fnc);

VaKvas
Začátečník | 111
+
0
-

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));
    });
VaKvas
Začátečník | 111
+
0
-

Kdyby nekdo take resil nefunkcnost datepickeru po invalidaci snippetu, tak jsem to poresil takto..

$("input.date").live('hover', function(){
	$(this).datepicker();
    });

tvari se to jako zcela funkcni.. ;)