Ako najjednoduchsie zistim, ci na formulari bolo nieco zmenene?

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

Zdravim, mam formular na editaciu nejakeho prvky v databaze. Pri vytvarani formulara naplnim prvky aktualnymi hodnotami, a po jeho odoslani zmenim hodnoty v databaze.

Potreboval by som zistit, ci bola hodnota aspon v jednom prvku zmenena oproti hodnote, ktoru som nastavil cez setDefault(). (Skratka aby som zbytocne nenastavoval do db rovnake hodnoty).

Najlepsie by bolo vykonat validaciu na strane klienta pomocou js. Existuje take nieco v Nette ?

Editoval srobowak (3. 6. 2012 18:26)

Ot@s
Backer | 476
+
0
-

V Nette nic takového není. Client-side řešení např. zde a zde). Server-side řešení by spočívalo ve vytvoření vlastního MyForm, který by dědil z Nette UI/Form a byl by rozšířený o metodu, která by prošla všechny formulářové pole a porovnala default hodnoty s POSTlými.

Aurielle
Člen | 1281
+
0
-

Nepomohlo by ti setEmptyValue() a validační pravidla navázaná přes podmínku?

Tomáš Jablonický
Člen | 115
+
0
-

A je to opravdu potřeba? Není to chyba návrhu, že je právě tento postup potřeba? Můžeš uvést k čemu přesně toto chování potřebuješ?

srobowak
Člen | 27
+
0
-

V databaze mam nejake zaznamy, a mam formular na upravu zaznamu. Ked zobrazim ten formular, tak sa nacitaju udaje z databazy a nastavia sa do formulara cez setDefault(). Uzivatel potom udaje upravi, odosle formular a zmeny sa zapisu do db. Ja by som chcel spravit nieco take, aby sa formular neodoslal v pripade, ze ziadna polozka v nom nebola zmenena (validacia na strane klienta pomocou js).

To co posielal Ot@s nie je az take zle. Teda myslim ten druhy odkaz lebo prvy je cez jQuery a ten nechcem tahat do aplikacie kvoli jednej veci. Skor by som ale rozmyslal, ze by som si pri kazdom prvku nastavil napr. do hidden jeho default hodnotu, a pri odoslani by som kontroloval, ci je aspon jedna polozka zmenena. Len zatial neviem, ako by som to sklbil s pouzitym validacnym skriptom z nette.

Alebo mozno najlepsie by bolo vyriesit to cez setEmptyValue() ako pisal gmvasek. Len tie validacne podmienky by asi boli trochu zlozite, kedze staci aby bola zmenena lubovolna z poloziek.

llook
Člen | 407
+
0
-

HTMLInputElement má vlastnost defaultValue. Můžeš si na submit navěsit event, který porovná value a defaultValue.

LeonardoCA
Člen | 296
+
0
-

srobowak: ten druhý odkaz od Ot@s není ideální, protože $somethingChanged zůstane nastaveno i pokud někdo změní jednu položku a pak ji vrátí na původní hodnotu.

Pokud nechceš použít jQuery, můžeš si něco podobného napsat v javascriptu bez jQuery.

Taky tuto vlastnost budu implementovat, ale ještě má pro mne nízkou prioritu, takže zatím jen promýšlím, ale osobně rozhodně využiju jQuery.

Na straně serveru bys pak mohl využít onValidate a projít všechny elementy.

Pokud jde o jednoduchý update jedné nebo i několika tabulek a neděje se při ukládání nic jiného, tak bych vůbec neřešil, jestli jsou hodnoty změněné nebo ne. To validace bude mít asi stejnou nebo větší režii než jeden update, který vrátí AffectedRows 0.

Smysl řešit by to mělo pokud uložení formuláře spustí nějakou náročnější operaci. Jinak to má smysl jen na straně js, aby se formulář vůbec neodesílal.


