(This guest blog was written by Wolfgang Loder, February 2017.)
Whenever web developers are asked about a language or framework they want to try, most likely the language Elm will be mentioned.
If you have not had the chance to look deeply into Elm, have a look at the following points:
- Elm is a functional language with many advantages like immutable variables and higher order functions.
- The Elm platform (language, tools and libraries) is geared towards SPA (Single Page Applications), although it is possible to create multi-page applications with routing.
- Elm code is compiled into JavaScript, and the resulting code is bundled with a JavaScript runtime.
- The Elm architecture is similar to a Model-View-Controller architecture, with the wiring between parts done in the aforementioned JavaScript runtime.
This is not an Elm primer, so I assume you have a little experience with the Elm basics. If not, the following paragraphs will give you an idea what can be achieved with the Elm platform.
As much as Elm libraries try to cover everything needed for web applications development, there are gaps and inadequate solutions. This is why pure Elm applications may be good for demos and simple applications, but are not always feasible for production code. We will often have to enhance Elm code with JavaScript libraries.
What we want to build
For example, take forms. Almost every web application needs a form in one way or another, especially if the application is in the field of e-commerce. Let’s assume we have to develop a form for an online pizza order web app. This form is for the internal use of employees who take orders over the phone. The requirements are:
- Choose a pizza from a drop down list.
- Once a pizza is chosen, additional toppings can be added. This data is dependent on the pizza selection.
- The price updates dynamically depending on the pizza and toppings selection.
- It is possible to choose more than one pizza for each order.
- There are name, address, and phone fields, with validation for the phone field.
- Depending on the address and pizza selection, an approximate delivery time will be displayed.
- We assume payment on delivery.
- Submitting the form updates an order list that is displayed on the right side of the form.
The wireframe design looks like this:
The form is not too complicated and could probably be coded with Elm alone, but we do not want to re-invent the wheel. We will use Synfusion’s Essential Studio® for JavaScript to make our lives easier.
Implementation
Let’s look first at the finished form – you can find the code for this article here..[DW1]
If you want to run the example, download all files and then download Essential Studio® for JavaScript and claim a free community license if you are eligible.
Once you have Essential Studio® on your computer, copy the files as shown in the following image into a folder called static in the root of the project:
All other files are downloaded into the root and the command
will install the needed Elm packages and compile all code files into one JavaScript file (advancedform.js). The application can then be run with elm reactor and opened at localhost:8000.
I have divided the code into different files for easier handling. It could be all in one file, but even for a simple project like this it is difficult to maneuver through the code. The advantage of Elm is that the wiring between parts of the Elm architecture is done in the background, and we only need to know how the parts fit together:
In advancedform.elm we define the function main and provide other functions to be called by the runtime for init, update, view, and subsciptions.
We won’t focus on the actual Elm implementation of this form, but on the way we can integrate Essential Studio®. In the HTML file we have to link to several stylesheet and javascript files which are necessary to get the theming and features of Essential Studio®.
The same HTML file also has a script section to initialize components like listviews or text boxes. One example is the code for the pizza dropdown list at the top of the form:
Essential Studio® uses jQuery, so the expression $(‘#pizzadd’) looks for the DOM element with the id pizzadd – which is an input element in our case – and attaches the code for the dropdown list to it by calling ejDropDownList. Its parameters define, amongst others, a callback for the change event and a targetID that defines the list that should appear in the dropdown. The markup for these elements can be found in the Elm code in advancedformview.elm – here is an excerpt from this file:
The targetID we defined above points to the div-element with the id pizzaddlist. In this case we have hard coded the list.
Elm Ports
The most important integration task is to establish communication between our Elm code and outside JavaScript code.
The change callback function we saw above has these contents:
This article is not the place to explain Elm ports in detail. The gist is that ports are well defined comunication channels either called from JavaScript code to Elm (send) or from Elm to JavaScript code (subscribe):
The first port call is sending updated values to the Elm code. The second port call means that the JavaScript code subscribes to an event raised by the Elm code, and whatever function is defined will be called.
So why do we need this? The Elm code needs to maintain the application state, and this is most easily done with events. Whenever something changes, an event is raised and the runtime will pass the message to the update function in our Elm code. Most of the time this happens automatically, but the Essential Studio® components have their own event handling, and we need to push updated values with a port call. For example, the numerical textbox changes the value of the textbox, but does not raise an input event. The same applies to the drop down list. Remember that all code is run on the client, so raising an additional event does not cause huge time delays.
The second reason for using ports is that sometimes the Elm code needs to tell the JavaScript code to update. When we add an order to the list, the Elm runtime pushes the model changes to the form without having to code anything. In our case, we want to run the Essential Studio® functions like ejListView as well. This is why the Elm code sends an event to say, “Update the lists now.” When you want to integrate components like Essential Studio®, you will have to use this technique to achieve the functionality you need.
Markup
More work needs to be done in the view function. Defining markup and integrating it with data is done in various ways in different frameworks, with templates or custom attributes. Elm uses code to describe markup, including attributes, and compiles this into HTML markup. The view code for our simple form is almost 150 lines. Bigger projects need to be broken into separate functions to define the markup, but it can be difficult to see exactly what is going on, especially when markup needs to be changed, added, or removed.
One pitfall when integrating with Essential Studio® is to know when the document is rendered and scripts can be applied. We have wrapped all script calls to initialize elements with the JQuery $(document).ready function to make sure that elements are all rendered. If this is not done, then the page won’t look as intended, although it may work because the Essential Studio® is smart enough not to raise exceptions by default.
This article has shown that we can integrate Elm code with frameworks like Essential Studio® for JavaScript to create appealing applications quickly. Our example is simple and did not save data to a backend or retireve data from a backend database. The principles shown in this article are valid nevertheless, and a future article may go deeper into the code to show how to integrate a backend, for example .NET, into an Elm application.
Read more from Wolfgang on his blog where you can also find information about his books and online courses.