This article take a fresh look at a Mithril JavaScript Tutorial. Recently we were taking a look at the very slick Flarum Forum Software here at Vegibit, and one of the things we discovered is that it makes use of a great high performance JavaScript framework called Mithril. Peaking our interest, we decided to read up more about Mithril and have a play with the features it offers ourselves. What we found was an incredibly small footprint, and blazing performance, all the while staying true to a mostly native JavaScript syntax. Mithril Js is really cool, let’s learn all about it now.

Creating Virtual DOM Elements

We’ll begin by creating a button in the Virtual DOM, and then rendering it.

1 2 3 attachto = document . getElementById ( 'mfunction' ) ; renderthis = m ( 'a.btn btn-default[href=#]' , "A Button" ) ; m . render ( attachto , renderthis ) ;

<div id="mfunction"></div>



First we used the m() function to create a virtual anchor tag with bootstrap classes assigned. This was assigned to the variable renderthis. Next, we grab the element on the page with the id of one, and assign that to the variable attachto. Finally, we call the m.render() function and pass to it the attach point, and the newly created element to render. Cool stuff!

Mithril Components and Views

1 2 3 4 5 6 7 8 9 attachto = document . getElementById ( 'basiccomponentone' ) ; var Button = { view : function ( ) { return m ( 'a.btn btn-primary' , 'This is also a button, but it is blue.' ) ; } } ; m . mount ( attachto , Button ) ;

<div id="basiccomponentone"></div>



A more common way to display elements on the page is by using components. To do this requires a few steps.

Create a JavaScript Object Assign a function to the view property of said object Mithril will render what the function stored in view returns

Following these steps, we create a JavaScript object named Button, store a function in it’s view property, then pass the object to m.mount as the second argument. The first argument is where we want to attach it in the DOM.

Let’s look at another way to create a component, with a Hello World type example. This time around, we will say “Hello Mithril” using Mithril of course.

1 2 3 4 5 6 7 8 attachto = document . getElementById ( 'basiccomponenttwo' ) ; var app = { } ; app . view = function ( ) { return m ( 'h3' , 'Hello Mithril!' ) ; } ; m . mount ( attachto , app ) ;

<div id="basiccomponenttwo"></div>

Changing Application State

1 2 3 4 5 6 7 8 9 10 11 12 13 attachto = document . getElementById ( 'applicationstate' ) ; var State = { count : 0 , controller : function ( ) { this . count ++ ; } , view : function ( controller ) { return m ( 'button.btn btn-success' , { onclick : this . controller . bind ( this ) } , "The button has been pressed " + this . count + " times!" ) ; } } ; m . mount ( attachto , State ) ;

<div id="applicationstate"></div>



In this example, we start to look at the ability to change state in JavaScript, and have our views be updated in real time. If you click the button, you will see that each time you click it, the count increments. How does this happen? The key is writing views that reflect the state of your application.

The function contained in view will be run anytime an event which has been created in that function gets fired. It works kind of like this:

The page loads, and JavaScript executes, displaying the button. The user clicks the button, which invokes onclick, which in turn causes the function stored in view to run again! When that function runs, the virtual DOM is evaluated. If there are changes since the last iteration, the real DOM get’s updated.

Two Way Data Binding

Libraries like Angular, React, and VueJS introduced the concept of two way data binding. It is one of the core reasons in fact to even use a view library like this. You change the state of the application, and the view updates in real time, almost as if by magic. You can do two way data binding with Mithril as well, but the approach is slightly different. You will absolutely need to read up on m.prop() and m.withAttr() as these two functions are used together to make the data binding work. Let’s show a quick example, then run through the code to make sure we understand it.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var app = { } ; app . controller = function ( ) { this . stuffwetype = m . prop ( '' ) ; } ; app . view = function ( controller ) { return [ m ( 'label[for=instructions]' , 'type some text here!' ) , m ( 'input#instructions[type=text].form-control input-lg' , { value : controller . stuffwetype ( ) , oninput : m . withAttr ( 'value' , controller . stuffwetype ) } ) , m ( 'h3' , [ 'You just typed: ' , m ( 'span.text-warning' , controller . stuffwetype ( ) ) , ' into the box.' ] ) ] ; } ; m . mount ( document . getElementById ( 'twowaydatabinding' ) , app ) ;

<div id="twowaydatabinding"></div>

Did you try typing some text into the text box? Cool, right?! How does it work?

Well, the official documentation tells us that in Mithril, a component is simply an object which has both a controller and view function. So it looks like we meet the requirements of having a component since we have an app object, which holds a function in both it’s controller and view properties. As you type in the text field, a property called stuffwetype gets updated. This is due to the getter / setter functionality of m.prop(). The changes that occur to this property trigger visual updates in the View. Now comes the funky part, m.withAttr(). m.withAttr() is a little tricky to grasp at first, but we’ll step through it here. First off, the official Mithril documentation tells us the following:

The m.withAttr utility is a functional programming tool provided by Mithril to minimize the need for anonymous functions in the view.

m.withAttr() takes two arguments.

The first is a string representation of the element in the DOM to fetch. Note that m.withAttr() occurs inside of the call to m() which renders an input element. We are passing the string value of value to m.withAttr(). In this context, we are saying we want the current DOM value of the value property of the input element. Now, here is the tricky part.

The second argument passed to the m.withAttr() function is itself a callback. In other words, it is a function that will run, and here is the kicker: It is passed the property value of said element into it upon execution. In our case, we can see that the callback (argument two of m.withAttr()) is input.stuffwetype . As it turns out, what is stored in input.stuffwetype is the m.prop() getter / setter function which we declared in the controller. So this is what we mean by m.prop() and m.withAttr() working together. In an indirect kind of way, m.prop() is usually the second argument passed to m.withAttr() . Don’t you just love functional programming?! 🙂

withAttr Example

We’ll look at another example just to be sure we see how this special function works.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var withAttrComponent = { showoutput : function ( withAttrResult ) { m . render ( document . getElementById ( 'withAttr' ) , m ( 'div.alert alert-success' , [ 'The button you clicked has the class of ' , m ( 'b' , withAttrResult ) ] ) ) ; } , view : function ( ) { return m ( 'button.btn-lg' , { onclick : m . withAttr ( 'class' , this . showoutput ) } , 'What class do I have?' ) ; } } ; m . mount ( document . getElementById ( 'buttonlarge' ) , withAttrComponent ) ;

In this example, the second argument to m.withAttr() is this.showoutput just for fun. We know that the button on the page has a class of btn-lg, since this is how we constructed our view. Now, we can almost read the code of the call to m() in that view function like so: Go get me the value of the class property of the button element in the page, then call the function that exists in this.showoutput, and pass the value you found in step one to that function.

We create a simple little function that then renders the result of that operation onto the screen. If all went well, you should see “The button you clicked has the class of btn-lg” when you actually clicked the button. Smashing!

m.prop() and m.withAttr() work together

Let’s look at another example of how the m.prop() and m.withAttr() functions work together. In the text box below, type a message to send as an alert, then click the button. Try it a few times if you like.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var Alert = { message : m . prop ( '' ) , sendAlert : function ( ) { var div = document . createElement ( 'div' ) ; var attr = document . createAttribute ( 'class' ) ; attr . value = 'alert alert-success' ; div . setAttributeNode ( attr ) ; var attachto = document . getElementById ( 'alertexample' ) ; attachto . appendChild ( div ) ; var message = document . createTextNode ( this . message ( ) ) ; div . appendChild ( message ) ; Alert . message ( '' ) ; } , view : function ( ) { return [ m ( "input[type=text].form-control input-lg" , { onchange : m . withAttr ( "value" , Alert . message ) , value : Alert . message ( ) } ) , m ( "button.btn-lg" , { onclick : this . sendAlert . bind ( this ) } , "Send Alert" ) ] ; } } ; m . module ( document . getElementById ( "alertexample" ) , Alert ) ;

High Performance Rendering

This next example is a slightly modified version of some example code provided by Einar Norðfjörð from a rvk.js meetup. This is pretty incredible! His example makes use of a setInterval function in the controller to populate an array of 100 random numbers every 20 milliseconds. For brevity, in our example we just bump it down to 25. In the example below, you can click the run button to make it active and the stop button to make it stop. Now what is incredible, is that this code snippet does not actually need to remove the DOM and create a new DOM. It *only* replaces the value inside of the td element. This type of rendering is why Mithril is so incredibly fast. You’ll note your browser does not even break a sweat during execution of this example code.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 var app = { } ; app . running = false ; app . run = function ( ) { app . running = true ; } ; app . stop = function ( ) { app . running = false ; } ; app . controller = function ( ) { this . data = [ ] ; window . setInterval ( function ( ) { for ( var i = 0 ; i < 25 ; ++ i ) { this . data [ i ] = Math . random ( ) ; } if ( app . running ) { m . redraw ( ) ; } } . bind ( this ) , 20 ) ; } ; app . view = function ( ctrl ) { return [ m ( 'button.btn-lg btn-success' , { onclick : app . run } , 'Click to run' ) , m ( 'button.btn-lg btn-danger' , { onclick : app . stop } , 'Click to stop' ) , m ( 'table.table table-condensed' , [ m ( 'thead' , m ( 'tr' , [ m ( 'th' , 'Key' ) , m ( 'th' , 'Value' ) ] ) ) , m ( 'tbody' , [ ctrl . data . map ( function ( value , index ) { return m ( 'tr' , [ m ( 'td' , { style : 'width:50%' } , index ) , m ( 'td' , { style : 'width:50%' } , value ) ] ) ; } ) ] ) ] ) ] ; } ; m . mount ( document . getElementById ( 'random' ) , app ) ;

Views Are JavaScript

Before we go to much further, we will discuss a little bit about how views are created in Mithril. You may have noticed that we have not written any actual HTML in our code examples. So where the heck is the view? We have been trained recently to adhere to the new approach of pseudo HTML / JavaScript proprietary markup made popular by frameworks like Angular and React. In Mithril, there is no such need to strictly adhere to this approach, though you can make use of it if you like with the MSX HTML syntax preprocessor.

With this knowledge, we can see that Views in Mithril are created by using the m() utility method to create virtual DOM elements, which are then attached to the page with something like m.mount() . Recall that the convention is to have a function stored in the view property which should return the desired markup to appear on the actual page. It is a little different than what you might be used to, but it is very efficient and fast. A huge benefit provided by Leo Horie, the creator of Mithril, is a handy HTML to Mithril View converter. Simply paste in your HTML, and the Mithril specific JavaScript will be output to you. This makes working with this approach much easier, especially early on when you are coming up to speed with how to best make use of the m() utility function.

Putting It All Together: Task MVC

The final piece to our Mithril JavaScript Tutorial will be to hammer out a slightly refactored version of the sample application provided by the official documentation. We'll see that most of it is native JavaScript, with sprinklings of calls to the Mithril API, and an application structure which follows best practices with regard to Models, Views, Controllers, and Components. A task object will namespace the entire application, while a native JavaScript constructor sets up the properties of taskdescription and isfinished . The TaskList class holds all of the tasks for completion. Within our task object is a viewmodel property which holds the function representing the view model. It uses private variables and logic to track all tasks, store descriptions, and clears the text input field as needed. The task object also has a controller property which holds the function which simply initializes the viewmodel. Finally, we have the view property which holds a function that returns the markup to be rendered on page. Of course if makes heavy use of the m() utility function. If you choose to work with Mithril, this is one function you will rapidly become familiar with! Lastly, the application is attached to the DOM, and it is ready for action.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 // task is a javascript object which in the context of mithril is a component // it is used to namespace the model classes var task = { } ; // We now employ a JavaScript constructor to set up two properties, taskdescription and isfinished task . Todo = function ( data ) { this . taskdescription = m . prop ( data . taskdescription ) ; this . isfinished = m . prop ( 'false' ) ; } ; // TaskList is a class that holds an array of tasks to complete task . TaskList = Array ; // viewmodel is a self executing anonymous function that tracks a running list of tasks // stores a description for new tasks before they are created // takes care of the logic surrounding when adding is permitted // clears the input after adding a task to the list task . viewmodel = ( function ( ) { var _vm = { } ; _vm . init = function ( ) { //a running list of todos _vm . list = new task . TaskList ( ) ; //a slot to store the name of a new task before it is created _vm . taskdescription = m . prop ( '' ) ; //adds a task to the list, and clears the description field for user convenience _vm . add = function ( ) { if ( _vm . taskdescription ( ) ) { _vm . list . push ( new task . Todo ( { taskdescription : _vm . taskdescription ( ) } ) ) ; _vm . taskdescription ( '' ) ; } } ; } ; return _vm } ( ) ) ; // the controller defines what part of the model is relevant for the current page // in this case, there's only one viewmodel that handles everything task . controller = function ( ) { task . viewmodel . init ( ) } ; // vdom creation in the view task . view = function ( ) { return [ m ( 'label[for=inputTask]' , 'Type your task:' ) , m ( 'br' ) , m ( 'input.input-lg#inputTask' , { onchange : m . withAttr ( 'value' , task . viewmodel . taskdescription ) , value : task . viewmodel . taskdescription ( ) } ) , m ( 'button.btn-lg' , { onclick : task . viewmodel . add } , 'Submit Task!' ) , m ( 'table' , [ task . viewmodel . list . map ( function ( task , index ) { return m ( 'tr' , [ m ( 'td' , { style : 'width:33%' } , [ m ( 'button.btn btn-danger#false' , { onclick : m . withAttr ( 'id' , task . isfinished ) , checked : task . isfinished ( ) } , 'Mark Unfinished' ) ] ) , m ( 'td' , { style : 'width:33%' } , [ m ( 'button.btn btn-success#true' , { onclick : m . withAttr ( 'id' , task . isfinished ) , checked : task . isfinished ( ) } , 'Mark Complete' ) ] ) , m ( 'td.lead' , { style : { textDecoration : task . isfinished ( ) == 'true' ? 'line-through' : 'none' , width : '33%' } } , task . taskdescription ( ) ) ] ) } ) ] ) ] } ; // mounting the component to the page m . mount ( document . getElementById ( 'taskmvc' ) , { controller : task . controller , view : task . view } ) ;

Mithril JavaScript Tutorial Summary

Mithril JS is The High Performance JavaScript Framework! It's size and speed make it a fine choice for your view model needs. The thing about Mithril is that it does not try to force you into a hybrid syntax heavy architecture, which may be subject to change radically over time. Most of working in Mithril is plain JavaScript. In addition to that, Mithril is a gateway drug to true functional programming. It nudges you in that direction, and certainly helps you keep your native JavaScript chops growing. All of this makes Mithril JS a framework to dive into and learn from.