Ciele

  1. Naučiť sa ako údaje z objektov v JavaScript-e pretransformovať do HTML pomocou šablónových literálov (template literals).
  2. Naučiť sa ako údaje z objektov v JavaScript-e pretransformovať do HTML pomocou šablónovacieho systému Mustache.
  3. Aplikovať transformáciu údajov z objektov v JavaScript-e do HTML pomocou šablónových literálov alebo Mustache do vášho blogovacieho systému (Úloha 4).

Úvod

    Na minulom cvičení ste sa naučili ako prečítať údaje z formulára a tiež ako ich uložiť do window.localStorage a odtiaľ prečítať. Dnes si vyskúšate, ako tieto údaje namiesto vypisovania do konzoly vložiť priamo do HTML kódu stránky.

    Urobíte to dvoma spôsobmi:

    Vyskúšate si to najprv na príklade blogu o obľúbených stromoch (My Favourite Trees) a potom vo vašom vlastnom blogovacom systéme.

    Na rozdiel od predchádzajúceho cvičenia, bude váš JavaScript kód umiestnený vo viacerých samostatných skriptoch typu modul [5] a jednotlivé moduly budú vytvorené ako triedy [6].

    Poznámka: Všetko potrebné na splnenie dnešných úloh ste sa dozvedeli z prednášok 4 až 7 ([1], [2], [3], [4]). Na podrobné oboznámenie sa s jazykom JavaScript odporúčame zdroje [7] a [8]. Ako používať knižnicu Mustache zistíte z prednášky [4], príkladov [15] a dokumentácie na [13].
    S problematikou, ktorú máte dnes zvládnuť vás podrobne oboznámia aj prvé dve úlohy tohto cvičenia.

