#Angular2 – Terminarz cz. 1

Praca nad projektem w końcu ruszyła pełną parą. Matury już prawie skończone, został tylko polski i już mam jedną rzecz z głowy. Ostatnie kilka dni w moim życiu trochę pogorszyło moje samopoczucie, ale mam nadzieję, że nie wpłynie to na mój projekt.

Skończyłem już w całości zarządzanie usługami. Komponent usługi, jest bardzo podobny do komponentów magazyn i pracownicy, więc wystarczy tylko skopiować jego funkcjonalność i mam gotowe trzy komponenty. W dokumentach zostały mi dwie rzeczy. Jedna to edycja danych dokumentu, z tym uwinę się szybko, a druga to generowanie PDF. Z tym drugim mogę mieć problemy, ale jestem dobrej myśli. Prawdopodobnie skorzystam z PDFKit. Biblioteka ta wygląda na dość prostą w obsłudze, więc mam nadzieję, że również pójdzie szybko.

Kiedy już ukończę w całości komponent dokumentów, zabieram się za zlecenia. Zlecenia są dość podobne do dokumentów, więc w większości również będzie to kopiowanie kodu.

Postanowiłem więc, że zajmę się komponentem terminarza. Miałem już gotowy wygląd, ale musiałem wymyślić sposób, żeby wyświetlić go w odpowiedni sposób jak kalendarz. Tzn., żeby dni tygodnia zgadzały się z dniami w miesiącu. Chciałem na początku skorzystać z jakichś gotowych bibliotek / komponentów dostępnych w npm, ale żaden z nich mi nie odpowiadał, albo nie działał, albo był zbyt masywny.

Postanowiłem więc, że napiszę wszystko od nowa. Założenie jest takie, że kalendarz mieści się w 6 wierszach i 7 kolumnach i wyświetla koniec poprzedniego i początek następnego miesiąca.

Stworzyłem więc coś takiego:

getArray(year, month){
    this.calendar = [];

    let daysInMonths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    if((year%4==0 && year%100!=0) || year%400==0){
        daysInMonths[1] = 29;
    }
    
    let daysInMonth = daysInMonths[month];

    let firstDayOfMonth = new Date(year, month);
    let firstDayOfWeek = firstDayOfMonth.getDay();
    let daysBefore = null;

    if(firstDayOfWeek == 0)
        daysBefore = 6;
    else if(firstDayOfWeek == 1)
        daysBefore = 7;
    else
        daysBefore = firstDayOfWeek - 1;
     
    let daysAfter = 42 - daysInMonth - daysBefore;

    let daysInMonthBefore = daysInMonths[month - 1];
    if(month-1 == -1)
    {
        daysInMonthBefore = daysInMonths[11];
    }

    let monthBefore = month - 1;
    let yearBefore = year;
    if(monthBefore == -1)
    {
        yearBefore = year - 1;
        monthBefore = 11;
    }

    for(let i = daysBefore - 1; i >= 0; i--)
    {
        this.calendar.push({
          number: daysInMonthBefore - i,
          date: new Date(yearBefore, monthBefore, daysInMonthBefore - i),
          inactive: true
        });
    }

    for(let i = 1; i <= daysInMonth; i++)
    {
        this.calendar.push({
          number: i,
          date: new Date(year, month, i),
          inactive: false
        });
    }

    let monthAfter = month+1;
    let yearAfter = year;
    if(monthAfter == 12)
    {
        let monthAfter = 0;
        let yearAfter = year + 1;
    }

    for(let i = 1; i <= daysAfter; i++)
    {
        this.calendar.push({
          number: i,
          date: new Date(yearAfter, monthAfter, i),
          inactive: true
        });
    }

    return this.calendar;
}

Algorytm jest dość długi, więc nie będę opisywał każdej linijki, ale opiszę mniej więcej jego zasadę działania. Metoda getArray() jest umieszczona w usłudze callendar.service i zwraca ona tablicę obiektów z dniami w kalendarzu.

Działanie jest dość proste. Na początku wyliczam ilość dni z poprzedniego miesiąca. Żeby to wyliczyć, sprawdzam dzień tygodnia pierwszego dnia miesiąca. Muszę pamiętać o tym, że tydzień w obiekcie date w JS zaczyna się od niedzieli, czyli niedziela – 0 poniedziałek – 1 itd. Sprawdzam więc, czy pierwszy dzień jest poniedziałkiem. Jeśli tak, to liczba dni z poprzedniego miesiąca wynosi 7, jeśli jest niedzielą, to 6, a dla każdego następnego dnia tygodnia, wynosi numerDniaTygodnia – 1.