jablon: může to být užitečné z mnoha různých důvodů.

  • ušetří se zátěž serveru – když se při uložení formuláře spustí nějaká náročnější sekvence operací (třeba přepočet nějakých údajů nebo generování náhledů obrázků nebo by se mělo přegenerovat nějaké PDF, které už jednou vygenerováno bylo atp
  • ušetří se zátěž DB – pokud se spustí transakce, která si uzamkne pár řádků nebo tabulek
  • ušetří se čas – pokud by se měly aktualizovat údaje přes API na nějaké externí službě
  • ušetří se místo na disku nebo v DB – pokud by se měla vytvořit záloha, protože data ukládaná formulářem jsou verzované
  • nebo dokonce peníze – pokud by se měla posílat sms s potvrzením o změně údajů
  • nebo se ušetří vsechno zároveň – pokud se jedná o server s vysokou návštěvností hostovaný na nějakém cloud řešení, kde se platí za výkon, místo a přenost dat dle skutečné zátěže

Takže pro soukromý blog to asi smysl nemá, ale pro jakoukoli trochu navštěvovanější aplikaci nebo službu se to může hodit.

Editoval LeonardoCA (17. 6. 2012 2:07)

srobowak
Člen | 27
+
0
-

No na strane servera to v mojom pripade fakt nema zmysel. Skor by som to potreboval spravit na strane klienta.

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Jak by to mělo fungovat? Asi by nemuselo být obtížné navázat na každý prvek formuláře na událost change callback, který by při prvním zavolání někde potvrdil „Ok, formulář je vhodné odeslat“ – přičemž tahle hodnota by byla ve výchozích stavu záporná. A formulář by při pokusu o odeslání ji nejdřív zkontroloval, a pokud by byla záporná stále, vyhodil by třeba alert nebo tak něco.

llook
Člen | 407
+
0
-

Zřejmě jsem to napsal nesrozumitelně, tak no napíšu znova jinak: Proč neporovnávat value a defaultValue?

<script type="text/javascript">
window.onload = function () {
	forms = document.getElementsByTagName("form");
	for (i = 0; i < forms.length; i++) {
		forms[i].addEventListener("submit", function (event) {
			form = event.target;
			for (i = 0; i < form.length; i++) {
				if (form[i].value != form[i].defaultValue) {
					return;
				}
			}
			alert('Žádná hodnota nebyla změněna.');
			event.preventDefault();
		});
	}
}
</script>
LeonardoCA
Člen | 296
+
0
-

llook: zkousel jsi to?
Pokud se nepletu, tak defaultValue maji nette formulare jen v php do javascriptu se neprenasi, alespon na aktualne otevrenem projektu je nevidim.

Tak by mozna fungovalo:

<script type="text/javascript">
window.onload = function () {
        forms = document.getElementsByTagName("form");
        for (i = 0; i < forms.length; i++) {
                for (j = 0; j < form.length; j++) {
                        forms[i][j].defaultValue = form[i][j].value;
                }
                forms[i].addEventListener("submit", function (event) {
                        form = event.target;
                        for (i = 0; i < form.length; i++) {
                                if (form[i].value != form[i].defaultValue) {
                                        return;
                                }
                        }
                        alert('Žádná hodnota nebyla změněna.');
                        event.preventDefault();
                });
        }
}
</script>

Ale nemam cas to ted zkouset a nejsem si jisty jestli se pres tento event zachyti vsechny zpusoby odeslani formulare. A i kdyby to fungovalo, tak je to takto neprakticke a nekonfigurovatelne.

vojtech.dobes: jde o to ze se opravdu musi porovnavat vychozi hodnota s aktualni, jinak by to bylo polovicni reseni, v pripade ze uzivatel neco zmeni a pak vrati zpatky puvodni hodnotu, tak taky nechceme formular odesilat

redhead
Člen | 1313
+
0
-

defaultValue ale je normální property text fieldů. Bohužel jak jsem si teď zkusil, tak nefunguje na checkboxech a asi i dalších, takže to nebude fungovat.

Nicméně, tohle se nijak netýká Nette, pokud to chcete řešit jen na klientu. Napsat JS kód, který po načtení stránky pro každý formulářový prvek uloží jeho hodnotu a pak při odeslání proti ní zkontroluje tu aktuální, je triviální (viz výše).

A i kdyby to fungovalo, tak je to takto neprakticke a nekonfigurovatelne.

Záleží na tom, co tam potřebuješ konfigurovat. (edit: mimochodem, funguje to, ale musí to být bez chyb ;) )

Dále bych se podíval, jak Nette hodnoty filtruje (např. odstraňuje na začátku a na konci mezery, apod.) a zahrnout toto i do toho klientského porovnání.

Editoval redhead (18. 6. 2012 11:56)

ViPEr*CZ*
Člen | 817
+
0
-

Proč to vykonávat na straně klienta? To budete klientovi jako oznamovat, že odesílá formulář, ve kterém se jako neobtěžoval cokoliv změnit a jen si hraje??? No to asi není úplně hezké :-D
Nebude lepší form prostě odeslat, uživateli oznámit jak se data krásně změnila v databázi… ale zatím to v pozadí nehlo ani brvou a obě strany budou spokojený?

redhead
Člen | 1313
+
0
-

