Částečná aktualizace stránky - partial update

Částečná aktualizace stránky - partial update

Edee.one rozhraní pracuje v ui s konceptem tzv. panelů, které se v jedná stránce postupně otevírají a modifikují její obsah. Nedochází tedy k přenačítání celé stránky, ale k úpravám domu jednou načtené stránky pomocí javascriptu.

Tento přístup je úzce spjatý s technikou partial update (také jako částečná výměna obsahu) - která umožnuje vracet ze serveru pouze fragmenty stránek a ty potom v prohlížeči vkládat na správné místo.

Stejného mechanizmu se použivá i při synchronizaci ui se stavem na serveru pomocí tzv. refresh event.

Technicky je použitý partial update RamJet frameworku, ze kterého Edee UI vychází. Obecně se využívá:

  • page manager - script běžící ve stránce starající se o správu panelů - rychlých oken, které se skládají v ui nad sebe
  • layout context - mechanizmus RamJetu, který zajisťuje prefixování DOM identifikátorů ve spojení s page managerem
  • partial update - script běžící ve stránce který provádí volání fragmentů stránek na základě nastavení v data atributech (v datasetu)
  • jsPartialUpdate - RamJet komponenta pro vymezení chování partial update mechanismu

Zkopírovat odkaz na sekciNastavení partial update na úrovni komponent

Primárně se váže na javascript událost spojenou s komponentou, např. při změně hodnoty. Definuje se v metadatech komponenty (odtud se nastavení kopírují do datasetu).

  • partialUpdate specifikace javascript události po které je partial update zahájen
  • partialUpdateTarget, partialUpdateWidget identifikátor widgetu, který chceme načíst ze serveru (při použití transparentControl je výsledkem pouze base komponenta, nikoliv obsah včetně kontejneru)
  • partialUpdateEventName, partialUpdateCommand umožňuje specifikovat název ramjet události, která bude vyvolána na straně serveru
  • partialUpdateSettings dodatečné vlastnosti po parametrizaci partial update požadavku

Pozor: Při kopírování hodnot partialUpdateTarget a partialUpdateWidget dochází k automatickému prefixování layoutContext, pokud je takový kontext pro vykreslení stránky použit. V rámci těchto metadat je také možné použít konstantu thisWidget, která použije id komponenty, ve které jsou metadata definována. Z tohoto důvodu není vhodné zapisovat metadata vztahující se k partialUpdate přímo do cílového dataset kontejneru.

Dotaz na widget, který je součástí transparentControl se bere v potaz pouze vnitřní komponenta, pokud je navíc tato komponenta obohacena podmínkou s renderOn pak je tato podmínka ignorována!

Zkopírovat odkaz na sekcipartialUpdateSettings vlastnosti

Název dataset vlastnostiMožné hodnotyDefaultPopis
targetstring, Arrayfalseid widget na serveru, nebo seznam id
urlstringnullnastavení url cílové stránky, pokud není nastavena je vypočítáno automaticky
requestTargetstringnullvolitelně přetížení id widgetu na serveru, který se použije místo target hodnoty
eventName, commandstringnullumožňuje specifikovat název ramjet události, která bude vyvolána na straně serveru (může přetížit hodnotu z partialUpdateEventName)
dataObjectnulldodatečné parametry (název, hodnota), které budou součástí partial update požadavku na server
dataMergeObjectnulldodatečné parametry s možností přetížení. Data se budou mergovat s odesílanými, tj. pokud v mergeDatech bude parametr, který je ve formuláři nebo url, tak bude přepsán
exceptParamsArraynullseznam parametrů, které se nemají na server odesílat - hodnoty oddělené čárkou
historyScopenone,parameters,allDataallDataVkládá do historie prohlížeče v rámci záměny obsahu i původní url s vybranými vstupními parametry, které umožní stránku správně obnovit. Je možné vybrat pouze nic, pouze parametry nebo parametry a všechna data komponent. Při poslední volbě je nutné zvážit omezení na délku URL.
removeContainerWidgetDataArraynullTODO neodešle na server widget data (frm.) uvnitř aktualizovaného targetu
timeoutnumber60000timeout v ms pro response ze serveru
layoutContextstringnullpro propagaci layout context id prefixu
submitIdstringnullid formuláře nebo tlačítka uvnitř formuláře TODO k čemu?
scrollboolean,top,bottomfalsepříznak zascrolování po zpracování výsledku TODO funguje v edee?
scrollOffsetnumber25počet px zascrolování po zpracování výsledku
scrollDurationnumber200délka animace scrolování
globalTargetstringdynamicAreavyužívá se při pohybu historie, mělo by to být id elementu, které se nachází na každé stránce webu
pickArrayfalsepole selectorů, které se mají nahradit
omitArrayfalsepole selectorů, které se nemají nahrazovat
headersObjectnulldoplňkové hlavičky požadavku na server
typeStringPOSThttp metoda požadavku TODO funguje?
ajaxObjectnullodstraněno (využívala původní jquery implementace)

