Něco jako nette.js s jQuery
- Honza Marek
- Člen | 1664
Aktuální informace o ajaxu a ajaxových formulářích
Editoval Honza M. (15. 6. 2009 17:04)
- ViliamKopecky
- Nette hipster | 230
Honza M. napsal(a):
…
Tak za tohle děkuju ještě víc :)
Editoval enoice (9. 2. 2009 15:16)
- Honza Marek
- Člen | 1664
Hm… U ajaxového formuláře jsem zapomněl, že tam může být taky nějaká validace. Přidal jsem teda jednu podmínku navíc, která spustí validaci, co je v parametru onsubmit.
- zdvori
- Člen | 10
Zatim nefunguje pro MultipleSelectBox, kde se jako hodnota posila pole. V nasledujicim kodu v „values“ jeste je:
CONTACTS[] = 1
CONTACTS[] = 2
ale v
sendvalues uz je logicky jen posledni:
CONTACTS[] = 2
<script>
var values = form.serializeArray();
for (var i = 0; i < values.length; i++) {
sendValues[values[i].name] = values[i].value;
}
</script>
- Honza Marek
- Člen | 1664
Chvíli jsem nad tím děsně koumal, ale nakonec jsem přidal podporu multi selectu.
- Jod
- Člen | 701
Honzo, feature request ,)
Keď chcem spraviť pekný prechod medzi updatom snippetu, napríklad fade, použijem:
<script>
if (data.snippets) {
for (var i in data.snippets) {
$("#" + i).fadeOut('fast', function() {
$("#" + i).html(data.snippets[i]);
$("#" + i).fadeIn('fast');
});
}
}
</script>
Nedá sa to spraviť nejak tak, aby som si mohol takýto efekt nastaviť bez toho aby som sa babral do tvojho pluginu? Dík.
Editoval Jod (21. 2. 2009 12:50)
- Etch
- Člen | 403
Honzo taky ti sem přidám něco do mlýnku. Možná, že by bylo dobré použít jiný selector při updatu snippetů, protože tak jak to máš ty se připravuješ o možnost využití stejného „snippetu“ dvakrát:
<?php
@{? $grid->renderPaginator()}
@{? $grid->render()}
@{? $grid->renderPaginator()}
?>
Toto by sice fungovalo, ale překreslovalo by se pouze horní stránkování. Proto by se tam pro překreslování snippetů hodil více například následující kód :
<script>
if (data.snippets) {
for (var i in data.snippets) {
$("[id='"+ i +"']").html(data.snippets[i]);
}
}
</script>
Ten již zajistí, že se vždy přepíší všechny potřebné snippety.
Editoval Etch (23. 2. 2009 19:14)
- Honza Marek
- Člen | 1664
Id by mělo teoreticky být unikátní. Pokud není, stránka je nevalidní a jsou s tím tyhle problémy.
Ideální by bylo, kdyby snippety byly označeny třídu a ne přes id. Anebo hlídat unikátnost toho id. To by mělo drobnou nevýhodu v tom, že by se takový vícenásobný snippet při aktualizaci přenášel vícekrát. K tomu se ale nějak musí postavit David, změna selektoru je spíše takový hack.
- Ondrej
- Člen | 110
Etch napsal(a):
<?php @{? $grid->renderPaginator()} @{? $grid->render()} @{? $grid->renderPaginator()} ?>
Zrovna toto jsem resil, snazil jsem se i generovat nazev snippetu dynamicky v sablone napr. renderPaginator(‚bottom‘), ale nic nefungovalo spravne, takze jsem to nakonec vyresil takto:
<?php
{snippet paginator}
@{? $grid->renderPaginator()}
{/snippet}
@{? $grid->render()}
{snippet bottom_paginator}
@{? $grid->renderPaginator()}
{/snippet}
?>
- Honza Marek
- Člen | 1664
Keď chcem spraviť pekný prechod medzi updatom snippetu, napríklad fade:
Přerozdělil jsem původní plugin do několika funkcí, jedna z nich je jQuery.updateSnippet. To v praxi znamená, že se dá snadno nahradit. Třeba takto:
jQuery.extend({
updateSnippet: function (id, data) {
$("#" + id).fadeOut("fast", function () {
$(this).html(data).fadeIn("fast");
});
}
});
No a už se to hezky mění s efektem fade.
- Jod
- Člen | 701
Po callbacku je treba znova zaregistrovať niektoré veci, ktoré nejdú cez jQuery.live ako napr texyla, alebo
// external links
$('a.external').attr('target', '_blank');
// hidden files
$('.hidden').attr('style', 'display: none');
Ak to ide nejak inak tak fajn, ja som si to spravil zatiaľ tak, že pridám do ajaxCallback za updaty snippetov funkciu jQuery.registerAfterUpdate() ktorá zostane prázdna
registerAfterUpdate: function () {
},
A vo svojom scripte volám niečo takéto:
jQuery.extend({
// updateSnippet
registerAfterUpdate: function() {
// texyla
$.texyla();
// external links
$('a.external').attr('target', '_blank');
// hidden elements
$('.hidden').attr('style', 'display: none');
}
});
Editoval Jod (1. 3. 2009 13:00)
- romansklenar
- Člen | 655
Po odeslání formuláře se selectem stačí přesměrovat (pokud nejde o ajaxový požadavek) a parametry se dostanou z POSTu do GETu a je po problému. Fixnul jsem to v tom archívu i v demu.
- Honza Marek
- Člen | 1664
Hm… docela nečekaná zrada. Myslel jsem, že když je to od jQuery, tak to bude fungovat všude.
- LeonardoCA
- Člen | 296
romansklenar napsal(a):
Zrovna asi před týdnem jsem si s tím hrál a zkošel na to napasovat DataGrid, tak tady máš:
v datagrid.js po funkci registerAfterUpdate je navíc čárka, která v IE shodí funkčnost javascriptů
jQuery.extend({
//grafický efekt u překreslení všech snippetů
updateSnippet: function (id, html) {
$("#" + id).animate({ opacity: 0.5 }, "fast", "swing", function () {
$(this).html(html).animate({ opacity: 1 }, "fast", "swing");
jQuery.registerAfterUpdate();
});
},
registerAfterUpdate: function() {
// schovat odesílací tlačítka formulářů (nutno po každém překreslení snippetu)
$("form.ajaxform :submit").hide();
},
});
jinak v další verzi jquery 1.3.3 by už snad mělo fungovat vše i bez použití livequery
- Honza Marek
- Člen | 1664
Vymyslel jsem ještě lepší ajaxování. Místo $.netteAjax
bude možné použít normální funkce $.get
, $.post
a podobně. Jen pomocí funkce $.ajaxSetup
nastaví nějaký
defaultní callback, který se postará o snippety a tak.
jQuery.extend({
updateSnippet: function (id, html) {
$("#" + id).html(html);
},
netteCallback: function (data) {
// redirect
if (data.redirect) {
window.location.href = data.redirect;
}
// snipeti
if (data.snippets) {
for (var i in data.snippets) {
jQuery.updateSnippet(i, data.snippets[i]);
}
}
}
});
jQuery.ajaxSetup({
success: function (data) {
jQuery.netteCallback(data);
},
dataType: "json"
});
Použití je stejné, jen funkci $.netteAjax
zaměníte za
libovolnou standardní funkci, třeba $.get
. Rozdíl nastane
v případě, že budete chtít při dokončení ajaxového požadavku zavolat
vlastní callback. Pokud budete chtít provést snippetování a podobně, tak
je potřeba explicitně zavolat funkci $.netteCallback
:
// chci kromě normálního zpracování ještě zobrazit hlášku
$.get("someUrl", function (data) {
jQuery.netteCallback(data);
alert("hláška");
});
Na závěr přidám upravený kód pro ajaxové formuláře:
jQuery.fn.extend({
netteAjaxSubmit: function (callback) {
var form;
var sendValues = {};
// odesláno na tlačítku
if (this.is(":submit")) {
form = this.parents("form");
sendValues[this.attr("name")] = this.val() || "";
// odesláno na formuláři
} else if (this.is("form")) {
form = this;
// neplatný element, nic nedělat
} else {
return null;
}
// validace
if (form.get(0).onsubmit && !form.get(0).onsubmit()) return;
var values = form.serializeArray();
for (var i = 0; i < values.length; i++) {
var name = values[i].name;
// multi
if (name in sendValues) {
var val = sendValues[name];
if (!(val instanceof Array)) {
val = [val];
}
val.push(values[i].value);
sendValues[name] = val;
} else {
sendValues[name] = values[i].value;
}
}
// odeslat ajaxový požadavek
return jQuery.ajax({
url: form.attr("action"),
data: sendValues,
type: form.attr("method") || "get",
success: callback
});
}
});
Editoval Honza M. (8. 4. 2009 23:48)
- Honza Marek
- Člen | 1664
Kód nemám, protože mi točítko uprostřed vyhovuje, ale udělalo by se to při kliknutí na odkaz asi takto (jestli jsem dobře pochopil z dokumentace ten jQuery offset).
$("a.ajax").click(function () {
$.get(this.href);
var ofs = $(this).offset();
$("#tocitko").css({
left: (ofs.left + 10) + "px",
top: (ofs.top + 20) + "px"
});
return false;
});
- romansklenar
- Člen | 655
Píšeš tam jako ukázku:
// nastaví událost onclick pro všechny elementy A s třídou 'ajax'
$("a.ajax").live("click", function(event) {
$.get(this.href); // zahájí AJAXový požadavek
// zobrazí spinner, signalizující uživateli, že se něco děje
$('<div id="ajax-spinner"></div>').css({
position: "absolute",
left: event.pageX + 20,
top: event.pageY + 40
}).ajaxStop(function() {
$(this).remove(); // po skončení spinner smaž
}).appendTo("body");
return false;
});
To zobrazení toho ajaxloaderu nemusí být nutně v těle té funkce, může být i mimo a pak se bude provádět při každé detekci ajaxového požadavku, to je myslím jedna z jeho velkých předností :) možná by bylo zajívé pro čtenáře to tam zmínit (pokud to ještě jde upravit) než si to ráno budou lidi číst.
- David Grudl
- Nette Core | 8218
romansklenar napsal(a):
To zobrazení toho ajaxloaderu nemusí být nutně v těle té funkce, může být i mimo a pak se bude provádět při každé detekci ajaxového požadavku, to je myslím jedna z jeho velkých předností :) možná by bylo zajívé pro čtenáře to tam zmínit (pokud to ještě jde upravit) než si to ráno budou lidi číst.
Teď asi nerozumím. Ajaxloaderem myslíš ten obrázek? A proč se nezobrazuje po ajaxStart() ?
- romansklenar
- Člen | 655
Vlastně jo, chybí tam ajaxStart, proto to nejede …už tam vidím něco co tam není.
$("a.ajax").live("click", function () {
$.get(this.href);
return false;
});
// zobrazí spinner, signalizující uživateli, že se něco děje
$('<div id="ajax-spinner"></div>').css({
position: "absolute",
left: event.pageX + 20,
top: event.pageY + 40
}).ajaxStart(function () {
$(this).show();
}).ajaxStop(function() {
$(this).hide();
}).appendTo("body").hide();
- David Grudl
- Nette Core | 8218
Už asi rozumím. A ty vyvoláváš Ajaxové požadavky i jiným způsobem, než přes tu knihovnu?
- Honza Marek
- Člen | 1664
David Grudl napsal(a):
Honzo, jsi na Zdrojáku
Hezký… :-)
Už asi rozumím. A ty vyvoláváš Ajaxové požadavky i jiným způsobem, než přes tu knihovnu?
Když se spinner zobrazuje pomocí ajaxStartu, tak se zobrazí při jakémkoliv požadavku daném přes jQuery. Což kromě kliknutí na odkaz může být třeba ajaxové odeslání formuláře.
- Tomik
- Nette Evangelist | 485
Ahoj Honzo!
Jednak musím říct: skvělá práce! :)
A teď dotaz :) –
Mám takovou situaci – vykresluju tabulku, podobnou DataGridu, která
obsahuje výpis adresářové struktury, vše jede jak má, ale kvůli multifile
uploadu používám knihovnu http://www.uploadify.com .. ta podporuje spuštění kódu po
provedení uploadu, a to pomocí fce onComplete (viz http://www.uploadify.com/documentation/), do této fce,
která se pouští po provedení uploadu jsem umístil
$.get({link list! $path, $orderBy, $rename})
→ aby došlo
k obnovení dat v snippetu. Požadavek se provede (FireBug mi jej zobrazí a
je vidět, že Nette vrátí validní JSON odpověď s aktuální tabulkou
(vč. nově uploadnutých souborů), jenže Tvůj JS kód jej
nepřekreslí…
Původně jsem si myslel, že to je asi v kolizi s tou uploadovací knihovnou, tak jsem ji dal pryč a zkusil pouze něco ve smyslu:
function akce() {
$.get({link list! $path, $orderBy, $rename});
}
setTimeout("akce()", 5000);
A opět, JSON obsahoval správný výsledek, ale ten nepřepsal, to co bylo starší.
Ptám se tedy: nevíš, kde by mohla být chyba?
Díky!
- Tomik
- Nette Evangelist | 485
Aha, tak už jsem na to přišel. Dík!
Nakonec místo $.get({link list! $path, $orderBy, $rename});
volám $.netteAjax({link list! $path, $orderBy, $rename});
–
původně jsem myslel, že i ten $.get zavolá callback sám, ale evidentně
ne. To je jedno, problém vyřešen! :)
Editoval Tomik (27. 4. 2009 22:18)
- Honza Marek
- Člen | 1664
No když nahraješ novou verzi toho pluginu, která je na webu v extras, tak tam žádná funkce $.netteAjax není a $.get opravdu volá $.netteCallback sám.