Postup

  1. V príklade (aplikácii) 57myTreesFormLStorageHtml je už aplikované spracovanie údajov do HTML pomocou šablónových literálov. Podobne ako v príklade 55myTreesFormLStorageConsole.html je to však urobené len pre položky name, created a comment. Vy teraz doplníte spracovanie údajov do html v upravenej verzii príkladu 57myTreesFormLStorageHtml, kde je aj položka willReturn ale chýba kód na spracovanie do HTML.
    Úloha: V aplikácii myTreesFormLStorageHtmlWr doplňte spracovanie údajov do HTML tak, aby sa:
    • Pri načítaní stránky všetky položky, ktoré sa z localStorage načítali do poľa opinions, zobrazili v elemente div s id="opinionsContainer".
    • Po odoslaní údajov z formulára sa nový názor (newOpinion) nezapísal iba do poľa opinions ale pridal aj do HTML na koniec elementu div s id="opinionsContainer".
    Z položky created zobrazte iba dátum, nie čas. Na vytvorenie HTML kódu využite šablónové literály. Váš JavaScript kód píšte vo forme modulov [5], kde jednotlivé moduly sú triedami [6].
    Úlohu môžete riešiť samostatne. Komentáre //TODO v JavaScript súboroch aplikácie vám napovedia kde je aký kód potrebné vložiť. Alebo môžete použiť nasledujúci kompletný postup riešenia:

    1. Stiahnite si a rozbaľte archív myTreesFormLStorageHtmlWr.zip s aplikáciou. Ďalej budete pracovať s touto rozbalenou verziou aplikácie. Nasledujúce kroky, okrem posledného, budete robiť v JavaScript súbore opinionsHandler.js s triedou OpinionsHandler, ktorý je v podpriečinku js.

    2. V konštruktore triedy komentáre
      
      //TODO Add opinionsElm property, referencing the div with id given by the parameter opinionsListElmId
      //TODO Add opinionsFrmElm property, referencing the form with id given by the parameter opinionsFormElmId                   
                      
      nahraďte kódom
      
      this.opinionsElm = document.getElementById(opinionsListElmId);
      this.opinionsFrmElm = document.getElementById("opnFrm");
                      
      Urobili sme to, aby sme príslušné elementy nemuseli opätovne vyhľadávať v DOM. Ušetríme tak čas aj energiu zariadenia na ktorom bude aplikácia zobrazená.

    3. Vo funkcii (metóde) opinion2html nahraďte komentár
      //TODO finish opinion2html
      kódom
      
      const opinionTemplate=
      `
          <section>
             <h3>${opinion.name} <i>(${(new Date(opinion.created)).toDateString()})</i></h3>
      
             <p>${opinion.comment}</p>
             <p>${opinion.willReturn?"I will return to this page.":"Sorry, one visit was enough."}</p>
          </section>`;
      return opinionTemplate;
                      
      Tu je využitý šablónový literál opinionTemplate na vyrobenie HTML kódu z údajov v objekte opinion. Všimnite si, že v šablónových literáloch môžeme používať aj zložitejšie výrazy ako len názvy premenných alebo ich vlastností (položiek). Na spracovanie vlastnosti willReturn sme využili ternárny operátor.

    4. Vo funkcii (metóde) opinionArray2html nahraďte komentár
      //TODO finish opinionArray2html
      kódom
      return sourceData.reduce((htmlWithOpinions,opn) => htmlWithOpinions+ this.opinion2html(opn),"");
      Tento kód vygeneruje HTML so všetkými názormi z poľa sourceData (Pri jej volaní ako parameter použijeme pole opinions).

      Poznámka: Funkcia opinionArray2html využíva funkciu Array.prototype.reduce. Ak sa vám táto zdá príliš zložitá na pochopenie, tu je jednoduchšia verzia kódu opinionArray2html, ktorá používa príkaz cyklu for...of:

      
      let htmlWithOpinions="";
      
      for(const opn of sourceData){
          htmlWithOpinions += this.opinion2html(opn);
      }
      
      return htmlWithOpinions;
                      

    5. Vo funkcii (metóde) init komentár
      //TODO render opinions to html
      nahraďte kódom
      this.opinionsElm.innerHTML = this.opinionArray2html(this.opinions);
      Takto sa obsah poľa opinions, ktorý funkcia opinionArray2html spracovala do HTML, dostane do elementu opinionsElm (div). Tento kód sa vykoná pri načítaní stránky (aplikácie) v prehliadači.

    6. Komentár
      //TODO add the new opinion to HTML
      vo funkcii processOpnFrmData nahraďte kódom
      this.opinionsElm.innerHTML+=this.opinion2html(newOpinion);
      Tým sa práve spracovaný názor (z opinion) dostane do HTML na koniec elementu opinionsElm.

    7. v JavaScript súbore myTreesFormLStorageHtmlWr.js komentár
      //TODO create the object window.opnsHndlr of the class OpinionsHandler and run its init method
      nahraďte kódom
      
      window.opnsHndlr = new OpinionsHandler("opnFrm","opinionsContainer");
      window.opnsHndlr.init();                    
                      
      Takto vytvoríte a inicializujete objekt opnsHndlr triedy OpinionsHandler, prepojený na príslušné html elementy.

  2. Teraz výsledok predchádzajúcej úlohy upravíte tak, aby bola namiesto šablónového literálu použitá šablóna systému Mustache. Využijeme pri tom aj dedičnosť tried.
    Úloha: V priečinku js vytvorte JavaScript modul opinionsHandlerMustache.js s triedou OpinionsHandlerMustache, ktorá je potomkom triedy OpinionsHandler a líši sa od nej v tom, že namiesto šablónového literálu používa šablónu systému Mustache. Mustache šablónu vložte ako nový element do myTreesFormLStorageHtmlWr.html. Skript myTreesFormLStorageHtmlWr.js upravte tak, aby použil objekt triedy OpinionsHandlerMustache namiesto OpinionsHandler.
    Úlohu môžete riešiť samostatne, podľa príkladu 66myTreesFormLStorageMstch (stiahnuteľná verzia: 66myTreesFormLStorageMstch.zip). Alebo môžete použiť nasledujúci kompletný postup riešenia:

    1. Do súboru 57myTreesFormLStorageHtmlWr.html doplňte nový element
      
      <script id="mTmplOneOpinion" type="text/template">
          <section>
              <h3>{{name}} <i>{{createdDate}}</i></h3>
              <p>{{comment}}</p>
              <p>{{willReturnMessage}}</p>
          </section>
      </script>     
                      

      Nie je dôležité, kde presne ho vložíte. Môžete ho dať napríklad pred element script, ktorý ste vložili v predchádzajúcom kroku.

      Tento nový element obsahuje Mustache šablónu pre zobrazenie názoru. V šablóne sú dve vlastnosti (položky), ktoré sa v objektoch nenachádzajú. Sú to createdDate a willReturnMessage. Je to preto, lebo hodnoty z položiek created a willReturn, ktoré v objekte sú, nechceme zobraziť priamo ale až po spracovaní. Keďže Mustache šablóny sú bez logiky (logic-less), takéto spracovanie priamo v šablóne neumožňujú. Musíme ho teda urobiť predtým a spracované údaje do objektu pridať. Možno sa vám to zdá obmedzujúce, no autori Mustache takto chceli zabrániť tomu, aby sa do ich šablón dostali príkazy programovacieho jazyka.



    2. V priečinku js vytvorte JavaScript modul opinionsHandlerMustache.js a vložte doň kód
      
      import OpinionsHandler from "./opinionsHandler.js";
      import Mustache from "./mustache.js";
      
      export default class OpinionsHandlerMustache extends OpinionsHandler{
      
          constructor(opinionsFormElmId, opinionsListElmId,templateElmId) {
      
              //call the constructor from the superclass:
              super(opinionsFormElmId, opinionsListElmId);
      
              //get the template:
              this.mustacheTemplate=document.getElementById(templateElmId).innerHTML;
          }
      
          opinion2html(opinion){
              //in the case of Mustache, we must prepare data beforehand:
              opinion.createdDate=(new Date(opinion.created)).toDateString();
      
              //use the Mustache:
              const htmlWOp = Mustache.render(this.mustacheTemplate,opinion);
      
              //delete the createdDate item as we created it only for the template rendering:
              delete(opinion.createdDate);
      
              //return the rendered HTML:
              return htmlWOp;
          }
      }
                      
      Táto trieda funguje rovnako ako OpinionsHandler, no namiesto šablónového literálu používa Mustache šablónu. Všimnite si, že do objektu opinion sme pred použitím šablóny pridali vlastnosti createdDate a willReturnMessage. Po jej použití sme ich odstránili. Súbor mustache.js, ktorý sa v priečinku js už nachádza, je mustache.mjs stiahnutý zo stránky [14] a premenovaný na mustache.js.

      Poznámka: V mnohých prípadoch je považované za bezpečnejšie namiesto modifikácie pôvodných údajov vytvoriť nové údaje, určené iba pre zobrazenie. Tento spôsob ochráni pôvodné údaje pred nechcenou modifikáciou. Na druhej strane je však zdĺhavejší a vyžaduje viac pamäte. Ak chcete aplikovať tento spôsob, použite pre funkciu opinion2html nasledujúci kód:

      
      const opinionView ={
          name: opinion.name,
          comment: opinion.comment,
          createdDate: (new Date(opinion.created)).toDateString(),
          willReturnMessage:
            opinion.willReturn?"I will return to this page.":"Sorry, one visit was enough."
      };
      
      return Mustache.render(this.mustacheTemplate,opinionView);
                          



    3. v JavaScript súbore myTreesFormLStorageHtmlWr.js riadky
      
      import OpinionsHandler from "./opinionsHandler.js";
      
                          
      window.drMenuCntrl = new DropdownMenuControl("menuIts", "menuTitle", "mnShow");
                          
      window.opnsHndlr = new OpinionsHandler("opnFrm","opinionsContainer");
      window.opnsHndlr.init();                    
                      
      nahraďte kódom
      
      import OpinionsHandlerMustache from "./opinionsHandlerMustache.js";
      
                          
      window.drMenuCntrl = new DropdownMenuControl("menuIts", "menuTitle", "mnShow");
      
      window.opnsHndlr = new OpinionsHandlerMustache("opnFrm","opinionsContainer","mTmplOneOpinion");
      window.opnsHndlr.init();                 
                      


  3. Keďže už viete, ako údaje z objektov v JavaScript dostať do HTML, môžete túto funkcionalitu implementovať aj do vášho blogu, ktorý vytvárate ako zadanie z tohto predmetu.
    Úloha: HTML a JavaScript kód úvodnej stránky vášho blogu rozšírte tak, aby sa údaje o názoroch návštevníkov vášho blogu zobrazovali aj priamo na jeho úvodnej stránke, v na to určenom HTML elemente. Na vytváranie HTML použite šablónové literály (template literals) alebo šablónovací systém Mustache.
    Použite objektovo-orientovaný prístup a triedy OpinionsHandler a OpinionsHandlerMustache, uložené v samostatných moduloch v adresári js, tak ako v predchádzajúcich úlohách.
    Všetky položky uložených názorov majú byť zobrazené na stránke a to vhodnou formou.
    Úlohou je vlastne váš blog, ktorý je po minulom cvičení na úrovni príkladu 55myTreesFormLStorageConsole pozdvihnúť na úroveň príkladu 57myTreesFormLStorageHtml alebo príkladu 66myTreesFormLStorageMstch.

    Poznámka: Keď použijete Mustache, môžete získať viac bodov ako za použitie šablónových literálov. (podrobnosti zistíte v popise k nasledujúcemu cvičeniu).