Zkopírovat odkaz na sekcipartialUpdateSettings příznaky

Název dataset vlastnostiMožné hodnotyDefaultPopis
alterHistorybooleanfalsenastavení, zda se má po dokončení PU zaktualizovat history state prohlížeče
removeFormIdbooleanfalsepříznak zda při požadavku odstranit identifikátor konverzace (pro formPage bude požadavek součástí nové konverzace)
removeFormWidgetDataArray, booleannullpříznak (nebo seznam parametrů) pro vynechání widget dat parametrů (frm.) na server
suppressRedirectbooleanfalsepokud je odpověd ze serveru 302 pak - false vynutí refresh stránky, jinak zpracuje výsledek přesměrování
cachebooleanfalsepříznak XHR požadavku pro cachování TODO používá se?
rememberPaginationbooleanfalsepříznak zda využít hodnotu stránkování - hledá element s atributem data-fragment="pagination" a na něm aktuální stav stránkování
disposeAndDecorateLifecyclebooleantruepříznak pro korektní destroy lifecycle všech vnořených web komponent
generateReplacementContainerbooleanfalsepříznak jestli se má nahrazovaný obsah obalit do DIV elementu s css třídou "partialUpdateDynamicContainer"
formsChangesDetectionbooleanfalsepříznak kterým se aktivuje kontrola modifikovaného formuláře, která přeruší akci a zavolá onFormsChangesDetect
includeToProgressbooleantruepříznak zda je žádoucí zobrazovat identifikace běžící akce (probress bar, spinner)
mergeWithTargetSettingsbooleantruepříznak, který který určuje, zda přebírat nastavení z dataset atributů z dom prvku dle hodnoty target nebo submitId
dataFromAllFormsInDocumentbooleantruepříznak určuje jestli se se mají na server odesílat data ze všech formulářu v documentu (true), které mají stejný atribut action. Pokud se v nejakých formulářích vyskytují stejná widget data, tak se na server odešlou jen z prvního formuláře
historyReplaceStatebooleanfalsepříznak zda po úspěšném vykonání PU je do historie prohlížeče proveden push nebo replace
persistFocusbooleantruepříznak který zajišťuje zachování focusu ve formuláři, uvnitř input elementů zachovává i pozici kurzou
moveUrlQueryParamsToFormDataOnPostbooleanfalsepři POST požadavku převede všechny query parametry jako form data. Eliminuje tak problém s dlouhou url, což bývá maximálně 2083 znaků.
clearCachebooleannullodstraněno (využívala původní jquery implementace)

Zkopírovat odkaz na sekcipartialUpdateSettings funkce pro vlastní rozšíření

Název dataset vlastnostiMožné hodnotyDefaultPopis
onAlterHistoryfunctionnullcallback funkce
onErrorfunctionnullfunkce která se zavolá v případě vyskytnutí se chyby během vykonání partial updatu. Jde např. využít pro zobrazení dialogu s chybou
onAfterContentsReplacefunctionnullcallback funkce
onCompletefunctionnullcallback funkce
replaceContentsfunctionnullcustom replace funkce
replaceTargetContentfunctionnullcustom replace funkce
onBeforeContentsReplacedfunctionnullcallback funkce
onFormsChangesDetectfunctionnullcallback funkce
onBeforeExecutefunctionnullcallback funkce

Zkopírovat odkaz na sekcihodnoty nastavitelné v datasetu mimo partialUpdateSettings

