Die Erstellung unserer ersten Elm-Anwendung mag wie eine schwierige Aufgabe erscheinen. Die neue Syntax und das neue Paradigma können einschüchternd sein, wenn Sie noch keine anderen funktionalen Programmiersprachen verwendet haben. Aber sobald Sie Ihre erste Anwendung erstellt haben, werden Sie verstehen, warum Elm in letzter Zeit so viel Aufmerksamkeit erhält.
Artikelserie
- Warum Elm? (Und wie man damit anfängt)
- Einführung in die Elm-Architektur und wie Sie unsere erste Anwendung erstellen (Sie sind hier!)
- Die Struktur einer Elm-Anwendung
In diesem Artikel werden wir eine einfache Anwendung erstellen, die uns in die Grundlagen der Sprache einführt: die Elm-Architektur und wie wir mit der Erstellung von Dingen beginnen. Es wird ziemlich einfach sein, aber es wird uns in eine der häufigsten Aufgaben in jeder Anwendung einführen: auf Benutzeraktionen reagieren und etwas damit innerhalb der Anwendung tun.

Sie wird aus einem Formular zum Hinzufügen von Textfragmenten und zum Filtern früherer Einträge bestehen. Eine Liste aller Einträge ist ebenfalls enthalten. Es gibt ein GitHub-Repo für den gesamten Code, den wir in diesem Artikel behandeln.
Obwohl dies für vollständige Elm-Anfänger ohne Vorkenntnisse der Sprache gedacht ist, gehen wir davon aus, dass Sie die grundlegenden Dinge bereits gelesen haben, wie z. B. die Syntax zum Schreiben von Funktionen und deren Anwendung. Um mehr darüber zu erfahren, können Sie die spezielle Syntax-Seite auf der Elm-Dokumentationsseite lesen.
Einführung in die Elm-Architektur
Jede Elm-Anwendung folgt tendenziell einem bestimmten Muster, bis zu dem Punkt, dass sie nun als der Weg zum Schreiben von Elm gilt. Wenn Sie mit der MVC-Architektur vertraut sind, werden Sie einige Gemeinsamkeiten in den Konzepten finden, aber wenn die Konzepte für Sie völlig neu sind, machen Sie sich keine Sorgen, sobald wir diese Anwendung erstellen, wird alles klarer werden.
In den meisten Anwendungen finden wir diese drei wesentlichen Teile
- Modell: Die
model-Funktion speichert den gesamten Zustand unserer Anwendung; das sind alle dynamischen Daten, die während der Ausführung unserer Anwendung bewegt werden. - Aktualisierung: Die
update-Funktion enthält andere Funktionen, die Ihre Anwendung dynamisch machen. Wir verwenden diese, um unseren Zustand mit der erforderlichen Logik zu verarbeiten, um das Ziel der Anwendung zu erreichen. - Ansicht: Die
view-Funktion kümmert sich um den visuellen Teil unserer Anwendung. Mithilfe kleinerer Funktionen, die HTML ähneln, können wir die Struktur der Anwendung erstellen, indem wir Daten aus dem Modell einbetten. Wir können auch Aufrufe zu Ereignissen einfügen, die bestimmte Funktionalitäten auslösen.
Hallo, Welt!
Der Aufbau einer dynamischen Anwendung mit Elm kann einfacher sein als der Aufbau einer mit reinem HTML/JS. Um zu beginnen, benötigen wir nur eine Datei. Wir müssen nicht darüber nachdenken, welche anderen Bibliotheken wir benötigen werden.
Erstellen Sie eine Datei mit der Endung .elm in einem Verzeichnis für dieses Projekt. Wir werden sie als main.elm bezeichnen, obwohl Sie sie beliebig nennen können. Sobald Sie die Datei in Ihrem Lieblingseditor geöffnet haben, fügen Sie den folgenden Inhalt hinzu, der eine einfache "Hallo, Welt!"-Anwendung ist, die uns helfen wird, bevor wir die eigentliche erstellen.
import Html exposing (text)
main =
text "Hello, World!"
Zuerst importieren wir das Html-Modul, das es uns ermöglicht, die sichtbare Anwendungsstruktur mit etwas Ähnlichem wie HTML zu schreiben, und wir machen die Textfunktion öffentlich, die es ermöglicht, einfachen Text auf der Seite auszugeben.
Wie in anderen Programmiersprachen ist die main-Funktion der Einstiegspunkt der Anwendung; sie ist die erste, die nach dem Start des Programms ausgeführt wird. Was wir hier tun, ist, den String "Hallo, Welt!" als Parameter an die Textfunktion zu übergeben und ihn dann der main-Funktion zuzuweisen. Sobald die Anwendung ausgeführt wird, zeigt sie einen einfachen "Hallo, Welt!"-Text im Browser an.
Um das Ergebnis im Browser zu sehen, müssen wir den Code zuerst kompilieren. Wie im Artikel Warum Elm? (Und wie man damit anfängt) erwähnt, enthält die Elm Platform das Reactor-Dienstprogramm, das es uns ermöglicht, unser Elm im Browser zu sehen und den Code automatisch zu kompilieren.
Führen Sie in einem Terminal-/Befehlszeilenfenster den folgenden Befehl im Verzeichnis aus, das die Elm-Datei enthält, die Sie gerade erstellt haben.
elm-reactor
Dies startet einen Entwicklungsserver, und wir können darauf zugreifen, indem wir https://:8000 im Browser eingeben.

