nette.ajax.js – alt. obsluha pro AJAX s jQuery
- na1k
- Člen | 288
Všiml jsem si pull requestu na podporu History API. Můžu se zeptat v jakém je to stádiu? Je to funkční nebo zatím jen prototyp?
Před časem jsem si něco podobného splácal sám, ale moc spokojený s tím nejsem. Kromě obsluhy history ale potřebuji mít možnost navázat na dokončení popstate eventu vlastní obsluhu (tj. snippety se obnoví na předchozí hodnoty a já s nimi chci ještě manipulovat). To zmiňuju jen pokud by taková možnost nebyla, takový lehký feature request :-)
- Vojtěch Dobeš
- Gold Partner | 1316
@peter.z bacha, aktuálně na masteru jsem prohodil
události before
a start
. Doporučuju použít
poslední stabilní verzi a doplnit si do ní tu úpravu předaných parametrů
(viz výše), master se ještě může změnit :).
To confirmovací rozšíření musí využívat ve stabilní verzi událost
start
(na masteru to teď musí být before
).
- David Zadražil
- Člen | 62
@pekelnik – tohle by byla skvělá funkce, nicméně se mi jí nedaří rozjet. Okno se sice při chybě otevře, ale je prázdné a bez obsahu.
- Vojtěch Dobeš
- Gold Partner | 1316
Je třeba nemít Firelogger. Pokud je zapnutý, tak Nette tuto hlavičku bohužel neposílá.
Editoval vojtech.dobes (19. 9. 2012 19:34)
- Vojtěch Dobeš
- Gold Partner | 1316
O jakou vyjímku/chybu v jaké fázi aplikace jde? Při vykreslování se už také neodešle.
- David Zadražil
- Člen | 62
V handleru záměrně volám neexistující funkci. Pokud vypnu ajax, laděnka normálně vyskočí a jsou tam tyto hlavičky – http://imgur.com/A4ELM
Děkuji za pomoc.
- Vojtěch Dobeš
- Gold Partner | 1316
Nechceš poslat klikatelnou laděnku? V handleru jako ve zpracování signálu, jo?
- klasyc
- Člen | 14
pepakriz napsal(a):
Případně dá se nějak ovlivnit pořadí extenzí?
Obávám se, že aspoň moje (asi 3 týdny stará verze) to neumožňuje. Pokud potřebuješ, aby se Tvá extenze provedla až nakonec (což byl můj případ), můžeš v příslušném handleru použít
setTimeout (function() { ... }, 0);
ale moc čisté řešení to není (co kdyby tohle dělaly nezávisle na sobě dvě extenze, mezi kterými bys potřeboval určit pořadí…).
- Vojtěch Dobeš
- Gold Partner | 1316
Ten load
by se měl ošetřit, dobrý point. Podívám se na
to… pořadí bohužel ovlivnit nelze.
- klasyc
- Člen | 14
Ahoj pánové,
před časem jsem tady psal o myšlence propojení zde probíraného ajaxového rozšíření s modálními formuláři, které umí vyrobit jquery UI. Před několika dny jsem se dostal k celkem funkčnímu kódu, tak ho dávám k dobru a třeba se bude někomu hodit nebo mi napíše, jak by se to nechalo udělat lépe.
Tady je odkaz: http://pastebin.com/wPnybT9v
A ještě nějaký krátký popis:
Jedná se o 3 extenze (dialogy vyžadují ty dvě zbývající):
- extrapost – vyrobí metody $.nette.post a $.nette.get,
které funkčně odpovídají
klasickým $.post a $.get, ale navíc volají i handlery všech zbylých extenzí. Je
to spíš jenom usnadnění pro toho, kdo není zvyklý na metodu ajax.
- watchdog – přidává metodu $.nette.watchSnippet(name,
callback), která umožňuje
přidat sledování určitého snippetu. Pokud pošle server novou verzi snippetu, zavolá se
daný callback. To se hodí pokud máte navěšené nějaké události na vnitřku snippetu. Pokud
nová verze snippetu, je potřeba znovu navěsit tyto události a k tomu používám zmíněnou
metodu.
- dialogs – umožňuje poměrně snadno vyrobit
z normální aplikace ajaxovou pomocí
modálních oken. Výchozím stavem je funkční neajaxová aplikace, dejme tomu telefonní
seznam. Při editaci jména nás Nette přesměruje na novou stránku s formulářem, který
vyplníme, a pak nás hodí zase zpátky na seznam. Pokud chceme, aby probíhala editace
jména v modálním okně, uděláme následující:
- Nalinkovat jQuery UI + pohrát si se styly
- Editační formulář vložíme do snippetu a také tabulku s telefonním
seznamem dáme do
snippetu:
{snippet renameFormSnippet}
{control renameForm}
{/snippet}
{snippet phoneBookSnippet}
<table> ... </table>
{/snippet}
- V presenteru přidáme do akce edit následující. Díky tomu nám přijde
na ajaxový
požadavek místo celé stránky jenom snippet s formulářem.
if ($this->isAjax()) {
$this->invalidateControl("renameFormSnippet");
}
- Upravíme událost renameFormSubmitted tak, že místo přesměrování
zavoláme metodu
podobnou té níže. Pokud se nejedná o ajaxový požadavek, proběhne obyčejné
přesměrování. V opačném případě se zavolá výchozí akce, která naplní šablonu,
a invaliduje se snippet s tabulkou jmen. Do payloadu se ještě přidá příznak
dialogs["all"] = "close"
, který říká javascriptové části, že má zavřít všechna okna(místo all můžeme použít název snippetu, který okno obsahuje). Výsledkem ajaxového
požadavku je tak opět json odpověď s novou verzí tabulky.
private function redirectOrAjax()
{
// Redirect if this is not ajax call:
if (!$this->isAjax()) {
$this->redirect('default');
} else {
$this->actionDefault();
$this->template->setFile($this->getContext()->params['appDir'] . '/templates/Homepage/default.latte');
// Invalidate necessary snippets:
$this->invalidateControl('phoneBookSnippet');
$this->payload->dialogs["all"] = "close";
}
}
- Příslušným odkazům vedoucím na editační formulář přidáme
událost onclick,
ve které zavoláme metodu $.nette.showDialog(url, snippet, args, options).
Snippet je jméno snippetu, který obsahuje editační formulář, args jsou
parametry, které se předají v POSTu, options je objekt, který obsahuje
konfiguraci jquery dialogu (viz nápověda k jquery ui). Může to vypadat třeba
takto:
<a href="..." onclick="$.nette.showDialog({link //edit $person_id}, 'renameFormSnippet', {}, { width: 600 }); return false;">Upravit</a>
S trochou štěstí by se po kliknutí na editační odkaz měl objevit hezký modální formulář. Pokud nebude povolený javascript, aplikace se bude chovat jako dříve.
Snad se bude tohle rozšíření někomu hodit. Pokud ne, tak se omlouvám za spam a přeju hezký večer.
Honza
Editoval klasyc (20. 9. 2012 22:02)
- LeonardoCA
- Člen | 296
@**vojtech.dobes**: Pořád nevím jak čistě vyřešit spolupráci
nette.ajax.js a bootstrap from twitter.
Týká se to všech ajaxových odkazů, pokud je takový odkaz v dropdown
tak se dropdown po kliknutí nezavře, týká se to různých komponent,
volání ajaxu prostě zruší funkčnost protože obsahuje stopPropagination()
(v projektu jsem si prozatím ten řádek zakomentoval)
Chtělo by to asi možnost přidat volitelný parametr do settings povolující propagination? Máš nápad jak to vyřešit nějak jednoduše, ať se to nemusí řešit pro každý odkaz?
- Vojtěch Dobeš
- Gold Partner | 1316
LeonardoCA Mrknu na to, kompatibilita s Bootstrapem je moc hezká feature :).
- Vojtěch Dobeš
- Gold Partner | 1316
Zatím jsem přidal podporu pro dropdowny – v téhle větvi
přibyla extenze twitterBootstrap
(v samostatném souboru). Ta se
o vše automaticky postará.
Zítra mrknu na ostatní Bootstrapové komponenty, jestli to nějak potřebují, a snad se to brzy dostane do stabilní verze.
- Vojtěch Dobeš
- Gold Partner | 1316
@h4kuna Refaktoring API zanesl do kódu chybu, kdy se formulářová data zpracovala až po odeslání requestu. Fixed.
- LeonardoCA
- Člen | 296
vojtech.dobes napsal(a):
Zatím jsem přidal podporu pro dropdowny – v téhle větvi přibyla extenze
twitterBootstrap
(v samostatném souboru). Ta se o vše automaticky postará.Zítra mrknu na ostatní Bootstrapové komponenty, jestli to nějak potřebují, a snad se to brzy dostane do stabilní verze.
Díky, jak bude čas tak to vyzkouším, případně rozšířím, teď pár dnů asi moc nebude.
- LeonardoCA
- Člen | 296
@vojtech.dobes: zvážil bych přidání cache: false do standartního ajax requestu.
- Vojtěch Dobeš
- Gold Partner | 1316
LeonardoCA Kdyžtak otevírej issuečka, bylo by to supr. Rád vedu diskuse na Githubu :).
Konkrétně k tomuto, nevím jestli nestačí, aby si to každý pohlídal sám… jak přesně se to chová s tou zapnutou cachí? PJAX to kupříkladu automaticky nenastavuje.
- motorcb
- Člen | 552
Zdravim. Stáhl jsem poslední verzi ale nefunguje mi v Multiplier.
Formulář se vůbec neodešle. Na chvilku problikne spinner ale nic se
neděje.
Když odeberu formuláři
$form->getElementPrototype()->class(‚ajax‘);, tak vše funguje.
Dělám něco špatně?
HomepagePresenter.php
<?php
use Nette\Application\UI\Form;
use Nette\Application\UI\Multiplier;
class HomepagePresenter extends BasePresenter
{
public function renderDefault()
{
}
protected function createComponentShopForm()
{
$neco = $this;
return new Multiplier(function ( $id ) use ( $neco ) {
$form = new Nette\Application\UI\Form;
$form->getElementPrototype()->class('ajax');
$form->addText('count', 'Počet zboží:')
->addRule($form::FILLED)
->addRule($form::INTEGER);
$form->addHidden('id', $id);
$form->onSuccess[] = $neco->shopFormSubmitted;
$form->addSubmit('create', 'Přidat do košiku');
$form->setDefaults( array( 'count' => 1 ) );
return $form;
});
}
public function shopFormSubmitted(Form $form)
{
sleep(10);
$aValues = $form->getValues(TRUE); // same as: (array) $form->values;
$this->flashMessage("Přidáno do košíku id: ".$aValues["id"]." Kusu:".$aValues["count"], 'success');
if (!$this->presenter->isAjax()) {
$this->redirect('this');
} else {
$this->invalidateControl("flashMessage");
}
}
}
@layout.latte
...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script type="text/javascript" src="{$basePath}/js/netteForms.js"></script>
<script type="text/javascript" src="{$basePath}/js/nette.ajax.js"></script>
<script type="text/javascript" src="{$basePath}/js/extensions/spinner.ajax.js"></script>
<script type="text/javascript" src="{$basePath}/js/ajax.js"></script>
...
{snippet flashMessage}
<div n:foreach="$flashes as $flash" class="flash {$flash->type}">{$flash->message}</div>
{/snippet}
...
default.latte
{block content}
{snippet matches}
{for $i=0; $i<10; $i++}
{snippet match-$i}
{$i}
{control shopForm-$i}
{/snippet}
{/for}
{/snippet}
{/block}
Na obyčejný formulář bez Multiplier vše funguje
- leninzprahy
- Člen | 150
vojtech.dobes napsal(a):
@h4kuna Refaktoring API zanesl do kódu chybu, kdy se formulářová data zpracovala až po odeslání requestu. Fixed.
skoro mi přijde že se fix ještě nedostal na https://github.com/…ette.ajax.js
- motorcb
- Člen | 552
Jak udělám efekt při update snippetu?
Jako v https://componette.org/search/?…
jQuery.nette.updateSnippet = function (id, html) {
$("#" + id).fadeTo("fast", 0.01, function () {
$(this).html(html).fadeTo("fast", 1);
});
};
Děkuji za nápady
- Vojtěch Dobeš
- Gold Partner | 1316
@motorcb This way :)
$.nette.ext('snippets').applySnippet = function ($el, html) {
$el.fadeTo("fast", 0.01, function () {
$el.html(html).fadeTo("fast", 1);
});
};
- Vojtěch Dobeš
- Gold Partner | 1316
@leninzprahy, @h4kuna To je
pravda. Ještě jsem to přepracoval, zítra večer pushnu aktualizovanou verzi.
S beforeSend
callbackem se to ukázalo být krapet
složitější… jinak odporúčám stabilní verzi 1.1.2, a samozřejmě díky
všem, kteří testují vývojový master.
- motorcb
- Člen | 552
@vojtech.dobes
Ještě mne napadla jedna věc :) Bylo by možné ihned po požadavku na update
snippetu, snipet nejprve zneviditelnit – $el.fadeTo(„fast“, 0.1);
A až po jeho obnovení ho zobrazit – $el.fadeTo(„fast“, 1);
Takhle se skreje a následně ihned zobrazí až když jsou data připravena k zobrazení.
- Vojtěch Dobeš
- Gold Partner | 1316
@motorcb To je složitější – klient neví, které snippety pošle server k obnovení. Můžeš si napsat vlastní rozšíření, snippetové kontejnery najdeš pomocí tohoto selektoru:
[id^="snippet--"]
- Vojtěch Dobeš
- Gold Partner | 1316
motorcb Myslíš třeba linku, na který bylo kliknuto? Jo. V poslední stabilní verzi takto:
$.nette.ext('my-ext', {
before: function (settings) {
if (settings.nette) {
var id = settings.nette.el.attr('id');
}
}
});
Update: omlouvám se, autor skriptu neví, jak ho používat :). Tento kód nemůže fungovat na žádné verzi.
Editoval vojtech.dobes (2. 10. 2012 18:31)
- Vojtěch Dobeš
- Gold Partner | 1316
Ty callbacky volá samotné nette.ajax.js
, přičemž s těmito
parametry. Volal jsi to na poslední stabilní verzi? Na masteru musí
být to settings
až druhý argument.
- motorcb
- Člen | 552
@vojtech.dobes:
Ano, mám poslední verzi nette.ajax.js
To moc dobře nechápu…
Mám soubor: www\js\extensions\muj.js:
(function($, undefined) {
$.nette.ext('my-ext', {
before: function (settings) {
alert("xxx");
if (settings.nette) {
var id = settings.nette.el.attr('id');
alert( id );
}
}
});
})(jQuery);
Ten mam naincludovany do sablony:
<script type="text/javascript" src="{$basePath}/js/extensions/muj.js"></script>
Po kliknutí na tlačítko pro odeslání formuláře vyskočí alert „xxx“ ale nevyskočí alert s ID buttonu.
Nevěděl by někdo co dělám špatně?
- Vojtěch Dobeš
- Gold Partner | 1316
Máš skutečně 1.1.2? Protože v ní tento kód nebude fungovat. Události
before
se předává pouze jqXHR objekt. Tento kód ti nebude
fungovat na žádné verzi, ale pokud posuneš ten parametr
settings
na druhou pozici, tak ti fungovat bude na masteru.
Omlouvám se, před tím jsem mystifikoval, příspěvek jsem doplnil.
Editoval vojtech.dobes (2. 10. 2012 18:31)
- motorcb
- Člen | 552
@**vojtech.dobes**:
Ano mám poslední verzi: https://github.com/…ette.ajax.js
Prosím o bližší vysvětlení :) Jak je odkaz na verzi ve které mi to bude fungovat?
Kam na druhou pozici? Co bude na prvni pozici?
Diky
- Vojtěch Dobeš
- Gold Partner | 1316
Ano, použij verzi z masteru (poslední stabilní verze je z tagu 1.1.2, tedy tato). A použij tento kód:
(function($, undefined) {
$.nette.ext('my-ext', {
before: function (xhr, settings) {
alert("xxx");
if (settings.nette) {
var id = settings.nette.el.attr('id');
alert( id );
}
}
});
})(jQuery);
Změnily se parametry, které jsou tomuhle callbacku předávány, dříve se
settings
vůbec nepředávalo, jen xhr
.
- cafesk8
- Člen | 103
Zdravím,
pokud se zde něco takového již řešilo, tak se omlouvám, ale nic jsem
nenašel.
Asi jsem správně nepochopil jak se používají extensions.
Dejme tomu, že mám na stránce několik ajaxových odkazů s třídou .ajax, které po kliknutí správně provedou akci a aktualizují snippet. No problem.
Problém nastává v momentě, když bych si chtěl u některých odkazů napsat vlastní extension.
<script>
$.nette.init();
$.nette.ext('confirmBeforeSend',{
before: function() {
// potvrdit akci, pokud ne, return false
},
success: function(payload) {
.....
}
});
</script>
Lze a pokud ano, tak jakým způsobem tuto extension napojit pouze na
některé ajaxové odkazy?
Např. že odkazy, kde bych chtěl provést callbacky z „confirmBeforeSend“,
bych označil třídou „.confirmAjax“ a poté si do JS napsal
něco jako
<script>
$.nette.init();
$.nette.ext('confirmBeforeSend', { /* callbacky */ });
$(document).on('click','.confirmAjax',function(){
// zde docílit toho aby ".confirmAjax" využil mé extension 'confirmBeforeSend'
});
</script>
Takže prostě aby se zachovala původní funkcionalita u „.ajax“ odkazů a u „.confirmAjax“ se spustily nějaké mé předem definované callbacky.
Pokud jsem to celé nějak špatně pochopil, tak se omlouvám, za přihlouplý dotaz.
Díky
- pekelnik
- Člen | 462
Uz jsem neco takovyho taky promyslel… https://github.com/…js/issues/35 –
zatim je nejlepsi validovat elementy primo v kodu rozsireni nebo pouzit
$.nette.ajax()
.
- duskohu
- Člen | 778
Zdravím, mam jeden problém:
$.nette.ext('data-click-handle',{
init: function(){
var visibleDiv = 'default'; // default
},
before: function(){
if(!$(".presenter-rightContent").is(":visible")){ //ak nie je element visible
visibleDiv = 'none';
}
},
load: function () {
$('tr[data-click-handle]').click(function(e){
e.preventDefault();
var obj = $(this).data('clickHandle');
if (obj.type == 'ajax') {
$.nette.ajax({
url: obj.url
});
// ajaxové volanie handle
} else {
window.location = obj.url;
}
});
},
success: function () {
if(visibleDiv == 'none'){ // ak nieje element visible zobraz ho
$(".presenter-rightContent").show("slide", { direction: "right" }, 700);
}
}
});
chcel by som si pred vykonaním požiadavku zapamatovat .presenter-rightContent či je visible alebo nie, a po požiadavke spracovať, ale neviem ako si mám prenášať visibleDiv?
- Vojtěch Dobeš
- Gold Partner | 1316
@duskohu Všechny callbacky mají sdílený kontext,
což znamená, že přiřazení property do this
v jednom
callbacku zpřístupní tuto property i v ostatních.
Takže:
$.nette.ext('data-click-handle', {
init: function () {
this.visibleDiv = 'default'; // default
},
before: function () {
this.rightContent = $(".presenter-rightContent");
if (!this.rightContent.is(":visible")) {
this.visibleDiv = 'none';
}
},
success: function () {
if (this.visibleDiv == 'none') {
this.rightContent.show("slide", { direction: "right" }, 700);
}
}
});