Behind the scenes, I've updated the HTML UI and added in some helper JS functions to allow us to render new to-do's. We are going to start off by adding in the UI for a user to be able to input their own to-dos. Then we are going to work on creating a backend to store that data and retrieve it using our KV key of "data"
.
Instructor: [0:00] We've successfully set up an HTML page and sent the KV data from our KV namespace into the HTML page as a JavaScript variable.
[0:09] What I've done is updated the design slightly and added some helper JavaScript functions, which will allow us to render new todos in the UI. Looking at the HTML, I've added a HEAD section, giving it the title of, todos, and then adding Tailwind CSS.
[0:24] In the body, I've set up a body with a bg-blue-100 background, a couple divs, and most importantly, a div here which has the ID, todos.
[0:34] In our script tag, there's a corresponding function to the todos variable called populateTodos, which targets that div with the ID of todos, clears it out. After clearing out the HTML inside of that container, it loops through window.todos, and for each item inside of that array, creates a set of HTML elements that represents the todo item in the todo list.
[0:55] That includes a div, a span, which has the actual name of the todo and then an input, which is a check box showing whether the todo is completed or not. Finally, at the end here, it appends it to the todo container so you can see it in the UI.
[1:09] Obviously, if you want to use something like React or Svelte, or any sort of frontend JavaScript framework to accomplish this, you can. In this case, plain JavaScript works fine.
[1:19] With our updated design and the basic JavaScript function set up, the next thing we need to do is allow the user to create todos in the UI. To do that, I'm going to paste in some HTML that I've written, which is a simple div with a flexbox layout.
[1:33] Then, inside of it an input which represents the new todo item. This button here which represents how we create a new todo. It has an ID of create and that's what we'll target any time that someone clicks that button to call a corresponding function for creating a todo.
[1:46] In order to do that, I'm going to make a new function called create todo. Inside of that, I'm going to target an input, which has a name attribute that matches name. That's going to be the name of our todo that we're writing. Then I'll check and make sure that input value has length.
[2:01] Basically, if that input has been filled in at all. If it has, I'm going to update window.todos. To do that, I'm going to use the array.concat feature, which is a function that takes an arbitrary number of arrays and items, and creates a new array and appends all of them to it.
[2:20] This is an empty array, which I'm going to concat both todos, that's our original list of todos. Then, this object here, which is going to represent a new todo. Inside of that, I'm going to set ID which is going to be window.todos.length+1. Basically, the current ID or size of the todo list, plus one.
[2:41] When we have a single todo in that list, it will be an ID of one, ID of two, etc., a name, which is going to be the value of that input. For instance, if I write in my input field, take out garbage can, the value here is going to be the actual text inside of that input. Then, Completed, which is going to default to False. Obviously, it's a new todo, so we haven't completed it yet.
[3:06] After that, I'm going to clear out the input. Make the text field blank again, so I can write another todo in the future. Then, I'm going to call this updateTodos function, which is going to make a request to my Workers function and update Workers KV. We'll define that in a second.
[3:23] With that function complete, the last thing I need to do is connect it to my Create button. I'll say, document.createSelector, looking for the ID of Create, which is our button up here. When I've found that button, I'll say, addEventListenerclick, so listen for new clicks on that button and call the createTodo function any time that it is clicked.
[3:46] The last thing we need to do is define this updateTodos function. Up until now, everything we've done has been UI or frontend-focused code, where we're manipulating data on the frontend, or querying HTML elements. This updateTodos function is going to be what makes a request back to our Workers function and updates our KV namespace.
[4:05] To do this, I'll make a new function called updateTodos. Inside of that, I'm going to make a fetch request, which I'll make to the root route here of my Workers function, and then parse in a couple of options.
[4:18] First, is the method. This is going to be a PUT request to our Workers function. Here, in the body, I'll say, json.stringify window.todos. Just taking this array and making it a JSON string, which gets sent up to Workers KV.
[4:33] Back in createTodo, I updated this array to add my new todo after I've written it in the input field. I'm going to be sending here, using the fetch request, is an updated version of that array.
[4:44] Then, finally, I'm going to call this populateTodos function. This is the helper function that I showed you earlier, that clears out the entire UI and rewrites the todos elements from scratch. It'll start with a clean slate for a second, before adding all of our todos, including the new one, to our user interface.
[5:02] This request here, we haven't set up to handle yet, because it's a fetch request that has a PUT method attached to it. Everything we've done up until now is making GET requests to our Workers function. To do this, we're going to update our handleRequest function to just have more logic around looking at the incoming requests, and doing different things accordingly.
[5:23] I'm going to say, if request.method = 'PUT', return updateTodos, and parse in the request variable here, else, do the default behavior, which we've already been doing up until now, which is, call getTodos. This PUT request that might come in, we'll call this updateTodos function. Otherwise, anything else, we'll call this getTodos function that we've been using up until now.
[5:48] The next thing we need to do is create this updateTodos function. To do that, I'm going to make a new async function, called updateTodos, which takes request in. Then, I'll begin defining the behavior for handling the KV data coming from our UI.
[6:03] The first thing I want to do is parse the data coming back from the request. To do that, I'll say, await request.text. This will make the text of my request body that's being parsed in, available as this variable body. The second thing I'm going to do is set up a cache key.
[6:20] This is the same cache key, importantly, that I'm using here in my getTodos function, because I want to make sure I'm reading and writing to the same key so I can handle any changes, and obviously, see them, by making sure I work with the same KV key and the same KV data, in between these two different kinds of requests.
[6:38] The next thing I'll do is add a try-catch block, because the code that we're going to write here has the potential to fail. It's important that we catch an error here and return it appropriately if something goes wrong.
[6:48] First, what I'm going to do is try and JSON.parse the body. I do this here in this step, because instead of parsing it here directly, I want to make sure that the body that's being sent up is valid JSON before it gets set into Workers KV, because if it's not, it's going to cause the entire application to stop working.
[7:05] If we do know that it parses correctly, that is, it doesn't fall into this catch section, the next thing we can do is call await setCache, and give it both the cache key and the body. SetCache is a function, we'll define here in a second, to update our Workers KV data. I'll parse in the cache key here, which is going to be data, and then the body, which is the data coming from our request.
[7:28] Finally, if everything works, we'll return a new response with the body, returning the todos back, and then give it a status code of 200. Though, if something goes wrong, in our catch block, we'll return any response, parsing in the error here as the body of that response, and a status of 500.
[7:46] For our last function, we're going to add setCache, which is very similar to getCache, but with the added addition of a data argument. We're passing in both the key as well as data, which is what we're going to be setting for the key in Workers KV. Instead of get, I'll say my-first-kv.put, with the key, and then the corresponding value, which is data.
[8:08] Now we have a complete getTodos, which gets the information from Workers KV and the corresponding updateTodos, which takes incoming data and sets it to KV. If we publish our function one last time, we'll have everything that we need in order to build a fully-featured todo list application, entirely on Cloudflare Workers KV and Cloudflare Workers.
[8:29] I'll refresh the page. You can see that I now have this, a new todo input field and the corresponding button. I'll say, "Finish my egghead course," and then I'll click Create. You can see that it appears here in the UI, so the UI has properly rendered this data that's inside of the client-side application.
[8:47] Though the real test here is going to be what happens when we refresh. I'm going to inspect here. You can see right now, that inside of my script tag, window.todos is empty, because that is the value that was assigned when the page loaded for the first time.
[9:02] If I refresh the page, you can see that we expected things to work, but there's an error here. This is something that I run into all the time. Actually, ran into while recording this course. It's interesting to note it, and make sure that we fix it and handle it appropriately as we work with KV data.
[9:19] You can see this window.todos here is not an array. It is a JSON string that has an array inside of it. What we've done wrong here, is instead of embedding this window.todos here, instead of saying data, what we need to do is say, JSON.parse data. This is because we need to return the object embedded inside of that, that is a array, not a JSON string with an array inside of it.
[9:46] That's going to be what will allow us to use that data inside of our JavaScript. I'll publish my project one more time. Then, back in browser, if I refresh the page, you can see that window.todos is no longer a string, it's an actual JavaScript array, with the object that has our todo list item inside of it.
Member comments are a way for members to communicate, interact, and ask questions about a lesson.
The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io
Be on-Topic
Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.
Avoid meta-discussion
Code Problems?
Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context
Details and Context
Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!