Zdroje

  1. Prednáška 4.
  2. Prednáška 5.
  3. Prednáška 6.
  4. Prednáška 7.
  5. JavaScript modules at MDN web docs (tutorials and reference), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules.
  6. JavaScript classes at MDN web docs (tutorials and reference), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes.
  7. JavaScript at MDN web docs (tutorials and reference), https://developer.mozilla.org/en-US/docs/Web/JavaScript.
  8. The Modern JavaScript Tutorial, https://javascript.info/.
  9. Template literals at MDN web docs, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals.
  10. Client-side form validation at MDN web docs, https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation.
  11. Detecting device orientation at MDN web docs, https://developer.mozilla.org/en-US/docs/Web/API/Detecting_device_orientation#Orientation_example.
  12. Pete LePage: Device Orientation and Motion, https://developers.google.com/web/fundamentals/native-hardware/device-orientation/.
  13. Mustache Manual, https://mustache.github.io/mustache.5.html.
  14. JavaScript knižnica pre Mustache, https://github.com/janl/mustache.js.
  15. Príklady k Mustache, https://hron.fei.tuke.sk/~korecko/WT/06JsMustchSpa/.
  16. Device orientation and motion demo, https://hron.fei.tuke.sk/~korecko/WT/05JsZaklady/58devMotionOrientation.html.
  17. Stiahnuteľné verzie vybraných príkladov k prednáškam, https://hron.fei.tuke.sk/~korecko/WT/Downloads/.