Kiedy już policzę ilość dni przed, to dalej jest już z górki. Ilości dni w miesiącu mam zapisane w tablicy. Więc dla danego miesiąca (miesiące zaczynają się od 0) sprawdzam ilość dni. Czyli wiem, że np. dla lutego będzie to 28. Jest też if, który spawdza, czy rok jest przestępny. Rok jest przestępny, jeśli jest podzielny przez 4 i niepodzielny przez 100, lub podzielny przez 400. Jeśli dany rok jest przestępny, to element tablicy o indeksie 1, czyli luty zmienia wartość na 29.

Teraz muszę wyliczyć ilość dni z następnego miesiąca. Pól w kalendarzu mam 6×7, czyli 42. Więc liczba wolnych pól, to (42 – (dniPrzed + dniMiesiąca)).

Kiedy już mam te wszystkie dane, to wystarczy wykonać 3 pętle. Pierwsza dodaje mi dni przed, czyli zaznacza inactive na true, co przyda mi się przy wyświetlaniu. Druga dodaje dni wybranego miesiąca, czyli inactive na false i trzecia dni po, czyli inactive na true. Każdy obiekt dnia, ma też numer dnia oraz datę, po której będą przypisywane zlecenia.

Tak zwróconą tablicę wyświetla przez ngFor i sprawdzam, czy jest inactive. Jeśli tak, to dodaję klasę inactive, która zmienia mi to pole na szare.

A w ten sposób używam tego w komponencie:

calendar: any = [];
today: any;
month: number;
year: number;
nameOfMonths: Array;
monthName: string;

constructor(private calendarService: CalendarService) { }

ngOnInit() {
    this.nameOfMonths = [
        "Styczeń",
        "Luty",
        "Marzec",
        "Kwiecień",
        "Maj",
        "Czerwiec",
        "Lipiec",
        "Sierpień",
        "Wrzesień",
        "Październik",
        "Listopad",
        "Grudzień",
    ];
    this.today = new Date();
    this.month = this.today.getMonth();
    this.year = this.today.getFullYear();
    let day = this.today.getDate();
    this.today = new Date(this.year, this.month, day).toString();
    this.reload();
}

nextMonth(){
    this.month = this.month + 1;
    if(this.month == 12)
    {
        this.month = 0;
        this.year = this.year + 1;
    }
    this.reload();
}

previousMonth(){
    this.month = this.month - 1;
    if(this.month == -1)
    {
        this.month = 11;
        this.year = this.year - 1;
    }
    this.reload();
}

reload() {
    this.calendar = this.calendarService.getArray(this.year, this.month);
    this.monthName = this.nameOfMonths[this.month];
}

isToday(date) {
    return this.today == date;
}

Tutaj również szybki opis. Tworzę najpierw potrzebne parametry i w ngOnInit przypisuje im wartości. Następnie tworzę tablicę z nazwami miesięcy, aby wyświetlić ją dla użytkownika. Biorę dzisiejszą datę i zapisuję jej dzień i miesiąc, a następnie zapisuje ją jeszcze raz, tak aby pozbyc się czasu i zamienić ją na string, ponieważ potrzebuję tej daty do dodania odpowiedniej klasy dla dzisiejszego dnia.

Metoda reload przeładowuje tablicę, oraz zmienia nazwę miesiąca. Jest uruchamiana na starcie i przy zmianie miesiąca. Metody next i previous przełączają miesiące.

I to tyle na dziś. W drugiej części opiszę, jak dodaję do kalendarza zlecenia. Jednak najpierw będę musiał zająć się ich stworzeniem, więc niewiem, kiedy się ona pojawi.

Zastanawiam się również, czy uda mi się dodać funkcjonalność samochodów zastępczych. Mogę się z tym nie wyrobić, więc nie będę się na niej skupiał, ale jeśli starczy czasu, to ją dodam.

Pozdrawiam!
MTK

  • Sebastian

    Cześć,

    próbowałeś może napoju Yerba Mate? Może pomoże Ci z pogorszonym samopoczuciem.

    Pozdrawiam.

    • MTK

      Tak, ale nie smakuje mi :(. To nie dla mnie.

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