Tyto hodnoty lze doplnit přímo do datasetu komponenty, případné stejné hodnoty v partialUpdateSettings mají vyšší prioritu.

  • partialUpdateUrl nastavení url cílové stránky, pokud není nastavena je vypočítáno automaticky
  • partialUpdateRequestTarget, partialUpdateTargetHtmlContainer Id elementu, který pomocí PU chceme zaktualizovat (pokud je potřeba ze serveru načíst jiný container než je na clientu nahrazován)
  • partialUpdateData Dodatečné parametry (název, hodnota), které budou součástí partial update požadavku na server.
  • partialUpdateAlterHistory Příznak, zda se má po dokončení PU zaktualizovat history state prohlížeče

Je možné použít i variantu s náhradou partialUpdate za pu - např. puUpdateUrl - zkrácené varianty mají vyšší prioritu než plné, ale nižsí než hodnoty v partialUpdateSettings.

Zkopírovat odkaz na sekcipříklady

Přenačtení po akci komponenty

xml
1 <!-- po výběru hodnoty dojde k přenačtení widgetu "objectPreview" -->2<tileButtonSelect id="pageTreePrototype">3    <dataSource type="selectablePrototypesProvider"/>4    <metadata>5        <icon>[#item[].properties[icon]#]</icon>6        <partialUpdate>change</partialUpdate>7        <partialUpdateWidget>objectPreview</partialUpdateWidget>8    </metadata>9</tileButtonSelect>
xml
1 <!-- po uploadu dojde k aktualizaci "record" komponenty a vyvolání command eventy "updateWarning" -->2<uploadButton id="upload">3    <metadata>4        <partialUpdate>uploadcomplete</partialUpdate>5        <partialUpdateWidget>record</partialUpdateWidget>6        <partialUpdateCommand>updateWarning</partialUpdateCommand>7    </metadata>8</uploadButton>
xml
1 <!-- alternativní definice settings přímo v datasetu -->2<baseReactSelect id="webId">3    <dataSource type="cpsWebSelectableItemsProvider"/>4    <metadata>5        <partialUpdate>change</partialUpdate>6        <partialUpdateTarget>layout</partialUpdateTarget>7        <dataset>8            <puSettings>9                <exceptParams>parentId</exceptParams>10            </puSettings>11        </dataset>12    </metadata>13</baseReactSelect>

Modifikace možností refreshEvent

xml
1 <!-- refresh porvést bez odeslání widget dat (frm parametrů) -->2<nestedGrid id="grid">3    <metadata>4        <dataset mode="combine">5            <refreshEvent>6                <event>updateFile, moveFile</event>7                <puSettings>8                    <removeFormId>false</removeFormId>9                    <removeFormWidgetData>true</removeFormWidgetData>10                </puSettings>11            </refreshEvent>12        </dataset>13    </metadata>14    ..15</nestedGrid>
xml
1 <!-- refresh provede jako GET -->2<relatedPagesSelect id="localizedPagesTreeSelect">3    <dataSource type="relatedPagesDataProvider" category="LOCALIZE" />4    <population type="alwaysClear"/>5    <metadata>6        <dataset>7            <refreshEvent>8                <event>createLocalization</event>9                <validAttributes>10                    <sourceId>#widget[record].record.primaryKey!0#</sourceId>11                </validAttributes>12                <puSettings>13                    <removeFormId>true</removeFormId>14                    <removeFormWidgetData>true</removeFormWidgetData>15                    <type>GET</type>16                </puSettings>17            </refreshEvent>18        </dataset>19    </metadata>20</relatedPagesSelect>

nastavení přímo v data atributech

Jsou podporovány následující hodnoty:

  • data-partial-update
  • data-partial-update-url, data-pu-url
  • data-partial-update-request-target, data-pu-request-target
  • data-partial-update-target-html-container, data-pu-target-html-container
  • data-partial-update-target, data-pu-target, data-partial-update-widget, data-pu-widget
  • data-partial-update-command, data-pu-command, data-partial-update-event-name, data-pu-event-name
  • data-partial-update-data, data-pu-data
  • data-partial-update-alter-history, data-pu-alter-history
  • data-partial-update-settings, data-pu-settings

Ostatní lze vložit jako JSON přímo do data-pu-settings.

Příklad použití definice přímo ve FTL šabloně

html
1 <div data-pu-url="<@qf.pageUrl urlToIdentify="/edee/comment/addComment?ot=${comment.objectType}&oi=${comment.objectId}&rot=edeeComment&roi=${comment.id}" />"2     data-partial-update="click"3     data-partial-update-target="rpl${comment.id}"4     data-partial-update-settings="{ &quot;requestTarget&quot;: &quot;addPostArea&quot;, &quot;alterHistory&quot;: false, &quot;suppressRedirect&quot;: &quot;false&quot;, &quot;exceptParams&quot;: [&quot;objectId&quot;,&quot;objectType&quot;,&quot;referencedObjectId&quot;,&quot;referencedObjectType&quot;] }"5>6    <a href="#">${rjf.label('reply')}</a>7    <blockquote>${comment.text}</blockquote>8</div>

tecnické detaily - z obecné dokumentace

Libovolnou RamJet komponentu (nebo více komponent) je možné si nechat serverem vykreslit samostatně bez ohledu na zbytek stránky. Stačí k tomu sestavit správně URL následujícím způsobem:

1 /qf/jazyk/modul/cesta/ke/strance@idKomponenty2/qf/jazyk/modul/cesta/ke/strance@idKomponentyA+idKomponentyB

Server následně vrátí pouze HTML odpovídající daným komponentám, které jse možné na klientu vyměnit bez kompletní reinicializace celé stránky.

Zkopírovat odkaz na sekcihttp hlavičky a suppressRedirect

Funkcionalita umožnuje nahradit 302 redirect za mechanizmus, kdy server pouze odešle http hlavičku (FULL_PAGE_REDIRECT) a klient zpracuje výstup této stránky, pokud je v ní cílová komponenta dostupná.

Partial update pracuje dále s těmito hlavičkami

Http hlavičkapopis
FULL_PAGE_REDIRECTVyžadováno ve chvíli, kdy klient požádá o AJAX partial update výměnu stránky, ale server rozhodne o přesměrování na strukturálně jinou stránku, vůči které není možné partial update provést. Např. chci si vyměnit select a server místo toho rozhodne, že vypršela session a potřebuje fullscreen přesměrovat na login page.
RamJet-RequestedUrlVyžadováno pro správné fungování partial update - pokud server provede přesměrování přes HTTP302 a tudíž naviguje na odlišnou URL, klient se o této nové URL z API XmlHttpRequestu nedozví (je tam auto-follow redirects). Skrze tuto hlavičku dokážeme informovat JS o správné aktuální URL, se kterou má nadále pracovat.
RamJet-RequestedParametersSouvisí s hlavičkou RamJet-RequestedUrl - slouží k přenosu vstupních parametrů z Query stringu.
RamJet-ErrorSignalizuje validační chybu / chybu vykonání akce ('true' pokud je chyba). Slouží pro JS, aby např. detekoval tuto situaci a nezavřel aktuálně otevřený popup apod.

Zkopírovat odkaz na sekciZákladní chování je následující

TODO revize

  • pokud dojde k submitu formuláře na stejnou stránku, dojde pouze k AJAXové výměně dat a náhradě obsahu celého jsPartialUpdate
  • pokud dojde ke kliknutí na odkaz uvnitř jsPartialUpdate a odkaz směřuje na stejnou stránku, dojde pouze k AJAXému načtení dat a částečné výměně obsahu bez reinicializace stránky
  • pokud dojde ke kliknutí na odkaz uvnitř jsPartialUpdate a zároveň uvnitř HTML formuláře a odkaz směřuje na stejnou stránku, posbírají se aktuální data z formuláře, spojí se s parametry linku a vše se odešle AJAXem na server a vrácená odpověď se v obsahu vymění bez reinicializace stránky

Platí pravidlo, že pokud není řečeno jinak, vyměňuje se vždy celý obsah jsPartialUpdate komponenty. Server zpracovává požadavek na částečné přenačtení stránky úplně stejně jako každý jiný požadavek. Tj. jsou standardně spouštěna všechna přerušení, konverze, validace, akce - vyjímkou je pouze zpracování "render" fáze, kdy dojde k vykreslení pouze části komponent a ne celé stránky. Toto je velmi důležité si uvědomit, především kvůli správě paměti na straně serveru - tj. u stránek, které si na straně serveru neudržují žádná data, musíme vždy poslat všechny parametry nutné k jejich správnému fungování.