Ako najjednoduchsie zistim, ci na formulari bolo nieco zmenene?
- srobowak
- Člen | 27
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)
- Tomáš Jablonický
- Člen | 115
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
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.
- LeonardoCA
- Člen | 296
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)
- Vojtěch Dobeš
- Gold Partner | 1316
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
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
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
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
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
@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.
- llook
- Člen | 407
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
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
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();
});
});