Sobald Sie im Browser sind, sehen Sie ein Dateinavigationsfenster. Klicken Sie auf die Datei main.elm und warten Sie ein paar Sekunden, während sie kompiliert wird. Im Prozess wird auch eine Datei elm-package.json erstellt, die das Äquivalent der Datei package.json in Node.js-Projekten ist; sie enthält wesentliche Informationen über Ihre Anwendung, einschließlich der Abhängigkeiten, die in diesem Fall direkt aus unserer Anwendungsdatei bezogen werden. Sie wird auch diese Abhängigkeiten herunterladen und sie in einem Verzeichnis elm-stuff ablegen. Sobald der Vorgang abgeschlossen ist, sehen Sie den Text "Hallo, Welt!" auf der Seite.
Nachdem wir nun bestätigt haben, dass alles funktioniert, ist es an der Zeit, mit dem Aufbau unserer Anwendung zu beginnen.
Hinzufügen von Modulen und Definieren des Einstiegspunkts
Um bestimmte Funktionen zu verwenden, müssen wir zuerst die Module importieren, die sie enthalten. Ersetzen Sie den Inhalt Ihrer Datei durch Folgendes.
module Main exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
Die erste Zeile definiert unsere Anwendung als ein Modul namens Main, das alles darauf öffentlich machen wird. Obwohl wir das Modul nicht extern verwenden werden, ist es wichtig, davon zu wissen. Sie können mehr über Module auf der Seite Module auf der Seite Eine Einführung in Elm lesen.
Die folgenden drei Zeilen importieren einige Module, die wir in unserer gesamten Anwendung verwenden werden. Das erste ist das, das wir im Hallo-Welt-Beispiel verwendet haben. Html.Attributes ermöglicht es uns, HTML-Attribute in unserem Elm-Code zu verwenden, und Html.Events macht gängige Ereignisse wie Maus- oder Formularaktionen verfügbar.
In diesem Fall machen wir alles innerhalb dieser Komponenten öffentlich, sodass Sie, wenn Sie bei Ihrer Arbeit auf Namenskonflikte stoßen, die genauen Komponenten angeben können, die Sie importieren möchten.
Als nächstes definieren wir den Einstiegspunkt unserer Anwendung. Fügen Sie den folgenden Code zu Ihrer Datei hinzu.
main =
Html.beginnerProgram { model = model, view = view, update = update }
Für einfache Anwendungen ist es üblich, die Funktion Html.beginnerProgram zu verwenden. Sie hilft uns, unser Programm zusammenzusetzen, das, wie bereits erwähnt, aus diesen drei Hauptkomponenten besteht: Modell, Ansicht und Aktualisierung.
Die Wiederholung der Namen mag Ihnen zunächst etwas redundant erscheinen (model = model usw.), aber das liegt daran, dass wir unsere Modellfunktion wie üblich (und empfohlen) in anderen Elm-Programmen model, unsere Ansicht view und unsere Aktualisierung update nennen werden, aber es ist keine strenge Regel; Sie könnten auch etwas wie
main =
Html.beginnerProgram { model = mydata, view = myhtml, update = mylogic }
Aber wenn Sie sich entscheiden, dies in Ihrem Programm zu tun, denken Sie daran, Ihre Funktionsdefinitionen entsprechend zu benennen.
Modell
In unserem Modell werden wir den Zustand unseres gesamten Programms speichern. Zuerst müssen wir über die Dinge nachdenken, die wir speichern und verwenden werden.
Wir können Model als Datensatz von beschreiben
entries: Eine Liste von Strings mit allen Einträgen.results: Eine Liste von Strings mit den gefilterten Einträgen.filter: Ein String, der den Filter enthält.
Und um diesen Typ von Informationen in unserem Elm-Programm anzugeben, werden wir eine sogenannte Typ-Alias für unsere model-Funktion erstellen. Wie der Name schon sagt, ermöglicht sie uns, eine komplexe Datenstruktur auf einfachere Weise darzustellen.
Fügen Sie den folgenden Code unter der main-Funktion ein, die Sie zuvor definiert haben.
type alias Model =
{ entries : List String
, results : List String
, filter : String
}
Wie Sie sehen können, ist der Code recht ausdrucksstark – nicht allzu anders als die Beschreibung, die wir zuvor erstellt haben – nur ein wenig prägnanter. Jetzt können wir Model (Typen werden immer großgeschrieben) als Typ für unsere Funktionen verwenden, ohne die gesamte Struktur manuell schreiben zu müssen. Deshalb verwenden wir Typ-Aliase, um Dinge sauberer, leichter verständlich und weniger repetitiv zu machen.
Obwohl Typen abgeleitet werden können, ist es eine gute Praxis, sie vor dem Schreiben der eigentlichen Funktion zu schreiben. Es hilft uns, nachzudenken und von Anfang an am richtigen Ort zu sein. Außerdem wird uns der Compiler mitteilen, wenn wir etwas falsch machen.
Jetzt können wir unsere Funktion schreiben, die die gerade definierten Informationen enthält. Fügen Sie Folgendes zu Ihrer Datei hinzu.
model : Model
model =
{ entries = []
, results = []
, filter = ""
}
Die erste Zeile teilt Elm mit, dass unsere model-Funktion vom Typ Model ist, was der Typ ist, den wir zuvor definiert haben, und als nächstes definieren wir die eigentliche Funktion. Da unsere Anwendung jedoch ohne Daten beginnt, fügen wir einfach leere Listen ([]) ein. Diese Werte werden sich ändern, sobald der Benutzer mit der Anwendung zu interagieren beginnt.
Streng genommen ändern sich Werte in Elm nicht (sie sind unveränderlich), sondern es werden neue Werte erstellt, obwohl das für uns meist transparent ist.
Das war's! Jetzt ist der Zustand unserer Anwendung an einem zentralen Ort dargestellt, aber wir müssen immer noch die Funktionen implementieren, die mit diesem Zustand arbeiten und die Interna der Anwendung zum Laufen bringen.
Update
Die gesamte Logik in unserem Programm wird von einer einzigen Funktion namens update gehandhabt. Diese Funktion nimmt etwas namens [Nachricht] entgegen – die wir uns als Container für Aktionen vorstellen können, auf die wir reagieren können – und auch unser aktuelles Modell, das ein neues Modell mit unseren Änderungen zurückgibt, abhängig von der angewendeten Aktion.
Unsere Anwendung wird zwei Aktionen haben, eine zum Eingeben von Elementen in die String-Liste aus der Formulareingabe und eine weitere zum Filtern dieser Einträge. Um dies in Elm zu definieren, können wir Folgendes zu unserer Datei hinzufügen.
type Msg
= Filter String
| Add
Hier definieren wir einen neuen Union-Typ namens Msg, um unsere Nachrichten darzustellen. Jede Nachricht kann entweder eine Filter-Aktion mit einem angehängten String sein, der den Text des Filters enthält, oder eine Add-Aktion, die wir verwenden werden, um das Hinzufügen des Filters (des Strings in der Formulareingabe) zur Liste der Einträge auszulösen.
Jetzt ist der Msg-Typ bereit, innerhalb unserer update-Funktion verwendet zu werden. Wir können Folgendes zu unserer Datei hinzufügen.
update : Msg -> Model -> Model
update msg model =
case msg of
Filter filter ->
{ model
| results = List.filter (String.contains filter) model.entries
, filter = filter
}
Add ->
{ model
| entries = model.filter :: model.entries
, results = model.filter :: model.results
}
Obwohl es etwas komplex aussehen mag, besteht es aus sehr einfachen Teilen, um die Funktionalität unserer Anwendung zu erreichen.
Die erste Zeile ist die Typdefinition unserer update-Funktion. Sie besagt, dass sie einen Msg und ein Model entgegennimmt und ein Model zurückgibt, da wir unser Modell bei jeder Nachricht abhängig von ihrem Inhalt aktualisieren werden.
Als nächstes definieren wir die eigentliche Funktion, die msg und model als Parameter hat, die wir innerhalb der Funktion verwenden werden. Zuerst müssen wir den Aktionstyp überprüfen, den wir behandeln müssen, indem wir eine case-Funktion verwenden, die Filter und Add ist, wie wir sie zuvor definiert haben.
Die Filter-Aktion nimmt einen String entgegen, den wir filter nennen, und sie aktualisiert unser model, indem sie das Feld results mit einer neuen Liste aktualisiert, die sich aus dem Filtern (List.filter) unserer Einträge ergibt, die den Filter-String enthalten (String.contains). Wir aktualisieren auch den Wert von model.filter mit dem Inhalt des Filters, damit wir ihn bei Bedarf abrufen können. Die Syntax zum Aktualisieren von Datensätzen finden Sie in der Syntax-Dokumentation.
Der nächste Fall ist Add, der den filter-String aus dem model zu den Feldern entries und results hinzufügt. Dies geschieht jedes Mal, wenn der Benutzer auf eine "Hinzufügen"-Schaltfläche klickt, die wir im nächsten Abschnitt definieren werden. Das Hinzufügen des Strings zur Liste der Einträge ist selbsterklärend, aber wir fügen ihn auch zur Liste der Ergebnisse hinzu, da wir ihn auf diese Weise sofort sehen können, nachdem die Add-Nachricht gesendet wurde. Andernfalls müssten wir einen Teil des Strings löschen und ihn erneut schreiben, um die Ergänzung zu sehen.
Und das wäre alles bezüglich der Logik unserer Anwendung. Das Einzige, was wir jetzt noch tun müssen, ist zu definieren, wie sie im Browser angezeigt wird.
Ansicht
Bisher haben wir die internen Teile unserer Anwendung definiert; alles, was hinter den Kulissen passiert. Aber wir müssen immer noch definieren, wie wir alle Informationen dem Benutzer anzeigen und wie er damit interagieren kann.
Die Benutzeroberfläche der Anwendung wird aus drei Hauptelementen bestehen: dem Formulareingabefeld, in das der Benutzer einen Filterstring eingeben kann, um ihn zu suchen oder zu den Einträgen hinzuzufügen, einer Hinzufügen-Schaltfläche, um den Text zu den Einträgen hinzuzufügen, und der Liste der Einträge.
In HTML hätten wir so etwas
<div>
<input placeholder="Filter…" oninput="Filter()">
<button onclick="Add()">Add New</button>
<ul>
<li>Item list</li>
<li>…</li>
</ul>
</div>
Aber wir können HTML nicht direkt in Elm schreiben. Wir müssen spezialisierte Funktionen verwenden, die HTML-Tags nachahmen. Um dies zu erreichen, fügen Sie Folgendes zu Ihrer Datei hinzu.
view : Model -> Html Msg
view model =
div []
[ input [ placeholder "Filter…", onInput Filter ] []
, button [ onClick Add ] [ text "Add New" ]
, ul [] (List.map viewEntry model.results)
]
Zuerst definieren wir den Typ unserer Ansichtsfunktion, die ein Model als Eingabe mit allen Daten und Html Msg als Ausgabe hat, was die HTML-Darstellung ist, die im Browser angezeigt wird. Der Körper der Funktion ist fast eine direkte Darstellung unseres HTML-Codes, aber mit einer anderen Syntax in Form von <tag> [<attribute>] [<content>].
Beachten Sie, wie wir bei jedem onInput-Ereignis, das jedes Mal auftritt, wenn der Benutzer etwas in das Eingabefeld eingibt, eine Filter-Nachricht senden. Und wir machen etwas Ähnliches bei der Add-Nachricht mit dem onClick-Ereignis.
Für die Liste der Einträge mappen wir über die Elemente der Liste mode.results mit List.map und übergeben jeden Eintrag an die Funktion viewEntry, die wir wie folgt definieren werden (fügen Sie sie zu Ihrer Datei hinzu).
viewEntry : String -> Html Msg
viewEntry entry =
li [] [ text entry ]
Es ist nur eine einfache Hilfsfunktion für saubereren Code in view. Sie akzeptiert einen String als entry und gibt ihn innerhalb eines li-Elements vom Typ Html Msg zurück.
Und damit ist unsere Anwendung fertig. Sie können einfach Ihr Browserfenster neu laden (stellen Sie sicher, dass Reactor noch ausgeführt wird) und Sie sehen das Endergebnis.

Fazit
Das in diesem Artikel enthaltene Beispiel ist ziemlich einfach, aber hoffentlich hilft es Ihnen durch die anfängliche Lernkurve der Elm-Programmiersprache. Wenn Sie möchten, können Sie versuchen, dieses Beispiel zu einer komplexeren Anwendung zu erweitern. Es wird Ihnen helfen, weiter zu lernen, ohne sich mit dem "Wie fange ich an?"-Problem auseinandersetzen zu müssen, das bei neuen Technologien üblich ist.