Doplňujúce úlohy

    Úloha: Na koniec zoznamu názorov návštevníkov doplňte tlačidlo po stlačení ktorého sa vymažú všetky názory staršie ako 1 deň. Vymazať sa majú z localStorage, príslušného JavaScript objektu aj HTML kódu.

    Poznámka: Ak by sme toto chceli implementovať do výslednej podoby aplikácie 57myTreesFormLStorageHtmlWr alebo do príkladu 66myTreesFormLStorageMstch, postupovali by sme nasledovne:

    1. Nové tlačidlo by sme dali za element div s id="opinionsContainer".
    2. Do JavaScript funkcie, ktorá sa zavolá pri stlačení tlačidla by sme dali kód, ktorý:
      1. Vymaže z poľa opinions všetky objekty s názormi staršími ako deň. Ako zistiť ktoré sú staršie ako deň vám napovie nasledujúci výraz
        Date.now() - new Date(opinions[0].created);
        ktorý vypočíta rozdiel medzi terajším dátumom a časom a dátumom a časom vytvorenia prvého názoru v poli opinions v milisekundách.
      2. Uloží pole opinions do localStorage.myTreesComments.
      3. Znova vytvorí obsah div s id="opinionsContainer" podľa opinions.

    Úloha: V našich príkladoch sa na chybu používateľa pri vypĺňaní formulára, ktorá sa zachytí v JavaScript kóde, upozorní pomocou modálneho dialógového okna, vyvolaného funkciou window.alert(). Používanie modálnych dialógových okien ale nie je vhodné, používateľa je potrebné upozorniť inak. Zistite ako a implementujte to do JavaScript časti validácie formulára vo vašum blogu.

    Poznámka: Niečo o tom ako používateľa upozorniť sa dozviete na konci článku [10].

    Úloha: Vytvorte samostatnú stránku sensorApp.html s jednoduchou web aplikáciou využívajúcou udalosti senzorov pohybu. Môže ísť o hru alebo vhodnú vizualizáciu údajov zo senzorov.

    Poznámka: Udalosti senzorov boli na prednáške [3], Príklad ich použitia nájdete na [16]. Viac sa o nich dočítate aj v článkoch [11], [12].