I mainly code in Elm but the other day I took a look at Vue, writing a small example that I copied from a tutorial video. Several things went wrong.

This is the example:

This is a working demo: https://codepen.io/lucamug/pen/aXdPqw

It is a simple application that send an HTTP request, retrieve a list of products, list them with the stock quantity and let the user either edit the quantity or add 1 to the quantity with a button showing the total of the inventory:

…but

#1 “Total Inventory” doesn’t work

While the “Add 1” buttons work fine, typing number in the input field give wrong result:

Let’s type 123. What? Where 01123052 is coming from? I guess someone is trying to concatenate strings instead of adding numbers. Note also that the list of quantities is now [“1123”,0,5,2].

After some research in the Vue documentation I found this:

“If you want user input to be automatically typecast as a number, you can add the number modifier to your v-model managed inputs”

It sounds exactly what we needed. Let’s add it in our script at line 3:

from

<input type="number" v-model="product.quantity">

to

<input type="number" v-model.number="product.quantity">

Fixed!

#2 “Total Inventory” is broken again!

Now typing digits works, but if we delete all digits we are getting again the same problem discussed above.

Ok, maybe we should refactor the function that calculate the Total Inventory.

Let’s add a condition at line 20 that, if the quantity is not a number, the value is skipped.

From

totalProducts() {

return this.products.reduce((sum, product) => {

return sum + product.quantity

}, 0)

}

to

totalProducts() {

return this.products.reduce((sum, product) => {

if (typeof product.quantity === "number") {

return sum + product.quantity;

} else {

return sum;

}

}, 0)

}

Fixed!

#3 The “Add 1” button sometime doesn’t work

The button doesn’t work if pressed after we remove all digits or we type non-numeric characters:

Ok, time to fix this one too. Let’s change the command that add 1 (line 4) from

<button @click="product.quantity += 1">

to

<button @click="product.quantity = Number(product.quantity) + 1">

Fixed!

Vue/Javascript experience

Maybe these issues came from my lack of knowledge of Vue but I was expecting a smoother experience.

Maybe using the magic two-way data binder v-model is not a good practice and we should rather use one-way binding?

Even if the application now works, the array of quantities still contain a mix of strings and numbers, that is a prelude for other issues in the future. For example when this data will need to be saved permanently somewhere.

Also all the above issues were detected just using the application and not automatically by the development environment. They could have been easily passed undetected and go to production.

Elm experience

Demo for the Elm version: https://ellie-app.com/4yx6ZpH7w2Ra1

This is the code. It consists of two parts, a small html section to load and initialise the page, and the Elm code that will compile to Javascript:

Elm forces us to consider many more cases, like the one that are responsible for the issues above.

The quantities are of type Integer so is not possible to store any string in them.

We need to convert the string that we get from the input field into an integer before saving it. Then we need to convert it back to a string before displaying it in the page.

During the conversion from string to integer things can go wrong, for example when the string doesn’t contain a valid number. Also in this case Elm want to know from us how we want to deal with such a case.

One of the important part is, as mentioned above, when we convert from string to integer:

{ product

| quantity =

Maybe.withDefault product.quantity

(String.toInt newQuantity)

}

This piece of code says: “If the user typed a valid number, replace the old number with the new one, otherwise keep the old number”

The Elm version doesn’t allow any impossible state so it doesn’t allow to delete all the digits from an input field because that would not be a valid number. This make difficult to change the single digit. This could be fixed checking if the string is empty and converting to a 0, for example. But here we would enter in the realm of issues related to the input field of type number.

In any case, the Total Inventory is always correct and the list of quantities always contains numbers, out of the box.

There are other things that Elm force us to consider, for example the case when the HTTP request fail, but these go out of the scope of this post. So in the Elm version we ignored this request just returning the old list of products and no commands:

GotProducts (Err _) ->

( products, Cmd.none )

Closing HTML Elements

One thing that I was not doing for long time was writing HTML and specifically closing HTML elements. I have been using HAML, Jade and Pug before working in Elm.

Working on this example reminded me the good old days when I was opening a <DIV> and closing a </P>.

Typos

While several type of typos will generate a runtime error in Vue, there are others that go undetected. For example changing

<input v-model.number="product.quantity">

into

<input v-model.number="product.quanity">

does not show any error but the application is broken (all input fields are empty and typing in them nothing happen. The buttons are still working).

Other errors will only show when interacting on the interface but not on loading.

In Elm the above typo generate this error at compile time:

Detected errors in 1 module.

-- TYPE MISMATCH ----------------------------------------- Main.elm The 2nd argument to `map` is not what I expect: 84| products

^^^^^^^^ This `products` value is a: List Product But `map` needs the 2nd argument to be: List { a | id : Int, name : String, quanity : Int, quantity : Int } Hint: Seems like a record field typo. Maybe quanity should be quantity?

Note the “Hint” section at the bottom.