Phoenix LiveView: Load More Button und Sortierung

Einleitung

Vor einiger Zeit bin ich auf das Webframework Phoenix gestoßen, das in der Programmiersprache Elixir geschrieben ist. Da ich einen Hintergrund in Ruby on Rails habe, wurde mein Interesse geweckt, mich damit zu beschäftigen.

Ein Webframework ist eine Softwarebibliothek, die die Entwicklung von Webanwendungen erleichtert. Ein Webframework bietet typischerweise Funktionen wie Routing, Templating, Datenbankzugriff, Sicherheit und Validierung. Ein Webframework ermöglicht es dem Entwickler, sich auf die Geschäftslogik der Anwendung zu konzentrieren, anstatt sich um die technischen Details der Webprogrammierung zu kümmern.

Elixir ist eine funktionale Programmiersprache, die auf der Erlang Virtual Machine (BEAM) läuft. Elixir wurde 2011 von José Valim entwickelt und bietet eine moderne und ausdrucksstarke Syntax, die Metaprogrammierung, Nebenläufigkeit und Fehlertoleranz unterstützt. Elixir wird häufig für Webentwicklung, Datenverarbeitung und eingebettete Systeme verwendet. Elixir ist mit bestehendem Erlang-Code kompatibel und kann von dessen reichhaltigem Ökosystem profitieren.

Während meines Studiums hatte ich Kontakt mit der ebenfalls funktionalen Programmiersprache Haskell und schon damals fand ich das Konzept spannend. Mit Elixir und Phoenix öffnet sich für mich die Möglichkeit, eine funktionale Sprache produktiv in Projekten zu verwenden.

Phoenix LiveView ist eine Bibliothek für das Phoenix-Framework, die es ermöglicht, interaktive Webanwendungen ohne JavaScript zu erstellen. Mit LiveView kann man den Zustand und das Rendering einer Seite auf dem Server verwalten und nur die geänderten Teile an den Browser senden. LiveView nutzt WebSockets, um eine bidirektionale Kommunikation zwischen Server und Client aufrechtzuerhalten.

LiveView verspricht eine hohe Leistung für viele gleichzeitige Verbindungen.

Das Projekt

Ich zeige Dir in diesem Projekt, wie Du mit LiveView einen „Load More“ Button und Sortierung nach Spalten realisieren kannst. Ich baue dazu auf dem Artikel Efficient bidirectional infinite scroll in Phoenix LiveView von Christian Alexander auf.

Hier findest Du das Projekt auf GitHub.

Wir werden eine Liste von Ländern und deren ISO 3166-1 alpha-2 Code anzeigen. Nachdem wir das Projekt erstellt haben, erzeugen wir das Model und die Views für die Länder:

mix phx.gen.live Basics Country countries name:string code:string

Um die Länder in die Datenbank zu laden, kopierst Du Dir diese Datei nach ./priv/repo/countries.csv in Deinem Projekt. Dann führst Du folgende Schritte aus, um die Tabelle für die Länder in Deiner Datenbank zu erstellen und die Länder in die Datenbank zu laden:

Die seeds-Datei dient dazu, die Länder aus der CSV-Datei in die Datenbank zu übertragen.

Jetzt können wir die Tabelle erzeugen und den Code aus seeds.exs ausführen:

mix ecto.migrate
mix run priv/repo/seeds.exs

Damit wir die LiveView über den Browser erreichen können, müssen wir diese noch im Router eintragen:

Jetzt kannst Du den Server starten und Dir über http://localhost:4000/countries die Liste der Länder ansehen.

Load more Button

Momentan werden noch alle Länder auf einmal geladen und angezeigt. Wir möchten die Anzeige jetzt auf die ersten 80 Länder begrenzen und einen Load More Button anzeigen, über den wir weitere Länder nachladen können.

Dazu fügen wir zuerst den Button in der LiveView ein:

Wir benötigen ein paar zusätzliche Funktionen in der Verbindung zur Datenbank, um nur die benötigten Einträge aus der Datenbank abzurufen:

Jetzt können wir über page und per_page angeben, wie viele Einträge geladen werden sollen und welche „Seite“ wir gerade benötigen.

Ebenfalls fügen wir die Funktionalität zur Paginierung im zugehörigen Live-Controller ein:

Wir verwenden einen Stream, um die Länder über den Websocket zu übertragen. Dadurch muss der Server nicht die komplette Liste der Länder im Speicher ehalten. Stattdessen werden die Inhalte werden zum Client übertragen. Bei der Initialisierung des Streams in der Funktion mount werden nur die ersten 80 Länder geladen und angezeigt. Wird der „Load more“ Button gedrückt, werden jeweils die nächsten 80 Länder nachgeladen.

Sortierung

Um die Liste sortierbar zu machen, fügen wir etwas Funktionalität zu unserer Datenbankabfrage hinzu:

Das fügt als weitere Parameter order für die Reihenfolge und order_by für den Namen der zu sortierenden Spalte hinzu.

Ich habe in den Core Components die Definition der Tabellenüberschriften angepasst. Ein Klick auf die Überschrift löst ein order-by Event aus, mit der Spaltenüberschrift als Argument. Das wird ermöglichen, dass die Sortierreihenfolge über einen Klick auf die Spaltenüberschrift ausgewählt werden kann.

Im LiveController benötigen wir auch etwas zusätzliche Funktionalität:

In der mount-Funktion legen wir die initiale Sortierreihenfolge fest und binden die entsprechenden Parameter an das Socket.

Im Eventhandle für das load-more Event berücksichigen wir ebenfalls die Sortierreihenfolge, damit beim Nachladen von Ländern die Sortierung berücksichtigt wird. Würden wir das nicht machen, würden zusätzliche Länder unabhängig der Sortierung nachgeladen, was wir nicht wollen.

Schließlich brauchen wir noch den Eventhandler für das order-by Event, das ausgeführt wird, wenn eine Spaltenüberschrift angeklickt wird. Hier werden die Elemente entsprechend der angeklickten Überschrift sortiert aus der Datenbank geladen. Entspricht die Sortierung bereits der angeklickten Überschrift, wird die Sortierreihenfolge umgekehrt. Dann wird der Stream auf die neu geladenen Elemente zurückgesetzt.

Derzeit gibt es noch einen Bug in LiveView, der dafür sorgt, dass die Reihenfolge von Elementen, die bereits angezeigt wurden, nicht korrekt angepasst wird. Der Bug wurde aber mittlerweile gefixt, so dass ich erwarte, dass mit der nächsten Version von LiveView alles funktioniert.

Verallgemeinerung der Änderungen

Wir können jetzt Länder wunderbar sortieren. Aber es wäre ziemlich umständlich, müssten wir das alles für jedes Modell wiederholen. Wir wollen also in diesem Schritt die Änderungen generalisieren, so dass wir die Funktionalität für beliebige Modelle erhalten.

Dazu erstellen wir das folgende Modul, das die Funktionalität auslagert:

Dieses können wir jetzt über use in einen beliebigen LiveViewController einbinden:

Damit haben wir eine sehr flexible Lösung zur Sortierung und Paginierung von LiveView-Tabellen erzeugt.


Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert