Kotlin WebApp Tutorial — ToDoList — Part 2

In part 1 we created the REST backend for our TodoList App. Now, in part 2, we will complete the app by creating the VueJS front end.

Setup

Most of the setup is already done; we have our server via SparkJava, and we have created the /public folder and specified in SparkJava that is where our static resources are loaded from, all we have to do now is create an HTML file. So let’s go ahead and create an index.html file in /src/main/resources/public.

Most of this is standard HTML, the things of note are:

  1. Line 6/7: Here we are loading VueJS and Axios (defacto http library for VueJS).
  2. Line 11: This is where the VueJS template code will live.
  3. Line 16: This creates a new VueJS app, and specifies that the element bounds are from with the element with ID of “app” (the div from line 11).

The data, methods and mounted we will come back to shortly, but are mostly self explanatory; data is the application data (the model), methods are the functions we call as events etc, and mounted is executed when the VueJS is setup and ready to start (similar to $(document).ready() in JQuery).

Let’s Add Some Todos

Update the code so that it looks more like below.

  1. Line 3: Here we’ve added an input text tag, which calls the addTodo method when the enter key is pressed.
  2. Line 4–8: We have added an unordered list, with the list items being generated by iterating over the todos data, and then outputting the text of the todo (we’ll add the done part later). This double brackets notation is called handlebars, and is the template style used by VueJS.
  3. Line 15: Here we have added a data item called todos, and configured it with an empty array.
  4. Line 18–23: This is the addTodo function. This uses axois to post to our server, passing the input text value in the body (event.srcElement.value) and then pushes the JSON response onto the data array (this will be the Todo JSON from the server). Finally, the input textnox is rest to blank so we can add more Todos.

Note: On our SparkJava server, we used staticFileLocation which reads the index.html from the created JAR file. This means we have to restart our server for our HTML changes to take effect. It is possible to use externalStaticFileLocation and specify a path outside of the JAR file, which means we do not need to restart the server each time we change our HTML, but this will not deploy to a different location. If you use this method, do so for testing only!

If we give this a go, we should be able to add elements, but if we refresh the page we lose our todos (they still in the database, but our page is not loading them on start up). Let’s fix that next.

Load All Todos

To load all the todos, we need to do that when VueJS has finished loading. This what the mounted() function was for. So let’s update that function with an axois request that loads all the todos from the server.

It really is that simple. We call a GET request to the server route that returns all Todos, which responds with a JSON array of Todos, which we simply store on our todos data element. We should now see our saved todos even after we refresh the web page.

Delete a Todo

Inside of the li update the handlebars code, so that it now looks like the following.

{{todo.text}} 
<a href="#" @click="deleteTodo(todo.id)">(delete)</a>

This calls the deleteTodo method (we’ll create this next) when the href is clicked, passing in the id of the todo into the method.

Next we need to create the deleteTodo method, which we will place inside of the “methods” curly braces, underneath the addTodo method (ensure that there is a comma after the closing curly brace of the addTodo function).

This function simply sends an HTTP Delete request to the todo path (which includes the passed in ID). If the response data is equal to “ok”, which we return from the server if the delete from the DB succeeded, we then iterate through the data array and delete the matching element.

Updating the Todo

The final piece of the app is to allow us to update the todo. In this example, I will just focus on the done flag, by creating a checkbox showing if the todo is done or not, and allowing the checkbox to be updated. Also, now that we will be able to set the todo as done, I will also update the delete link, so that it is only visible for completed todos (using the v-if filter of VueJS).

So, update the li so that it now looks like the following:

  1. Line 2: creates a checkbox, marking it checked when the todo.done boolean is true, and setting up an event called toggleCheck passing in the todo to update.
  2. Line 4: contains the updated code for the delete, with the v-if. This added code means that the <a href is only visible when todo.done is true.

Next we need to add the toggleCheck(todo) method, which we will add to the methods section.

  1. Line 1–4: this code simply inverts the done boolean of the todo, effectively toggling the value, and then calls the update method.
  2. Line 7: this code executes an HTTP Put (update) to the URL containing the todo’s ID, and passes in a JSON string in the body of the request. The JSON is the updated todo values (in our case, just the done value, but both values are required to be sent serverside).
  3. Line 8–13: when the server responds we simply iterate through the list of todos, looking for the todo that matches the ID that we updated, and the we update the values to match what is returned (therefore keeping serverside and clientside in sync).

And That’s It!

And there we have it. A simple (yes, I know the CSS is lacking), but functional ToDo app client side in 70 odd lines of HTML and Javascript, plus 90 lines of serverside code.

Full source code can be found on GitHub → https://github.com/codemwnci/KotlinToDoApp

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Wayne Ellis

Wayne Ellis

167 Followers

Software Architect; Author of Introducing the Play Framework; Technologist.