@ViPEr: Mě je vcelku jedno, proč to tak chtějí a ano, také bych to dělal primárně na serveru a pak teprve na klientu (možná).

Důvody jsou jasné – do databáze můžu poslat update jen s opravdu změněnými hodnotami (můžu se vyhnout dělat updaty na více tabulkách pro nějaké propojené záznamy nebo nedělat update ani jeden). V takovém případě by stálo za to se tady o tom bavit (jak to udělat elegantně s Nette formuláři). Ale klientské řešení je 1) triviální, 2) nepatří do Nette fóra.

ViPEr*CZ*
Člen | 817
+
0
-

No nechce se mi dnes přemýšlet… dal jsem si volno… ale jediné co mě napadá, tak si fetchnout ten řádek (protože to stejně dělám pro nastavení hodnot editačního formuláře) a porovnat s POSTem.

llook
Člen | 407
+
0
-

LeonardoCA napsal(a):

llook: zkousel jsi to?
Pokud se nepletu, tak defaultValue maji nette formulare jen v php do javascriptu se neprenasi, alespon na aktualne otevrenem projektu je nevidim.

Zkoušel jsem to a fungovalo to: http://vaclavsir.php5.cz/…ue/test.html

Je ale fakt, že jsem to zkusil jenom na input type="text". Na checkboxech to opravdu nefunguje, stejně tak na selectech a asi i radiolistech. Každopádně javascript výchozí hodnoty zpřístupňuje. Akorát si to budeš muset trochu rozšířit, u checkboxů porovnávat checked proti defaultChecked apod. Viz http://www.w3.org/…binding.html

Taky addEventListener() nefunguje všude, ale to už si snad zvládneš ošetřit sám.

LeonardoCA
Člen | 296
+
0
-

Mimochodem, já řeším něco jiného než srobowak, ale úzce to souvisí, proto sem píšu.

Ono sledování toho jestli je něco změněno má ještě spoustu jíných využití…

  • upozornění na neuložené změny při opuštění stránky
  • autosave
  • redo/undo, etc…

Btw. dobré postřehy ohledně checkboxů, tam se samozřejmě musí projít každý prvek v cyklu.

readhead:
Klientské řešení není vůbec triviální, pokud chci vše propojit s funkcionalitou, kterou zmiňuju výše. A zároveň celou funkcionalitu zpřístupnit, pomocí rozšíření formulářů.
Takže se to v mém případě týká i nette.
A hlavně musí to nekonfliktně fungovat současně s validací!
Ideálně to chci implementovat jako vlastní validační pravidlo, akorát nette v současnosti nepodporuje javascript validaci nad celým formulářem. /v php ano – onValidate/

ViPErCZ:

Proč to vykonávat na straně klienta? To budete klientovi jako oznamovat, že odesílá formulář, ve kterém se jako neobtěžoval cokoliv změnit a jen si hraje??? No to asi není úplně hezké :-D

V postatě přesně tak :-) jen jinými slovy.

Nebude lepší form prostě odeslat, uživateli oznámit jak se data krásně změnila v databázi… ale zatím to v pozadí nehlo ani brvou a obě strany budou spokojený?

U jednoduchých věcí bych nic takového neřešil. Ale už pokud bys řešil například verzování, tak je blbost psát uživateli, že se něco změnilo a vytvářet novou verzi (zbytečné verze) a nebo říct uživateli, že se něco změnilo a nevytvářet novou verzi (mírně řečeno zadějící a matoucí) …

Editováno:

@ViPEr: Mě je vcelku jedno, proč to tak chtějí a ano, také bych to dělal primárně na serveru a pak teprve na klientu (možná).

Souhlasím. Ale výsledkem by mělo být něco jako.

$form->SaveOnlyIfChanged(); // bude zajištěno jak na straně serveru tak js.
nebo
$form->WarnBeforeLeavingPage(); // bude zajištěno, že uživatel omylem nepřijde o změny

A chci to vyřešit jednou a moci používat bez jediné řádky javascriptu v projektu (krom přidání vlastního rozšíření nette.ajax.js, které vše zajistí)

Editoval LeonardoCA (18. 6. 2012 20:43)

LeonardoCA
Člen | 296
+
0
-

s jQuery lze asi nejjednoušeji – po načtení stránky serializovat celý formulář, uložit a pak před odesláním porovnat.

$('document').ready(function() {
    $('.changedOnly').each(function() {
        $(this).data('initial', $(this).serialize());
    });
    $('.changedOnly').on('submit',function (event) {
        if ($(this).data('initial') == $(this).serialize())
            event.preventDefault();
    });
});

test