Web UIs mit Kotlin

Was ich am aufregendsten an Kotlin finde, ist dessen Konzeption, ein einheitliches Toolkit (Sprache + Bibliotheken + Tooling) anzubieten, sich aber auch auf die native Umgebung zu verlassen, wo immer eine Kotlin-Anwendung läuft. Die Verwendung von Kotlin auf der JVM bedeutet eine vollständige Interoperabilität mit Java, im Browser können wir auf JavaScript-Bibliotheken zugreifen, und auch wenn es um die UI-Entwicklung geht, gilt Kotlin dasselbe Prinzip.

DOM Manipulation

Das Document Object Model (DOM) ist eine Programmierschnittstelle (API) für HTML- und XML-Dokumente. Es definiert die logische Struktur von Dokumenten und die Art und Weise, wie auf ein Dokument zugegriffen und es manipuliert wird. In der DOM-Spezifikation wird der Begriff “document” im weitesten Sinne verwendet – traditionell wird XML als ein Mittel zur Darstellung vieler verschiedener Arten von Informationen verwendet, die in verschiedenen Systemen gespeichert sein können. Vieles davon wird traditionell eher als Daten denn als Dokumente betrachtet. Dennoch stellt XML diese Daten als Dokumente dar, und das DOM kann zur Manipulation dieser Daten verwendet werden.

Mit dem Document Object Model können Programmierer Dokumente erstellen, in ihrer Struktur navigieren und Elemente und Inhalte hinzufügen, ändern oder löschen. Alles, was in einem HTML- oder XML-Dokument gefunden wird, kann über das Document Object Model abgefragt, geändert, gelöscht oder hinzugefügt werden, mit einigen wenigen Ausnahmen.

DOM Manipulation ist auch  in Kotlin/JS ist direkt über Adapter für Browser APIs möglich. Die Kotlin/JS-Standardbibliothek ermöglicht uns den Zugriff auf browserspezifische Funktionalität über das Paket kotlinx.browser, das typische Objekte wie „document“ und „window“ enthält. Die Standardbibliothek stellt, wo immer möglich, typsichere Wrapper für die durch diese Objekte offengelegte Funktionalität zur Verfügung. Als Ausweichmöglichkeit wird der „dynamic“ Typ verwendet, um die Interaktion mit Funktionen zu ermöglichen, die sich nicht gut in das Kotlin-Typensystem abbilden lassen. Für die Interaktion mit dem DOM können wir die Variable document benutzen. Man kann :

  • Elemente erzeugen
  • Elemente anhängen
  • Elemente mit ID finden

Es gibt aber auch einige Helfer als kotlinx Pakete zum Nachladen (Builder API für HTML oder JSON-Serialisierung).

Ich werde auf der Code-Basis fortfahren, die wir in früheren Blog-Beiträgen analysiert haben. Wir begannen mit der Programmierung einer ToDo-Listen-Anwendung, in der wir die gesamte Logik programmiert haben, ohne ein Front-End/UI zu haben. Wenn ihr die vorherigen Blog-Beiträge nicht gelesen habt, findet ihr sie hier (Kotlin für Java Web-Entwickler, Kotlin Multiplattform-Projekte für die Web-Entwicklung, Spring Boot mit Kotlin).

Beispiel ToDo-Liste

In der main() – Methode der Anwendung, deren Backend wir im vorigen Blog-Beitrag “Spring Boot mit Kotlin” erstellt haben, rufen wir update() und build() Methoden auf, mit denen wir die UI erstellen. Die Logik ist in der Klasse SampleJs.kt zu finden:

Beginnen wir mit der build() -Methode:

Mit Hilfe der DOM-Manipulation unter Verwendung der Variablen document erzeugen wir:

  • ein HTMLDivElement für eine bessere Struktur
  • ein HTMLButtonElement, das in den nächsten Zeilen die Beschriftung „Add“ mit add.textContent = "Add" bekommt
  • ein HTMLSelectElement, mit dem man ein Element aus der Shopping Liste selektieren kann
  • ein HTMLInputElement für die Beschreibung
  • ein HTMLOptionElement für jede Kategorie: wir iterieren über die Liste der Kategorien und fügen für jede Kategorie ein HTMLOptionElement in die Optionsliste ein. Übercategory.appendChild(option)“ hängen wir das Element mit dem Typ „option“ an das Select-Element an, damit man später eine Kategorie aus der Drop-Down-Liste auswählen kann.

Der Knopf mit der Beschriftung „Add“ erhält einen Event-Listener, der die ausgewählte Kategorie mit der entsprechenden Beschreibung hinzufügt.

fun build(): HTMLElement {
    val containerElement = document.createElement("div") as HTMLDivElement
    val add = document.createElement("button") as HTMLButtonElement
    val category = document.createElement("select") as HTMLSelectElement
    val description = document.createElement("input") as HTMLInputElement
    val categories = listOf<String>("Shopping", "Work", "Study", "Sport", "Movies");
    for(c in categories){
       val option = document.createElement("option") as HTMLOptionElement
        option.textContent = c
        option.value = c
        category.appendChild(option)
    }
    add.textContent = "Add"

    add.addEventListener("click", {
        val json = Json(JsonConfiguration.Stable)
        val todo = json.stringify(TodoEntry.serializer(), TodoEntry(category.value, description.value))

        var xhttp: dynamic = XMLHttpRequest();
        xhttp.open("POST", "/todo", true);
        xhttp.overrideMimeType("application/json")
        xhttp.onreadystatechange = fun() {
           update()
        }
        xhttp.send(todo);
    })

    document.body?.appendChild(containerElement)
    containerElement.appendChild(add)
    containerElement.appendChild(category)
    containerElement.appendChild(description)
    return containerElement
}

Man sieht, dass durch das Hinzufügen des ausgewählten Elements mit seiner Beschreibung eine update()– Methode aufgerufen wird, die ich im Folgenden erläutern werde:

fun update() {
    var xhttp: dynamic= XMLHttpRequest();
    xhttp.open("GET", "/todo", true);
    xhttp.onreadystatechange = fun() {
        val json = Json(JsonConfiguration.Stable)
        val todoEntries = json.parse(TodoEntry.serializer().list, xhttp.responseText)

        val element = document.getElementById("js-response")
        element?.innerHTML = "";

        for (e in todoEntries) {
            val div = document.createElement("div");
            div.textContent = e.description
            element?.appendChild(div);
        }

    }
    xhttp.send();
}

Es wird ein Ajax-Request durchgeführt, bei dem für jeden Eintrag in die ToDo-Liste der jeweilige Eintrag in einem div-Element angehängt wird. Das Ergebnis wird eine einfache GUI sein, die wie folgt aussieht:

Wie man sieht, ist Kotlin eine statisch typisierte Programmiersprache, die man sowohl im Front-End als auch im Back-End verwenden kann.

Ich hoffe, dass es Euch Spaß gemacht hat und ihr etwas lernen konntet, indem wir eine Spring Boot “ToDo – Liste” mit Kommunikation zwischen Browser und Backend mit Kotlin und mit Hilfe von DOM-Manipulation programmiert haben. Die folgenden Blog-Posts befassen sich mit weiteren Kotlin UI-Frameworks wie beispielsweise Kotlin mit React, Kotlin KVision, Kotlin Development Server, Kotlin mit Ktor und Testen mit Kotlin.

Views All Time
337
Views Today
1
Short URL for this post: https://blog.oio.de/ITqIY
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *