Nittro – novinka pro váš frontend (původně NetteJS)
- jahudka
- Člen | 71
Helou,
jak možná někteří a některé tušíte, pouštím do divočiny novou legraci, které říkám NetteJS a která by snad mohla pomoct tomu, aby víc produkčních webů na Nette používalo taky trochu toho JS (když už má Nette tak dobrou podporu pro AJAX).
Github: https://github.com/jahudka/nettejs
Dokumentace: https://github.com/…nettejs/wiki
Postupně tu dokumentaci dopisuju, ale to nejdůležitější už tam je; zároveň doháním resty-testy, cílem je pokrejt to celý, gotta catch 'em all žejo.
Co tam je?
– AJAX: odkazy, formuláře včetně uploadů a progress událostí,
transitions – přechody mezi stránkami
– Validace formulářů pomocí distribučních netteForms.js (s malou
úpravou viz Quick setup)
– Browser history, samozřejmě
– Dynamické snippety – mazání, vkládání nových vč. řazení
– Snippety žijí! – introducing Životní cyklus snippetu
– Plnohodnotný DI kontejner vč. autowiringu
– Routing na URL nebo na selektory
– Skeleton widgety pro dialogová okna a flash message
– Spousta užitečnejch utilit, mj. i NEON parser / enkodér
– Všechno je to krásný, objektový.. ^_^
Nejsme ještě production-ready, to budem až to potestujem celý, ale to už nebude víc než dny, maximálně nějaký krátký tejdny – takže už si to tam stahuj, testuj, zkoušej, čím víc zpětný vazby získáme teď, tím míň jí získáme potom!
Ha, na přednášce na PoSobotě se mě někdo ptal, proč vynalézám znova kolo – trochu jsem tam blekotal nějaký nesmysly, zaskočilo mě to – teď zas naopak nevím odkud začít: neděláme to snad všichni? je snad v oblasti client-side kódu kterej se s Nette dobře používá už všechno objeveno, všechno napsáno? proč je teda drtivá většina Nette webů neajaxová? nevynalézám kolo, vynalézám Teslu model Š ve světě, kterej jezdí na trakařích… atd atp.
Jinej dotaz se týkal mojí oblíbené techniky embedování javascriptu pro komponenty inline v šablonách a Content Security Policy – mea culpa, tenhle nejžhavější trend mě nějak minul, nicméně NetteJS na vkládání inline javascriptu nestojí ani nepadá, všechen client-side kód jde mít klidně zaminifikovanej do jednoho souboru a spouštět pomocí dobře napsanejch DOM rout.
Diskutuj!
- chemix
- Nette Core | 1310
Už se těším jak to vyzkouším
Ps: video z posoboty ma prioritu, tak brzy čekejte na vašich YT přímačích
Odběr možný sledovat http://www.youtube.com/…ework/videos
- Tomáš Jacík
- Člen | 147
Vypadá to skvěle, ale je to pro mě stavbou dost cizí. Chtělo by to nějakou sample appku, abych věděl jak to používat a v čem mi to vlastně pomůže. Neplánuješ nějaký sandbox?
- Šaman
- Člen | 2666
@jahudka: Dotaz asi z druhé strany vývojářského týmu, než kde se pohybuješ ty.
Jsem backenďák, rozumím PHP, SQL, Nette, nějaké databázové vrstvě. Názor na JS je ten, že jsou to nějaké pouťové efekty pro lepší feeling uživatele (dobrá, trochu to zlehčuji, ale v principu podobný názor mám). Mám aplikaci, která běhá i bez JS (aspoň na 99,9% – občas pomocí JS navíc zakážu inputy, které nemá smysl vyplňovat apod.). Závislé selectboxy, překreslování snippetů – to všechno by se s vypnutými scripty řešilo pomalu requestem, ale fungovalo by to. Na základní efekty mi stačil Bootstrap3 a nakonec i nette.js od @VojtěchDobeš.
A teď ta otázka – bude pro mě užitečné NetteJS? Ve smyslu, zda mi
umožní používat zmíněné fičury pokud možno bez psaní vlastního JS?
nette.js
je skvělé právě v tom, že pro základni použití
nemusím opustit php a html (např. přilinkuji rozříření confirm.js a
doplním nějaké data atributy a nic dalšího neřeším). Z tvé přednášky na poslední sobotě jsem nabyl spíš dojmu,
že představuješ knihovnu pro frontenďáky, kteří programují v JS, než
pro nettaře pracující v PHP.
- David Grudl
- Nette Core | 8228
Je to zajímavá knihovna a líbí se mi, že není závislá na jQuery.
Btw ukazuje se, že fakt není moc prozíravé nazývat všechny JS knihovny kolem Nette jako nette.js :-)
- jahudka
- Člen | 71
Tomáš Jacík napsal(a):
Vypadá to skvěle, ale je to pro mě stavbou dost cizí. Chtělo by to nějakou sample appku, abych věděl jak to používat a v čem mi to vlastně pomůže. Neplánuješ nějaký sandbox?
Jo, pravda, něco takovýho by to asi chtělo.. Nějak to sesmolím, hodím sem pak odkaz :-) dík za tip!
Šaman napsal(a):
@jahudka: Dotaz asi z druhé strany vývojářského týmu, než kde se pohybuješ ty.
Jsem backenďák, rozumím PHP, SQL, Nette, nějaké databázové vrstvě. Názor na JS je ten, že jsou to nějaké pouťové efekty pro lepší feeling uživatele (dobrá, trochu to zlehčuji, ale v principu podobný názor mám). Mám aplikaci, která běhá i bez JS (aspoň na 99,9% – občas pomocí JS navíc zakážu inputy, které nemá smysl vyplňovat apod.). Závislé selectboxy, překreslování snippetů – to všechno by se s vypnutými scripty řešilo pomalu requestem, ale fungovalo by to. Na základní efekty mi stačil Bootstrap3 a nakonec i nette.js od @VojtěchDobeš.
A teď ta otázka – bude pro mě užitečné NetteJS? Ve smyslu, zda mi umožní používat zmíněné fičury pokud možno bez psaní vlastního JS?
nette.js
je skvělé právě v tom, že pro základni použití nemusím opustit php a html (např. přilinkuji rozříření confirm.js a doplním nějaké data atributy a nic dalšího neřeším). Z tvé přednášky na poslední sobotě jsem nabyl spíš dojmu, že představuješ knihovnu pro frontenďáky, kteří programují v JS, než pro nettaře pracující v PHP.
Stručná odpověď: ne :-)
Dlouhá odpověď:
- NetteJS určitě jde použít na všechno co popisuješ, ale ne bez psaní
JS kódu. Není složitý dopsat si službu nebo dvě který ti vlastně
nasimulujou to samý, tj. už pak JS kód psát nemusíš a řešíš jen
nějaký data atributy, ale vestavěný v NetteJS určitě všechny věci z
nette.js
nejsou a pokudnette.js
zvládne to co potřebuješ, je to asi i menší download :) - Zároveň to není tak, že NetteJS je pro frontenďáky, kteří programují v JS – jestli si vzpomínáš na ty „sociální průzkumy“ na začátku mojí přednášky, většina z nás backenďáků jsou zároveň frontenďáci a nemaj k sobě dedikovanýho frontenďáka – pokud je tohle i tvůj případ, pak ty jsi ten frontenďák, a je už jenom na tobě / tvojí firmě / tvým klientovi, jestli s přístupem „JS jsou pouťové efekty pro lepší pocit uživatele“ obstojíš. Nehodnotím, just sayin'. Nevím kde a na čem děláš a je úplně klidně možný, že tvůj přístup je daný aplikaci zcela adekvátní. NetteJS má řešit případy, kdy už načtení confirm.js a tři inline řádky JS adekvátní nejsou. Zároveň jsem se ale snažil o přístup co nejpodobnější tomu, na co je člověk zvyklej z Nette, aby se to právě dobře používalo i lidem víc zvyklejm na backend (až samozřejmě na pár věcí poplatnejch rozdílům v jazycích).
David Grudl napsal(a):
Je to zajímavá knihovna a líbí se mi, že není závislá na jQuery.
Btw ukazuje se, že fakt není moc prozíravé nazývat všechny JS knihovny kolem Nette jako nette.js :-)
Nojo no, ono to vlastně začalo jako 1:1 port některejch částí Nette do JS, tak mi NetteJS přišlo tehdy vhodný, a nic lepšího mě od tý doby nenapadlo :-) ale jsem samozřejmě otevřenej návrhům ;-)
Editoval jahudka (10. 2. 2016 13:42)
- Šaman
- Člen | 2666
@jahudka: Díky za jasnou odpověď.
Co se druhého bodu týče (že i já jsem frontenďák), tak to je na
trochu filosofickou diskuzi. To, že občas skládám i nějkaý design pomocí
bootstrapu a občas používám snippety, js confirm, závislé selectboxy a js
validaci formulářů (vše pomocí předpřipravených řešení), to ze mě
nedělá frontendového programátora. Stejně, jako bych neuznal za php
programátora někoho, kdo si metodou pokus omyl upraví pár šablon ve
wordpressu. Mluvím teď o profesi, nikoli o tom, k čemu nás okolnosti
občas donutí.
A když už filosofuji, tak přemýšlím i o tom, jestli se dá
uživatelské rozhraní admin modulu považovat za frontend :)
- Vojtěch Dobeš
- Gold Partner | 1316
David Grudl napsal(a):
Je to zajímavá knihovna a líbí se mi, že není závislá na jQuery.
Btw ukazuje se, že fakt není moc prozíravé nazývat všechny JS knihovny kolem Nette jako nette.js :-)
K tomu bych si jen dovolil podotknout, že ta moje se jmenuje
nette.ajax.js
:).
- jahudka
- Člen | 71
Šaman napsal(a):
@jahudka: Díky za jasnou odpověď.
Co se druhého bodu týče (že i já jsem frontenďák), tak to je na trochu filosofickou diskuzi. To, že občas skládám i nějkaý design pomocí bootstrapu a občas používám snippety, js confirm, závislé selectboxy a js validaci formulářů (vše pomocí předpřipravených řešení), to ze mě nedělá frontendového programátora. Stejně, jako bych neuznal za php programátora někoho, kdo si metodou pokus omyl upraví pár šablon ve wordpressu. Mluvím teď o profesi, nikoli o tom, k čemu nás okolnosti občas donutí.
A když už filosofuji, tak přemýšlím i o tom, jestli se dá uživatelské rozhraní admin modulu považovat za frontend :)
Podle mě úplně není :-) myslím že je úplně putna jestli se člověk „cejtí“ bejt frontenďákem nebo ne, podstatný je to, že je nějaká aplikace, někdo ji vyvíjí, a pokud ty jsi jedinej kdo píše její „frontendovou část“, pak jsi pro tuhle aplikaci „frontenďák“ – myšleno tak, že výsledná podoba a chování fronendu nezávisí na nikom jiným než na tobě. Neznamená to, že frontend je tvoje profesní specializace; přesto je frontend tvoje osobní zodpovědnost nebo jak to líp říct..
Samozřejmě že i uživatelské rozhraní admin modulu je frontend :-) používá ho přece uživatel. Ne tisíce uživatelů, ale pořád to je nějakej uživatel. Já poslední dobou dělám vlastně spíš věci, který maj jenom „admin modul“ – různý interní nástroje který používaj jednotky, max malý desítky lidí, a přijde mi, že musím UX řešit naopak o to víc – protože tady mám narozdíl od „public“ frontendu velmi přímou a detailní zpětnou vazbu o tom, jak se co používá, co koho kde brzdí nebo co by mohlo bejt intuitivnější atd.. A lidi často neví, co vlastně chtěj – myšleno tak, že si na něco zvyknou, a nepřemejšlej moc o tom, že (potažmo jak) by to šlo jinak.. přijde mi, že bejt v tomhle nějak proaktivní je trochu základ, jinak přestávám bejt programátor a stává se ze mě automat na plnění mechanickejch úkolů..
- chemix
- Nette Core | 1310
Dneska jsem se Danem potkal a nedalo mi to spat a musel jsem pripravit alespon trailer k tomu co pro vas pripravujeme.
Nittro example trailer @ YouTube (3:03)
- GEpic
- Člen | 566
jahudka napsal(a):
Šaman napsal(a):
@jahudka: Díky za jasnou odpověď.
Co se druhého bodu týče (že i já jsem frontenďák), tak to je na trochu filosofickou diskuzi. To, že občas skládám i nějkaý design pomocí bootstrapu a občas používám snippety, js confirm, závislé selectboxy a js validaci formulářů (vše pomocí předpřipravených řešení), to ze mě nedělá frontendového programátora. Stejně, jako bych neuznal za php programátora někoho, kdo si metodou pokus omyl upraví pár šablon ve wordpressu. Mluvím teď o profesi, nikoli o tom, k čemu nás okolnosti občas donutí.
A když už filosofuji, tak přemýšlím i o tom, jestli se dá uživatelské rozhraní admin modulu považovat za frontend :)Podle mě úplně není :-) myslím že je úplně putna jestli se člověk „cejtí“ bejt frontenďákem nebo ne, podstatný je to, že je nějaká aplikace, někdo ji vyvíjí, a pokud ty jsi jedinej kdo píše její „frontendovou část“, pak jsi pro tuhle aplikaci „frontenďák“ – myšleno tak, že výsledná podoba a chování fronendu nezávisí na nikom jiným než na tobě. Neznamená to, že frontend je tvoje profesní specializace; přesto je frontend tvoje osobní zodpovědnost nebo jak to líp říct..
Samozřejmě že i uživatelské rozhraní admin modulu je frontend :-) používá ho přece uživatel. Ne tisíce uživatelů, ale pořád to je nějakej uživatel. Já poslední dobou dělám vlastně spíš věci, který maj jenom „admin modul“ – různý interní nástroje který používaj jednotky, max malý desítky lidí, a přijde mi, že musím UX řešit naopak o to víc – protože tady mám narozdíl od „public“ frontendu velmi přímou a detailní zpětnou vazbu o tom, jak se co používá, co koho kde brzdí nebo co by mohlo bejt intuitivnější atd.. A lidi často neví, co vlastně chtěj – myšleno tak, že si na něco zvyknou, a nepřemejšlej moc o tom, že (potažmo jak) by to šlo jinak.. přijde mi, že bejt v tomhle nějak proaktivní je trochu základ, jinak přestávám bejt programátor a stává se ze mě automat na plnění mechanickejch úkolů..
Defakto píši stejný typ aplikací, různé správní aplikace. Využívám hodně modalová okna, tabulky, stránkování a vše funguje přes ajax anižby se uživatel ztratil nebo se nějaká data „ztratila z pohledu“ (někdy si uživatel stěžuje, že se mu po vykonání akce přescrolluje stránka). Je to hlavně z toho důvodu, že každá aplikace ať už jakkoliv velká, funguje na telefonu a uživatel nemusí zbytečně čekat nebo se bát „bílého přechodu“. Prostě zobrazím spinner a člověk má pocit, že s ním aplikace komunikuje. User Experience je velice důležitý.
Editoval GEpic (15. 2. 2016 5:07)
- jahudka
- Člen | 71
flamengo napsal(a):
@jahudka @chemix Ahoj, byl by doporučen plugin DropZone, ale nikde jsem nenašel demo ani žádnou informaci, jak vůbec použít, co to dělá, prostě vůbec nic. Nejdu toto někde? Díky za info.
Ahoj, promiň, jak připravuju dvojku, tak mi dokumentace lehce pokulhává. Jedna věc je použít build Nittra kterej dropzone obsahuje; pokud ještě nepoužíváš nittro#master, dropzone je v buildu bower balíčku nittro obsaženej automaticky, pokud už jedeš na masteru, musíš si nittro zbuildovat ručně. To jde pomocí gulp nebo grunt pluginu, readme na githubu by tě mělo postrčit správným směrem.
Co se samotnýho dropzone týče: dropzone je plugin pro usnadnění drag&drop file uploadů. Jednoduchý použití s klasickým nette/forms upload control vypadá tak, že vykreslíš formulář s normálním upload políčkem, a pak inicializuješ dropzónu z toho políčka; dropzóna si to políčko „hijackne“, což má několik efektů:
- dropzóna přebere validační pravidla políčka (validuje se normálně přes netteForms.js, takže umí všechno, co by uměl samotnej input)
- dropzóna přebere název POST parametru políčka
- dropzóna „vysává“ soubory vybraný pomocí původního políčka – když uživatel místo drag&drop vybere soubor(y) normálně z Choose…, dropzóna spustí stejný události jako kdyby uživatel soubory dropnul na příslušný místo ve stránce, včetně validace etc., a resetuje políčko – tím můžeš sjednotit chování interface nezávisle na metodě, kterou uživatel vybere soubory
- validační pravidla na původním políčku plus případně atribut „required“ dropzóna zruší, protože je zpracovává sama a kdyby tam zůstaly, nefungovalo by to správně (například právě required by selhávalo, protože dropzóna soubory z políčka hned po výběru „vysaje“)
- jeden z vedlejších efektů je, že není potřeba dělat žádné úpravy v backendu, protože z pohledu backendu se dropzóna chová stejně jako původní HTML input
Dropzóna jen obaluje události a provazuje data s formulářem – uživatelské rozhraní je zcela na tobě – dropzóně jen řekneš, na jakém elementu má sledovat drag&drop události, a pak posloucháš události z dropzóny a reaguješ – takže například když uživatel nad cílovej HTML element najede s dragovaným souborem, můžeš cílovej element nějak zvýraznit atd. Pro každej dropnutej soubor kterej splní validační pravidla pak dropzóna spustí událost „file“, v níž máš přístup k File objektu a můžeš s jeho pomocí například přidat soubor do nějaký viditelný fronty (platný soubory si dropzóna jinak ve frontě udržuje sama, opět jde jen o GUI).
Kompletní příklad použití dropzóny bude časem v distribuci; prozatím aspoň tady: https://gist.github.com/…80b9a7cb3b54
Editoval jahudka (4. 8. 2016 19:07)
- jiri.pudil
- Nette Blogger | 1032
Ahoj, měl bych dotaz na takový složitější use-case: nákupní košík, ve kterém může uživatel volit u jednotlivých položek množství a další parametry, z nichž se při změně ajaxem přepočítává cena. Zkusil jsem v obsluze události dvě možnosti:
- Nasimulovat click na submit, který provede přepočet a překreslí snippet, ale ačkoliv má tlačítko nastavené prázdný validationScope, client-side validace proběhne a zabrání v odeslání :(
- Poslat request na signál přes
page.open()
. To funguje krásně, ale ani za zlaté prase se mi nedaří přimět Nittro, aby nesahalo do History a nevkládalo signál do URL :( zkusil jsem se trošku prošťourat v kódu a doufal jsem, že zabere podobný ošklivý hack:
var link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('data-push-state', 'false');
page.openLink(link);
Ale neúspěšně. Co teď prosím s tím?
(Nittro 1.9, Nette 2.3)
- jahudka
- Člen | 71
@jiri.pudil: Ahoj, validation scope momentálně nittro ještě nepodporuje, dík za připomenutí! Do dvojky určitě poladíme. Co se týče přidávání do historie, máš v zásadě dvě možnosti: buď dál používat službu Page, která je by design dělaná na to, aby věci dávala do historie (a upravit trošku backend aby se to chovalo tak jak chceš), nebo jít víc low-level a použít službu Ajax.
Příklad pomocí Page service:
page.open({link addItem!}, 'GET', { id: 123 });
// udělá GET request na "/aktuální/url?do=add-item&id=123"
V backendu se pak chováš stejně, jako by ses měl chovat při zpracování podobného typu požadavku bez ajaxu – tj. provedeš co potřebuješ a uděláš redirect. Narozdíl od neajaxového zpracování ale nemusíš nutně dělat reálnej redirect, protože tady jde jen o to uložit do historie až tu finální adresu – což můžeš udělat takhle:
// řekni nittru, že si má vzít URL pro položku historie z payloadu
// místo původní adresy requestu
$presenter->payload->postGet = true;
// .. a samozřejmě dodej tu správnou adresu
$presenter->payload->url = $presenter->link('this');
// Tohle chování by se ještě mělo dělat jen pokud je request
// opravdu AJAXový, jinak by se měl udělat normální redirect
// pomocí `$presenter->redirect(...)`. Pokud používáš
// `nittro/nette-bridges` a `PresenterUtils` trait, můžeš si
// celou tuhle logiku zjednodušit na jeden řádek:
$presenter->postGet('this');
Metoda postGet()
se chová pro tebe zvenku dost podobně jako
metoda redirect()
– uživatel je na konci na správné adrese
ať už šel request AJAXem nebo ne – ale zásadní rozdíl je, že pokud
request AJAXem šel, metoda postGet
neodešle odpověď a místo
toho pokračuje normální renderování snippetů, jen do payloadu už jsou
přidané právě ty položky postGet
a url
. Takže
ideální podoba backendu pokud tohle používáš je něco jako:
public function handleAddItem($id) {
// .. proveď potřebné operace ..
// .. zavolej postGet ..
$this->postGet('this');
// .. a tenhle kód už se zpracuje jen pokud
// odpovídáš na AJAXový request - takže invaliduješ
// příslušné snippety a nastavíš šablonu a zbytek
// za tebe udělá nette + nittro :-)
$this->redrawControl('items');
$this->template->items = [...];
}
Pokud bys na to chtěl jít pomocí služby Ajax, můžeš použít něco jako:
di.getService('ajax')
.get({link addItem!}, {id: 123})
.then(
function(response) { /* response je instance Nittro.Ajax.Response */ },
function(err) { /* server nevrátil 2XX nebo jsi offline etc. */ }
);
Editoval jahudka (23. 8. 2016 0:56)
- radekBrno
- Člen | 61
Zkouším Nitto, a když chci definovat prostor pro výpis flash zpráv
<div n:flashes></div>
, tam mi tento řádek vyhodí
chybovou hlášku „Unknown attribute n:flashes“.
Ještě mám jednu otázku, řeším závislé položky formuláře. Na základě výběru položky v select boxu se zobrazí textová pole a nebo zatržítka. Šlo by to řešit také přes Nittro?
- jahudka
- Člen | 71
@radekBrno zapomněl jsem v sobotu otagovat tu composer package
nittro/nette-bridges
, opravil jsem to až myslím včera, takže je
dost pravděpodobný, že máš nainstalovanou starou verzi – zkus si tu
závislost v composer.json
upravit na ^2.0.0
nebo tak
něco a updatnout. Pak samozřejmě musíš v config.neon
registrovat
latte:
macros:
- Nittro\Bridges\NittroLatte\NittroMacros
Závislé položky formuláře nejjednodušeji vyřešíš asi snippetem. Samozřejmě si můžeš napsat JS kód, kterej to vyřeší kompletně na frontendu, ale je to složitější :-) kdyby ses tou cestou chtěl vydat, napiš klidně mail, rád pomůžu :-) (me@subsonic.cz). Případně můžeš napsat na Slacku Péhápkáři, kde je separátní kanál #nittro: https://pehapkari.slack.com/…ages/nittro/
Editoval jahudka (2. 3. 2017 21:40)
- meridius
- Člen | 34
Ahoj, zkouším Nittro (2.0.5) a nelíbí se mi, že po ajaxovém odeslání
formuláře se mu nastaví výchozí hodnoty (i když není ve snippetu).
Zkoušel jsem tomu zabránit podle https://github.com/…o/wiki/Forms
přidáním no-reset
class na dotyčný element ve formu, ale
nepomohlo to. Nepomohlo ani její přidání na form.
Dá se s tím něco dělat?
- jahudka
- Člen | 71
meridius napsal(a):
Ahoj, zkouším Nittro (2.0.5) a nelíbí se mi, že po ajaxovém odeslání formuláře se mu nastaví výchozí hodnoty (i když není ve snippetu). Zkoušel jsem tomu zabránit podle https://github.com/…o/wiki/Forms přidáním
no-reset
class na dotyčný element ve formu, ale nepomohlo to. Nepomohlo ani její přidání na form.Dá se s tím něco dělat?
Ahoj, pardon, to je zastaralá verze dokumentace, ještě to pořád nemáme
všude správně – přidej na <form>
element atribut
data-reset="false"
:-)
- jahudka
- Člen | 71
Jinak hodně těchhle základních / nejčastějších věcí je tady: https://github.com/…ck-reference
.. pravda, zrovna to zakazování resetu formulářů tam nebylo, mea culpa :-) doplněno.
Editoval jahudka (28. 3. 2017 21:36)
- DominikDvorak94
- Člen | 14
Ahoj, narazil jsem na menší problém. Pokud mám přes nittro otevřený
dialog s formulářem, potvrdím ho, znovu otevřu a chci znovu potvrdit
(odeslat) tak mi vyhodí chybu chrome do konzole:
Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'frm-postForm' in undefined
.
Nejprve jsem myslel že je chyba někde u mě ale stejná se objevuje
i v demu na githubu.
Když bych poté dialog otevřel znovu, zavřel přes btn s
data-action="close"
, otevřel znovu a pokusil se odeslat tak se
vše provede bez problémů.
- jahudka
- Člen | 71
DominikDvorak94 napsal(a):
Ahoj, narazil jsem na menší problém. Pokud mám přes nittro otevřený dialog s formulářem, potvrdím ho, znovu otevřu a chci znovu potvrdit (odeslat) tak mi vyhodí chybu chrome do konzole:
Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'frm-postForm' in undefined
. Nejprve jsem myslel že je chyba někde u mě ale stejná se objevuje i v demu na githubu.Když bych poté dialog otevřel znovu, zavřel přes btn s
data-action="close"
, otevřel znovu a pokusil se odeslat tak se vše provede bez problémů.
Ahoj, dík za report, opravil jsem to – zkus si sehnat novější verzi
nittra (stačí balíček nittro-extras-dialogs
pokud si buildíš
nittro sám). V demu by to taky mělo být fixed.
- DominikDvorak94
- Člen | 14
Našel jsem další chybku, teď je tedy o dost menší a spíš taková
kosměťárna, jde o to že při zavolání upravené prompt nittrem jsou
tlačítka na potvrzení nebo zavření s data atributy napsána špatně.
data-action=""confirm""
v data action jsou dvakrát úvozovky,
koukal jsem na to v chromu i ve firefoxu a v obou případech jsou
uvozovky dvě.
Imho: Jde nějak přepsat text který bude v tlačítkách v propmtě, pokud možno přes data attr.
- jahudka
- Člen | 71
DominikDvorak94 napsal(a):
Našel jsem další chybku, teď je tedy o dost menší a spíš taková kosměťárna, jde o to že při zavolání upravené prompt nittrem jsou tlačítka na potvrzení nebo zavření s data atributy napsána špatně.
data-action=""confirm""
v data action jsou dvakrát úvozovky, koukal jsem na to v chromu i ve firefoxu a v obou případech jsou uvozovky dvě.Imho: Jde nějak přepsat text který bude v tlačítkách v propmtě, pokud možno přes data attr.
Ahoj, u confirmu můžeš text tlačítek měnit pomocí data atributů
data-confirm
a data-cancel
, např.
data-prompt="Určitě?" data-confirm="Ano" data-cancel="Ne"
. Jinak
Nittro s data atributy pracuje jako s JSON – když čteš data atribut
např. data-confirm
pomocí
Utils.DOM.getData(elem, 'confirm')
, Nittro zkouší nad hodnotou
atributu pustit JSON.parse()
, a naopak když Nittro data atribut
nastavuje pomocí Utils.DOM.setData(elem, 'confirm', 'hodnota')
,
nejdřív data serializuje pomocí JSON.stringify()
.
Když se na to pak koukáš v nějakým inspektoru, uvidíš uvozovky
dvojitý, protože
JSON.stringify("some string") === '"some string"'
a inspektoři se
snažej bejt friendly, takže ti HTML entity dekódujou; kdybys ale mrknul na
nějaký outerHTML
toho prvku, kterej má takhle nastavenej data
atribut, uvidíš normálně "
, protože
setAttribute()
hodnotu atributu escapuje.
Editoval jahudka (12. 4. 2017 21:22)
- zacatecnik27
- Člen | 26
v dnešní době bych řekl že vývoj webových aplikací prochází slušnou polarizací a širokým rozštěpem fronendového přístupu k vývoji (angular, react, …) a backendového (v případě php symphony, nette, apod…) … ten spor je celý vlastně o tom kdo opanuje statky a pozemky pod dnešními presentery a latte šablonami pokud se nemýlímm, zatímco pro backendový vývoj je browser jen displej kterému se obvykle dodávají celé obrazovky k vykreslení aniž by si klientská část musela řešit otázky stránkování, filtrování tabulek, obsluhy menu, zvýrazňování vybraných položek, pak fronendový dělá pravý opak, toto všechno přebírá a snaží se trivializovat backend jen na nějaké jednoduché restové api nebo webovou servisu nad základním modelem aplikace. De fakto tím zcela převzít úlohu dnešních nette presenterů a latte šablon a přesunout ji do klientské aplikační části. Zajímalo by mne zda lze považovat NETTE+NITTRO za nějaký počátek systematické snahy tento přerod skutečně dotáhnout do konce a zcela nahradit klientskou částí úlohu presenterů a latte šablon, nebo takto důsledné cíle a zásahy do architektury NETTE+NITTRO zatím nemá ?
Editoval zacatecnik27 (28. 4. 2017 8:52)
- zacatecnik27
- Člen | 26
dá se předpokládat že některé NETTE 3 nebo 4 už by se chtělo vydat touto cestou a zcela předat úlohu presenterů a latte frontendovému frameworku ? a pokud ano vsadíte na některý z těch existujících nebo by tou výchozí cestou mohlo být budoucí značně vylepšené NITTRO ? :-) Díky za vhled pod pokličku a lepší představu o budoucích záměrech …
Editoval zacatecnik27 (28. 4. 2017 8:50)
- jahudka
- Člen | 71
@zacatecnik27 nittro rozhodně nemá ambici dělat z nette jen „restovou servisu“ a nahradit presentery a latte na frontendu. Naopak integrace Nittra s Nette funguje jenom díky Nette presenterům a Latte. Takže ani dlouhodobě takovou ambici rozhodně nemám. U některýho typu webů je a vždycky bude naprosto adekvátní psát je jako single-page aplikace které jen komunikují s nějakým API a všechno se renderuje na klientu, ale u jiných typů webů naopak vždycky bude adekvátní renderovat je na serveru. Ty první jsou doménou Reactu, Angularu, Vue.js a podobných; ty druhé jsou záležitostí pro Nette, Symfony, Django a spol. A pro tu část té druhé skupiny která je postavená na Nette je tu Nittro.
Samozřejmě nevím, jestli se Nette jednou touhle cestou nevydá, ale Nittro s tím nepočítá a pokud se tak stane, Nittro přestane mít důvod existovat (protože React, Angular, Vue, …).
Editoval jahudka (28. 4. 2017 14:12)
- Blujacker
- Člen | 89
Zdravim,
premyslime, ze bychom tento doplnek zakomponovali do nasi Nette aplikace. Zatim testovne nasazeno a funguje nadherne.
Mam ale problem – na jedne strance se neustale preklesuje jeden prvek,
pouzivame na to setTimeout(function (){}, x);
. Nicmene po prechodu
na jinou stranku se prvek preklesuje poradl dal (protoze nedoslo ke klasickemu
redirectu, ktery by ten JS zrusil) – ma nittro nejakou moznost jak dosahnout
toho, ze by se funkce volala pouze v ramci jednoho requestu?
Dik!
- jahudka
- Člen | 71
@Blujacker zdravím, jsem rád, že vám to funguje :-) jestli jsem ten problém správně pochopil, je to úplně typickej adept na řešení pomocí životního cyklu snippetu.
Mějme ve stránce nějakej „hlavní“ snippet (třeba „content“) a
v něm další kterej se jmenuje třeba „refreshme“ (to je ten, kterej
budeme obnovovat). Zároveň předpokládejme, že jsou nainstalované
nittro/nette-bridges
a zaregistrovaná Nittro Latte macra. Nakonec
ještě předpokládáme, že používáte build Nittra obsahující
_stack
knihovnu. V šabloně pak bude něco takovéhohle:
<div n:snippet="content">
<div n:snippet="refreshme"></div>
<script type="application/json">
// následující dva řádky se díky _stack knihovně
// postarají o spuštění JS kódu až po načtení Nittra
window._stack || (window._stack = []);
window._stack.push(function(di) {
// definujeme si proměnnou pro uložení timeru
// vně setup a teardown callbacků, abychom k ní
// měli přístup z obou
var tmr = null;
// macro snippetId vpodstatě vrací
// $template->escape($control->getSnippetId($arg)),
// takže tady bude jeho výstup "snippet--content"
di.getService('page').getSnippet({snippetId content})
.setup(function(elem) {
// elem === document.getElementById('snippet--content')
// tenhle kód se spustí hned potom, co se hlavní
// snippet objeví ve stránce a naplní HTML kódem
// ...
tmr = window.setTimeout(function() {
// volej něco co překreslí snippet refreshme
}, 123);
})
.teardown(function(elem) {
// tenhle kód se spustí těsně před tím, než hlavní
// snippet Nittro překreslí nebo odstraní ze stránky
// takže tady po sobě můžeme uklidit :-)
if (tmr) {
window.clearTimeout(tmr);
}
});
});
</script>
</div> <!-- /#snippet--content -->
Je důležitý, že ten JS blok je vně snippetu „refreshme“,
ale uvnitř snippetu „content“ – můžeme se na to koukat tak,
že ten JS blok inicializuje snippet „content“, jehož je
součástí – tudíž se spustí pokaždý, když se snippet „content“
překreslí touhle šablonou. setup()
a teardown()
callbacky se po zavolání zahazují, takže je to přesně to chování, které
chceme (jinak by se snippet v této podobě inicializoval jen poprvé když se
objeví ve stránce a příště už ne).
Editoval jahudka (27. 6. 2017 2:12)
- Blujacker
- Člen | 89
Ahoj @jahudka
to reseni s refreshem snippetu zafungovalo, diky moc! Narazil jsem ale na dalsi problem.
Pokud jsem pochopil, tak $presenter->postGet()
mohu pouzit na
to, abych zmenil URL po provedeni requestu. Zkousim to menit u jedne akce,
kterou volam pres page.openLink()
page.openLink volam pomoci Tveho workaround:
function nittroOpenLinkWorkaround(di, Url, url, params, transition)
{
var a = document.createElement('a');
finalUrl = Url.from(url);
for (var key in params) {
finalUrl.setParam(key, params[key]);
}
a.href = finalUrl.toAbsolute();
a.setAttribute('data-transition', transition);
a.setAttribute('data-history', 'false');
di.getService('page').openLink(a);
}
V network konzoli prohlizece vidim v JSONu, ze se informace o zmene URL je soucasti odpovedi (viz http://imgur.com/agoPnUI), ale adresa se v prohlizeci nezmeni.
Delam neco spatne, nebo na to page.openLink
neni pripraven?
Diky moc!
Editoval Blujacker (29. 6. 2017 10:24)
- jahudka
- Člen | 71
Ahoj:
function nittroOpenLinkWorkaround(di, Url, url, params, transition)
{
// ...
// nezapomínej na "var" před lokální proměnnou!
var finalUrl = Url.from(url);
// tohle:
for (var key in params) {
finalUrl.setParam(key, params[key]);
}
// jde zjednodušit na:
finalUrl.addParams(params);
// ale hlavně, smaž / zakomentuj tohle:
a.setAttribute('data-history', 'false');
// ...
}
Editoval jahudka (29. 6. 2017 12:01)
- Blujacker
- Člen | 89
@jahudka moje blbost, dekuji. Nejak mi nedoslo, ze jsem nedal data-history do parametru a natvrdo dal false. Uz mi to funguje.
Dalsi problem se tyka abortovani soucasne bezicich requestu. Pokud mam nejaky snippet, ktery pravidelne refreshuji kazdych par sekund a kliknu na nejaky link, tak se obcas stane, ze automaticky refresh dostane prednost pred kliknutim a ten request abortne (viz screen http://imgur.com/a/36XLN)
Da se nejak nastavit priorita requestu? Protoze bych radsi, aby zafungovalo to kliknuti (napr nekam do menu), nez refresh snippetu
Dik moc za asistenci!
- jahudka
- Člen | 71
@Blujacker s trochou zpoždení oproti původnímu plánu jsem teď
releasnul aktualizovanou verzi nittro-page, ve který by mělo jít do parametru
context.transition
uvést selektor pro elementy, které se mají
animovat – takže ten workaround výše by neměl být potřeba. Snad to bude
fungovat :-) neměl jsem úplně čas to otestovat..
- revager
- Člen | 3
Ahoj,
snažím se nittro.js implementovat do jednoho projektu, ale narazil jsem na problém (nejspíš mé nepochopení problematiky) u formulářů.
Mám formulář:
<?php
class ClientFormFactory
{
use SmartObject;
public function create(callable $onSuccess)
{
$form = $this->formFactory->create();
$form->addText('name', 'Jméno klienta:')
->setRequired('Vyplňte prosím jméno klienta');
$form->addText('surname', 'Příjmení:')
->setRequired('Uveďte prosím příjmení klienta');
$form->addEmail('email', 'Emailová adresa:')
->setRequired('Uveďte platnou emailovou adresu');
$form->addSubmit('send', 'Vytvořit klienta');
$form->addProtection();
$form->onSuccess[] = function (Form $form, $values) use ($onSuccess) {
try{
$this->clientFacade->save($values->name, $values->surname, $values->email);
} catch (\Exception $ex){
$form->addError($ex->getMessage());
return;
}
$onSuccess();
};
return $form;
}
}
?>
V presenteru:
<?php
class ClientPresenter extends BasePresenter
{
protected function createComponentClientForm()
{
return $this->clientFormFactory->create(function (){
$this->flashMessage('Klient byl úspěšně vytvořen.', 'alert alert-success');
$this->postGet('Homepage:default');
$this->redrawControl('content');
});
}
}
?>
$clientFacade vrací exception. Pokud formulář odešlu bez nittro.js, tak správně skončí chybou (a ta je vykreslena v šabloně). Pokud ho ale odešlu s nittro.js, tak se mi do konzole vypíše chyba Failed to load resource: the server responded with a status of 502 (Bad Gateway) a má chyba (v tomto případě zpráva z exception) není vypsána do šablony.
Nevěděl by někdo, co dělám špatně? Za jakékoliv tipy děkuji :)
- kleinpetr
- Člen | 480
V SecuredPresenteru overuji identitu a pri selhani, provadim redirect na sign-in nicmene tento klasicky redirect se neprovede a misto toho v consoli dotanu
nittro.min.js:4 Uncaught (in promise) TypeError: Cannot read property 'trigger' of undefined
at tmp._doDispatch (nittro.min.js:4)
at <anonymous>
- jahudka
- Člen | 71
revager napsal(a):
Ahoj,
snažím se nittro.js implementovat do jednoho projektu, ale narazil jsem na problém (nejspíš mé nepochopení problematiky) u formulářů.
Mám formulář:
<?php class ClientFormFactory { use SmartObject; public function create(callable $onSuccess) { $form = $this->formFactory->create(); $form->addText('name', 'Jméno klienta:') ->setRequired('Vyplňte prosím jméno klienta'); $form->addText('surname', 'Příjmení:') ->setRequired('Uveďte prosím příjmení klienta'); $form->addEmail('email', 'Emailová adresa:') ->setRequired('Uveďte platnou emailovou adresu'); $form->addSubmit('send', 'Vytvořit klienta'); $form->addProtection(); $form->onSuccess[] = function (Form $form, $values) use ($onSuccess) { try{ $this->clientFacade->save($values->name, $values->surname, $values->email); } catch (\Exception $ex){ $form->addError($ex->getMessage()); return; } $onSuccess(); }; return $form; } } ?>
V presenteru:
<?php class ClientPresenter extends BasePresenter { protected function createComponentClientForm() { return $this->clientFormFactory->create(function (){ $this->flashMessage('Klient byl úspěšně vytvořen.', 'alert alert-success'); $this->postGet('Homepage:default'); $this->redrawControl('content'); }); } } ?>
$clientFacade vrací exception. Pokud formulář odešlu bez nittro.js, tak správně skončí chybou (a ta je vykreslena v šabloně). Pokud ho ale odešlu s nittro.js, tak se mi do konzole vypíše chyba Failed to load resource: the server responded with a status of 502 (Bad Gateway) a má chyba (v tomto případě zpráva z exception) není vypsána do šablony.
Nevěděl by někdo, co dělám špatně? Za jakékoliv tipy děkuji :)
Ahoj, promiň, já jsem tu na fóru jenom výjimečně a z nějakýho důvodu mi nepřišla noticka na mail, tak jsem si tvého dotazu všiml až teď :-( nevím přesně proč ti to vrací 502, ale každopádně si myslím, že háček bude v tom, že při selhání validace neinvaliduješ žádnej snippet – takže appka vrátí normální HTML. Nittro BasePresenter překresluje výchozí snippety jedině pokud aplikace nezpracovává žádnej signál (protože se předpokládá, že si v handleru překreslíš jenom to co potřebuješ) – a submit formuláře je signál. Možná že to je pak to co ti triggeruje i tu 502, pokud tam máš nějakou proxy – pokud by z clienta odcházel ten AJAX request s Accept hlavičkou která nějak zakazuje text/html, tak by ta proxy asi vyhodnotila odpověď serveru jako úplně vadnou.
- jahudka
- Člen | 71
kleinpetr napsal(a):
V SecuredPresenteru overuji identitu a pri selhani, provadim redirect na sign-in nicmene tento klasicky redirect se neprovede a misto toho v consoli dotanu
nittro.min.js:4 Uncaught (in promise) TypeError: Cannot read property 'trigger' of undefined at tmp._doDispatch (nittro.min.js:4) at <anonymous>
Ahoj, a co ti přijde v odpovědi na ten první AJAX požadavek na SecuredPresenter? Dostaneš normálně JSON s „redirect“: „nějaká URL“?
- jahudka
- Člen | 71
@kleinpetr aha, už to asi mám, byl tam bug – zkus si updatnout
Nittro, jestli si buildíš sám, tak npm update nittro-page
(nebo
npm update nittro
, podle toho co máš v
package.json
), jinak si stáhni aktuální build z https://nittro.org/download
- DominikDvorak94
- Člen | 14
Nevíte někdo proč mi píše Chrome v konzoli:
Construction of dialogs using data-dialog="<snippet id>" is deprecated, please update your code to use data-dialog="([<type iframe|form> ]<name>|self): (<snippet id>|<url>)".
a pak také pozor na:
[Deprecation] Using unescaped '#' characters in a data URI body is deprecated and will be removed in M67, around May 2018. Please use '%23' instead. See https://www.chromestatus.com/features/5656049583390720 for more details.
@jahudka asi bude nejvíce vědět :)
- jahudka
- Člen | 71
@DominikDvorak94 ahoj, to první je warning Nittra – nedávno jsem udělal takovej upgrade dialogů, jehož smyslem bylo řešit otevírání a zavírání dialogů trochu komplexnějc než to bylo doteď. Dialogy teď musí, podobně jako komponenty v Nette, mít jméno; zároveň existuje několik různejch typů dialogu který se používají na různý věci – základní typ funguje na všechny situace kdy uvnitř dialogu je normální DOM, ale třeba FormDialog má navíc API pro práci s formulářem uvnitř dialogu, dělá autofocus atd. IframeDialog pak umí v dialogu zobrazit iframe a řeší nějaké přechodné stavy a tak. A nakonec občas vznikne situace, kdy se o případném zavření dialogu rozhoduje až na backendu – např. když v dialogu zobrazíš formulář, chceš ho většinou zavřít až tehdy, kdy projdou i server-side validace, jinak ho chceš nechat zobrazenej a vyrenderovat v něm nějaký chybový hlášky atd. Proto se stávající konvence zavřít aktivní dialog při prvním dalším ajax requestu rozšířila o pár nových feature.
Typické workflow je takové, že otevřu dialog pomocí
data-dialog
, a uvnitř dialogu pak všechny odkazy / formuláře
které mohou způsobit že dialog zůstane otevřený mají
data-dialog="self"
; v obsluze příslušných signálů pak kromě
obvyklých redrawControl(...)
a případne
postGet(...)
ještě volám metodu
closeDialog(<nazev>)
(ComponentUtils
trait z nittro/nette-bridges
), která se postará o to, že dialog
na client side se zavře a zahodí. Zároveň existuje v
ComponentUtils
ještě metoda
openInDialog(<nazev>, <snippet nebo url>[, <typ>])
,
která umí otevření dialogu vyvolat ze serveru – tím by třeba šlo
řešit nějaký bezpečný confirm dialogy (bezpečný ve smyslu že fungujou
i bez JS – jen by se nezobrazily v dialogu).
Pokud chceš nějakej celej funkční example, mrkni se na Nittro Demo, konkrétně na PostPresenter
a jeho šablony default.latte
a form.latte
,
kde se to používá.
To druhý ale nevím – Nittro myslím s data URI moc nepracuje (jestli vůbec), nemáš k tomu nějakej trace kterej by pomohl odhalit kde to vzniká?
- Ages
- Člen | 128
Ahoj, nasadil jsem Nittro na svůj projekt a můsím říct že je to
vážně supr :) jen jsem narazil na menší zádrhel a to že se mi přepisuje
$title na původní hodnotu
Struktura šablon je:
<!-- @layout.latte -->
<html>
<head>
<title n:snippet="title">{ifset $title}{$title|stripHtml} | {/ifset}Super Web</title>
</head>
...
<!-- test.latte -->
{extends '../@layout.latte'}
{var $title = 'Test'}
{block content}
...
Takto mám postavenou celou aplikaci a před nasazením Nittro se mi
normálně generovaly správně nadpisy, ale nyní když přejdu jinam se mi
nejprve změní title na správnou v tomto případě na Test | Super Web a pak
se přepíše zpět na původní hodnotu.
Změna je téměř nepostřehnutelná a ano snippet title mám nasteven pro
defaultní překreslování.
Má někdo nápad co by to mohlo způsobovat?
- Václav Kraus
- Člen | 77
Ages napsal(a):
Ahoj, nasadil jsem Nittro na svůj projekt a můsím říct že je to vážně supr :) jen jsem narazil na menší zádrhel a to že se mi přepisuje $title na původní hodnotu
Struktura šablon je:<!-- @layout.latte --> <html> <head> <title n:snippet="title">{ifset $title}{$title|stripHtml} | {/ifset}Super Web</title> </head> ...
<!-- test.latte --> {extends '../@layout.latte'} {var $title = 'Test'} {block content} ...
Takto mám postavenou celou aplikaci a před nasazením Nittro se mi normálně generovaly správně nadpisy, ale nyní když přejdu jinam se mi nejprve změní title na správnou v tomto případě na Test | Super Web a pak se přepíše zpět na původní hodnotu.
Změna je téměř nepostřehnutelná a ano snippet title mám nasteven pro defaultní překreslování.Má někdo nápad co by to mohlo způsobovat?
Ahoj, taky se mi to chovalo zvláštně, tak title upravuju tímto způsobem:
public function renderDefault()
{
if($this->isAjax()){
$this->payload->title = 'Super titulek';
}
}
a funguje to korektně.
- Ages
- Člen | 128
Václav Kraus napsal(a):
Ages napsal(a):
Ahoj, nasadil jsem Nittro na svůj projekt a můsím říct že je to vážně supr :) jen jsem narazil na menší zádrhel a to že se mi přepisuje $title na původní hodnotu
Struktura šablon je:<!-- @layout.latte --> <html> <head> <title n:snippet="title">{ifset $title}{$title|stripHtml} | {/ifset}Super Web</title> </head> ...
<!-- test.latte --> {extends '../@layout.latte'} {var $title = 'Test'} {block content} ...
Takto mám postavenou celou aplikaci a před nasazením Nittro se mi normálně generovaly správně nadpisy, ale nyní když přejdu jinam se mi nejprve změní title na správnou v tomto případě na Test | Super Web a pak se přepíše zpět na původní hodnotu.
Změna je téměř nepostřehnutelná a ano snippet title mám nasteven pro defaultní překreslování.Má někdo nápad co by to mohlo způsobovat?
Ahoj, taky se mi to chovalo zvláštně, tak title upravuju tímto způsobem:
public function renderDefault() { if($this->isAjax()){ $this->payload->title = 'Super titulek'; } }
a funguje to korektně.
Díky moc vyzkouším :)