Lars Lillo Ulvestad
Lars Lillo Ulvestad
Developer and digital storyteller. Works as a front-end developer at Kantega.

Part 3: Structure Elm into a multi-widget app for IHP

Making the widget-equivalent of Richard Feldmans's RealWorld SPA.
Published: Tuesday, 22 December 2020
9 minute read
Article cover photo

This is part 3 of the series IHP with Elm

We have set up a single widget and most of our logic lives in a single Main.elm file.

Since we are planning on creating an application supporting multiple isolated widgets, we might as well split this application into smaller more maintainable sub-modules with their own seperate model, view and update functions.

A simplified version of Richard Feldmans's RealWord Example app is a great architecture for this use-case.

Continue from part two

If you haven't done part 2 of this series, do so first.

If you don't want to, you could clone the project source and checkout to this tag to follow along:

Separating the BookWidget module

Inside the elm folder, let's create a sub-folder named Widget, and a module inside named Book.elm

Let us extract all the relevant logic into elm/Widget/Book.elm.

What's nice about this is that we now can maintain this entire widget inside this isolated module.

Now we need to rewrite Main.elm into a central hub that can support many different Elm widgets.

Add a new widget

Let's start the process of adding a new widget. As you might have guessed, it starts with Haskell.

The first thing we need to do is to add it to the Widget type in /Application/Helper/View.hs:

We can also add a new widget entrypoint named bookSearchWidget.

This one won't use any initial data from IHP. Therefore, we won't need to pass in any data other than the Widget type's representation on the BookSearchWiget.

Make sure the module exposes the bookSearchWidget at the module definition.

Add widget to view

To demonstrate that we can insert many Elm views into one page, let's also add the bookSearchWidget into /Web/View/Books/Show.hs.

Break the app

We should now generate the types for the new Elm widgets defined in Haskell.

Imagine someone saying this for a JavaScript tutorial: Let's break the app to make it better.

Close the server (ctrl+c) and start it again with the start script that will generate the new Elm types before starting the server.

Main.elm should now be complaining. Good! Let's first make the separate BookSearch module.

Make the initial BookSearch widget

First create a new file for the new Widget.

Then create a simple module to start with.

Add the new widget to Main.elm

To finally get rid of the Elm errors, let's fix Main.elm step-by-step.

First, let's import the new widget module into Main.

The Model and Msg types in Main needs to be have a variant for BookSearch.

The Main update function also needs to deal with the sub-module. This looks complicated, but it's worth it 😄 Next time you add something, just follow the pattern.

Keep on just adding to the pattern with subscriptions and view.

The last thing the compiler should complain about is widgetFlagToModel and widgetFlagToCmd. These ones decides the initial state and commands (actions) upon startup of the widget.

Going into any book, you should now see a very dumb widget below that is just a title:

A dumb Elm widget

Next up

We will finalize this simple book app by making the new BookSearch widget more advanced with basic search functionality.

By doing this, we will walk through the final part of doing IHP interop Elm: JSON HTTP requests with IHP through Elm. And we'll finally get to update some Elm state 😊

Got a comment? Drop me a tweet