LWC podejście drugie
"JavaScript może być Twoim przyjacielem lub wrogiem, zależy jak go użyjesz"...
Po pierwszych sukcesach z LWC postanowiłem dalej zgłębiać ten temat. Na blogu Salesforce znalazłem artykuł na temat konwersji JSowego DatePickera na jego odpowiednik w LWC. Cały artykuł znajduje się TUTAJ .
Ponieważ nadal eksperymentowałem z FullCalendar nie bardzo chciało mi się pisać coś własnego. "Wygoda" używania zewnętrznych bibliotek w SF w połączeniu z Locker Service sprawiła, że przestudiowałem kod źródłowy owej biblioteki i zacząłem się zastanawiać, czy może dla sportu nie przepisać (skonwertować) jakiegoś niezbyt skomplikowanego skryptu JS na LWC. Miałem dylemat, ponieważ wybór skryptów (w tym wypadku z kalendarzem) jest ogromny. Zdecydowałem się jednak na TEN.
W międzyczasie Salesforce wypuścił swoje nowe dziecko - Live Development for LWC w wersji beta. W skrócie - jest to lokalny serwer LWC, który pozwala na development Lightning Web Componentów bez potrzeby robienia deployów na środowisko Salesforce. Dodatkowo zapewnia integrację z danymi na orgu. Niestety obecnie jeszcze nie wspiera Locker Service.
Tak więc uzbrojony w chęci przysiadłem do analizowania kodu. Pierwsze co musiałem zrobić to nieco inaczej podejść do szablonu HTML. Postanowiłem nie wrzucać nic dynamicznie za pomocą selektorów klas css tylko wykorzystać mechanizmy template z LWC oraz warunkowe renderowanie if:true. Po drugie nie chciałem korzystać z żadnych dodatkowych bibliotek związanych z datą i czasem (typu moment.js) aby w jak największym stopniu wykorzystać czysty JavaScript.
Tak więc przeniosłem markup HTML oraz style CSS do osobnych plików. Następnie zacząłem sukcesywnie przepisywać metody odpowiedzialne za renderowanie dni, miesięcy itp. Jak wspominałem wcześniej użyłem kolekcji obiektów poprzedzonych dekoratorem @track dzięki czemu komponent sam renderuje odpowiednie fragmenty w momencie pojawienia się danych w owych kolekcjach.
W projekcie użyłem trzech kolekcji obiektów (właściwie to 4 ale jednej jeszcze nie zaimplementowałem). Są to kolejno :
weekTemplate - znajduje się tu głównie definicja tygodni wraz z numerami dni (pon = 1, wt = 2 itd.) oraz definicją CSS dla aktywnego dnia w tygodniu.
monthTemplate - w tej kolekcji znajduje się definicja miesięcy, jak poprzednio wraz z numerami (tutaj jednak styczeń ma numer 0 - dzięki ci JavaScripcie) oraz klasami CSS.
daysTemplate - ta kolekcja przechowuje definicję dni w miesiącu, klasy CSS wybranego dnia oraz dzisiejszego.
Każda z powyższych kolekcji odpowiada za renderowanie odpowiedniej sekcji kalendarza. Metody odpowiedzialne za wypełnienie kolekcji danymi są niemal identyczne jak w oryginale. Pominąłem jednak globalną sekcję elements z oryginału. Nie była mi potrzebna. Zamiast dodawać w markupie Inner HTML użyłem iterowania po wyżej wymienionych kolekcjach. Dlatego też nie są to tylko zwykłe listy a listy obiektów. Każda z metod zapisuje te dane do tych list jak poniżej :
availableMonths.forEach((month, index) => {
let cssClass = index === calendar.active.month ? 'active' : '';
monthTemplate.push({num: index, cssClass: cssClass, month: month});
});
cssClass jest niezbędne aby trzymać odpowiednie style podczas renderowania odpowiednich sekcji. Ciekawą opcją jest dodawanie własnych data setów do markupu HTML dzięki czemu bardzo prosto można się do nich dobrać np. w metodach onclick i eventach.
Dla przykładu w sekcji renderującej miesiące mamy :
<template for:each={monthTemplate} for:item="item">
<li key={item.num} class={item.cssClass} data-month={item.month} data-monthnum={item.num} onclick={monthClick}>{item.month}</li>
</template>
data-month i data-monthnum to właśnie datasety do których dostęp mamy w evencie wykonanym po onclicku na danym elemencie :
let month = e.target.dataset.monthnum;
Działa to szybko i sprawnie.
Nie będę opisywał całego kodu, w 80% został on nietknięty względem oryginału. Konwersja nie jest jednak jeszcze kompletna. Pozostało dopisać sekcję z eventami w kalendarzu. Obecnie tego nie ma ale zostanie uzupełnione niebawem :)
Zapraszam do obejrzenia kodu w repozytorium : https://github.com/Trot-dms/LWC-Calendar