#Angular2, #Symfony3 – Filtrowanie danych

Kiedy zaczynałem tworzyć i wymyślać zasady działania aplikacji, założyłem sobie, że filtrowanie danych zrobię w Angularze. Kiedy już doszedłem do momentu, w którym trzeba było to zaimplementować, zacząłem się nad tym zastanawiać. Miałem już gotowe pobieranie dokumentów, wszystko ładnie się wyświetlało i przyszła pora na wyszukiwanie. Więc próbuję znaleźć w internecie jakiegoś sposobu na przeszukiwanie obiektu JSON w Angularze. Niby coś znalazłem, ale działał on dla tablicy jednoelementowej i w zasadzie nie bardzo go ogarniałem, więc nie wiedziałem jak to przerobić. Nie chcąc tracić czasu, zmieniłem początkowe założenia.’

Postanowiłem, że filtrowanie dokumentów wykonam po stronie serwera. Myślę, że jest to lepsze rozwiązanie. Pierwszą rzeczą, jaka przemawiała za takim rozwiązaniem, jest to, że przy dużych rozmiarach bazy, komputer kliencki, będzie miał problemy z wydajnością, podczas takiego przeszukiwania. Drugą jest łatwiejsza implementacja. PHP uczę się już od dawna i troch lepiej się w nim poruszam, natomiast może nie sam JS, ale Angular2, jest dla mnie czymś nowym i dobrze by było, jeśli nie będę sobie na początek za bardzo utrudniał. Poza tym większość JSON’owych API robi to właśnie w ten sposób, więc chyba programiści wiedzą, co robią.

Przerobiłem więc odpowiednio kontroler dokumentu w API:

public function cgetAction(Request $request)
{
    $type = $request->query->get('type', '');
    $from = $request->query->get('from', '');
    $to = $request->query->get('to', '');
    $search = $request->query->get('search', '');

    $documents = $this->getDocumentRepository()
        ->createFindAllQuery($this->getUserId(), $type, $from, $to, $search)
        ->getResult();

    if($documents == null) {
        return new View(null, Response::HTTP_NOT_FOUND);
    }

    return $documents;
}

w zasadzie to tylko jedną jego metodę. Dodałem do niej zmienne, zawierające dane przekazane metodą GET. Dzięki temu, do adresu mogę dodać odpowiednie parametry i wykorzystać je przy wyświetlaniu. Adres wygląda tak:

http://localhost:8000/api/documents?type={typ}&from={data_od}&to={data_do}&search={ciag_znakow_do_wyszukiwania}

Musiałem jeszcze rzecz jasna przerobić zapytanie w repozytorium:

public function createFindAllQuery(int $userId, string $type, string $from, string $to, string $search)
{
    if($type!='')
    {
        $type = "AND d.type = '".$type."'";
    }
    if($from!='')
    {
        $from = "AND d.date >= '".$from."'";
    }
    if($to!='')
    {
        $to = "AND d.date _em->createQuery(
        "
        SELECT d
        FROM ApiBundle:Document d
        JOIN d.consumer c
        WHERE d.userId = :userId
        ".$filters
    );
    $query->setParameter('userId', $userId);
    return $query;
}

Na początku domyślną wartość dla parametrów filtra chciałem ustawić na false, sprawdzać je w tych warunkach, a potem stworzyć zmienną $filter i dodawać do niej kolejne fragmenty przy pomocy „+=”. Niestety Doctrine nie chciał tego przemielić, wyrzucał jakiś błąd, że ma ‚0’ na końcu zapytania. Wykonałem to więc tak, jak widać powyżej i wszystko działa.

Tworząc część zapytania odpowiadającą za wyszukiwanie, zapomniałem dodać nawiasu do warunków OR, przez co przy testach, po zaznaczeniu Rachunków i wpisaniu czegokolwiek w wyszukiwaniu, dostawałem wyniki, mimo że w bazie nie było żadnych rachunków. Tutaj sprawdziłyby się testy, bo mogłem tego nie zauważyć, ale już wcześniej pisałem, dlaczego tutaj z nich nie korzystam.

Teraz pora na frontend. W _services, mam usługę document.service.ts, w którym mam następującą metodę:

getDocuments(type: string = '', from: string = '', to: string = '', search: string = ''): Observable {
    let headers = new Headers({ 'Authorization': 'Bearer ' + this.authenticationService.token });
    let options = new RequestOptions({ headers: headers });

    return this.http.get('http://localhost:8000/api/documents?type='+type+'&from='+from+'&to='+to+'&search='+search, options)
        .map((response: Response) => response.json());
}

Metoda ta po prostu pobiera obiekt JSON z API, przypisując do adresu odpowiednie parametry.

Implementuję tę usługę, do komponentu dokumentów. Następnie napisałem metodę, która pobiera dane z API i przypisuje je do obiektu Documents:

searchDocuments() {
    this.sub = this.documentService.getDocuments(this.type, this.from, this.to, this.search)
        .subscribe(documents => {
            this.documents = documents;
            this.documentsReturn = true;
        },
        (err)=>this.documentsReturn = false
    );
}

Mam tutaj jeszcze zmienną boolean documentsReturn, która jest sprawdzana w szablonie i w zależności od jej wartości, wyświetla wynik z API, albo napis „Nie znaleziono”.

Metoda ta jest wywoływana przy każdej zmianie parametrów. Przy wpisaniu tekstu do pola search, jest wywoływana, poprzez zdarzenie keyup, po podaniu zakresu dat, poprzez przycisk „Zatwierdź” i po wybraniu typu dokumentu, przez zdarzenie click, no i oczywiście w metodzie ngOnInit().

Tyle udało mi się wykonać przez ostatnie kilka dni. Do następnego wpisu, chcę dodać opcje dodawania i usuwania dokumentów, a potem opcje edycji. Z edycją będzie najwięcej zabawy,  bo w komponent edycji podzieliłem na kilka komponentów, aby było łatwiej zapanować nad tym wszystkim. Muszę też zająć się breadcrumbs’ami, już mam na nie pomysł, mam nadzieję, że zadziała.

Oczywiście wszystkie zmiany można zobaczyć na GitHub.

Pozdrawiam!
MTK

  • Jakub

    Pamiętam jak, my, w latach 90′. Też takie stronki robiliśmy. I w sumie to lepiej wychodziło wtedy. Taka ta młodzież teraz.

    • MTK

      Co masz na myśli, mówiąc lepiej?

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

Up ↑