There are many task managing apps out there, but it’s always exciting to make an app of your own. In this walkthrough, I’ll show you how to write a simple task-managing app that will work in your browser. In later episodes, I’ll show you how to upgrade this task manager to include more features.
This is a very basic walkthrough, aimed at beginners. If you are experienced in HTML and JavaScript, don’t expect much from it. But hey, one step at a time is the best way to learn.
Tools
For this to work, I’ll need a basic text editor and a browser. There are browsers on literally every machine now; I’ll use Chrome. As for our text editor, I prefer Sublime Text for simple tasks like these.
The main idea
In the text editor, I’ll create a web page that has a script. This script will be responsible for managing my tasks.
The task manager itself will be a simple list of bits of text. Those bits will be my tasks. Underneath this list, (or above it, whichever you decide), I’ll put an input box for new tasks.
The data about my tasks will be stored in Localstorage—that’s an area of memory that lives in your browser and helps store the data related to specific webpages. If I reload the page or restart my computer, my Localstorage will hold on to my tasks, and so the next time I open up the page, my tasks will be there.
Basic page layout
I’ll begin with the bare minimum for the page. This code below tells the browser that this is an HTML document. The tags
HEAD
and BODY
are required for the page to work, but at the moment, this page does nothing—it just exists. <!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>
I’ll save this as a file—for example, task-manager.html. We need to include “HTML” in the name of the file so that the browser can recognize the page and open it correctly. This page can sit anywhere on my computer.
Populating the Head
In an HTML document, the Head contains service information about the page: what its language is, how the page works with other browsers etc. Frankly, we don’t need to go too deep into this: I just copied the code from a verified source.
So, here’s what needs to go between the
<head>
and </head>
tags:<title>My Task Manager</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
Populating the Body
Now let’s add something legible to the Body section of the page. The Body section holds the actual contents of the document. So whatever I put here will be rendered.
At the moment, I want to create a header and an input box. Inside the code, I’ll put the
<!--
signs. When I write things in between the <!--
and -->
signs, these are my comments on my code; they are not rendered by the browser. Read these comments to understand what each line of code stands for: <div class="container" style="width: 400px; margin: auto;">
<!-- Invisible boundaries for our app. The width is 440 pixels. Our app should sit in the center of the screen. -->
<h2 class="todo__caption">My Tasks</h2>
<!-- That was the header. -->
<!-- Next will come the input field where we can type our tasks. -->
<div id="tdlApp">
<input type="text" class="form-control" placeholder="Add a task here">
<!—Now let’s create a list of tasks, a list that’s currently empty. -->
<div class="tdlDiv">
<ul class="tdList list-unstyled">
<!-- Our tasks will appear here later. -->d
</ul>
</div>
</div>
</div>
If you saved the page now and then opened it in your browser, you’d see a header and an input box. Nothing would work just yet, but we’ve made a great start.
Making it beautiful
I prefer to make an app look good first, then create the code that makes it work. This is because once I’ve written that code, the app starts working, and I no longer have the patience to make it beautiful.
So I’ll spend some time making our new app look nice now, and I’ll create the working code later.
This app will run as a webpage in my browser. To make a page look good, developers use something called CSS—that’s a kind of markup language that tells the browser everything about the appearance and design of a page. Hence the name—Cascading Style Sheets. It’s all about the style.
We can apply different styles to the things on a page. We can make a style describe a certain HTML tag—for example, we can make a style for all Inputs. Since I’ve only created one input, this style will only affect one object on my page. But if I had many inputs, this style would affect them all.
CSS also supports something called ‘classes.’ A class is a kind of a label for a style. For example, we can create a class called ‘
.importantTask
’ and apply it to specific tasks in our list. And we can specify that ‘
.importantTask
’ has to be red. That way, all tasks that are tagged ‘.importantTask
’ will appear in red. Then we could change our mind and make ‘.importantTask’ not red, but blinking and bold instead. Then all tasks with the class ‘
.importantTask
’ would become bold and start blinking.It’s a good idea to write all our styles in the Head section of the page, so we give the browser all the design instructions before it draws anything on the screen. However, it’s technically possible to place styles anywhere in the document—today’s browsers are so fast, they can handle it just fine. But I’d keep it old school and place my styles in the
<head>
...</head>
. Observe this code and the comments. (Note: in CSS, we write comments in between /*
and */
.) <style type="text/css">
/* These next instructions will apply to BODY—that is, to the whole page. These instructions should be self-explanatory: how the text is aligned, what the page margins are, what the font is, etc. In CSS, most things turn out to be exactly what they say on the box.* /
body{
text-align: center;
margin: 10;
font-family: Verdana, Arial, sans-serif;
font-size: 16px;
}
/* This next set of instructions relates to the INPUT tag, which is where we input text when using the app. */
input{
display: inline-block;
margin: 20px auto;
border: 2px solid #eee;
padding: 10px 20px;
font-family: Verdana, Arial, sans-serif;
font-size: 16px;
}
/* The next set of styles will apply to a class. We’ll call this class ‘.task’ and use it for all our tasks. */
.task{
text-align: left;
padding: 10px;
cursor: default;
border-radius: 7px;
}
/* What happens if we hover the mouse over a task? */
.task:hover{
background-color: lightblue;
}
</style>
Preparing the script
I now need some application code that will take care of accepting new tasks, storing them, retrieving them from memory, and deleting them if necessary. I’ll do this in JavaScript—a simple scripting language that any modern browser can support.
To run scripts in JavaScript (JS), I need to add the tag
<script>
...</script>
to the page. By the time it executes a JS script, the browser should have already loaded everything on the page. So, it’s a good idea to place the script at the very end of the Body section, not at the beginning. If I place my JS script at the beginning and tell the script to manipulate some part of the page that hasn’t loaded yet, my script won’t work.To include jQuery, I’ll use this code in
Head
or Body
:<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
I’ll need to make sure that jQuery is loaded before I write my script, so I can use things from jQuery. If I write my script before jQuery loads, I’ll be referencing parts of jQuery that haven’t been loaded yet, and that will throw and error.
A few words about Localstorage
Every browser has
Localstorage
. As we mentioned earlier, that’s a bit of memory that allows your browser to store data related to specific pages. With JavaScript, I can read from and write to Localstorage. So, I can use this area to store my tasks.Localstorage works well for our project because Localstorage is immune to us reloading the page, rebooting the browser, resetting the internet router, and whatnot. Even if the page freezes, we close the browser, and our internet connection goes dead, the tasks will still be stored properly.
The downside is that Localstorage doesn’t sync across multiple devices, pages, or browsers. My page can’t read from another page’s Localstorage; it’s restricted to its own Localstorage. So, if I open my task manager on a different computer or even on my own phone, I won’t see my tasks.
If I wanted to sync my tasks across many devices, I’d need a whole lot of infrastructure: a server, a login-pass routine, a password recovery system, and much, much more. So, I’ll keep it simple for now.
Showing all available tasks
Once the page has loaded, I want my script to look into Localstorage and see if there are any tasks already stored. Here is the code with my comments. (In JavaScript, comments come after
//
).function showTasks(){
// Find out if there is anything lying around in Localstorage and waiting for us:
var Storage_size = localStorage.length;
// If there is something...
if (Storage_size > 0){
// then add it into the task list
for (var i = 0; i < Storage_size; i++){
var key = localStorage.key(i);
if(key.indexOf(Mask) == 0){
// and make it part of the task list. We’ll use a jQuery command for that:
$('<li></li>').addClass('task')
.attr('data-itemid', key)
.text(localStorage.getItem(key))
.appendTo(List);
}
}
}
}
// At this point, we’ve defined the function, but we haven’t run it yet. Let’s run it now:
showTasks();
If we save our code and reload the page in our browser now, nothing will change visually, but the script already works: it’s going into Localstorage and checking for new tasks. But since Localstorage is empty, there is nothing to display. Good, let’s keep going.
Adding new tasks
Our program will add new tasks whenever the user inputs something into the input field and presses Enter. We can use JS to make this happen:
/ We’ll use a jQuery command that gets read like this: Start by looking at an input called ‘tdlApp’. When a key is pressed inside of that input, do the following things.
$('#tdlApp input').on('keydown',function(e){
// If the Enter (code 13) key wasn’t pressed, never mind; just await the next keystroke.
if(e.keyCode != 13) return;
// This next line of code will only run if Enter was pressed.
// Next line: put whatever was in the input field into temporary memory, under the name ‘str’. Str now holds our task.
var str = e.target.value;
// Then we’ll make the input field blank. The task will stay stored inside the memory, although user can’t see that task in the task list yet.
e.target.value = "";
// If the user has indeed written something in the input field, we’ll first count up the current tasks before we add the new one to the task list. That way, we can put our new task on the list in the proper order.
if(str.length > 0){
var number_Id = 0;
List.children().each(function(index, el){
var element_Id = $(el).attr('data-itemid').slice(4);
if(element_Id > number_Id)
number_Id = element_Id;
})
number_Id++;
// Now we’ll send the task into Localstorage...
localStorage.setItem(Mask+number_Id,str);
// and inject the task into the task list:
$('<li></li>').addClass('task')
.attr('data-itemid', Mask+number_Id)
.text(str).appendTo(List);
}
});
Removing tasks by clicking
I’ll now add a small snippet of code that removes a task from memory and from the list if you click on it:
// The next line of code adds an event: let something happen when someone clicks on an object with a .task class.
$(document).on('click','.task', function(e){
// Which task was clicked?
var jet = $(e.target);
// Remove that item from Localstorage…
localStorage.removeItem(jet.attr('data-itemid'));
// and from the list, too.
jet.remove();
})
The final product
Once we’ve saved the code and reloaded the page in our browser, our brand new Task Manager will look like this:
Note that this code has a few limitations:
And now, without further ado, here is the final code:
<!DOCTYPE html>
<html>
<head>
<title>My Task Manager</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
body{
text-align: center;
margin: 10;
font-family: Verdana, Arial, sans-serif;
font-size: 16px;
}
input{
display: inline-block;
margin: 20px auto;
border: 2px solid #eee;
padding: 10px 20px;
font-family: Verdana, Arial, sans-serif;
font-size: 16px;
}
.task{
text-align: left;
padding: 10px;
cursor: default;
border-radius: 7px;
}
.task:hover{
background-color: lightblue;
}
</style>
</head>
<body>
<div class="container" style="width: 400px; margin: auto;">
<h2 class="todo__caption">My Task Manager</h2>
<div id="tdlApp">
<input type="text" class="form-control" placeholder="Add task">
<div class="tdlDiv">
<ul class="List list-unstyled">
</ul>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js">
</script>
<script>
var List = $('#tdlpp ul');
var Mask = 'tdl_';
function showTasks(){
var Storage_size = localStorage.length;
if (Storage_size > 0){
for (var i = 0; i < Storage_size; i++){
var key = localStorage.key(i);
if(key.indexOf(Mask) == 0){
$('<li></li>').addClass('task')
.attr('data-itemid', key)
.text(localStorage.getItem(key))
.appendTo(List);
}
}
}
}
showTasks();
$('#tdlApp input').on('keydown',function(e){
if(e.keyCode != 13) return;
var str = e.target.value;
e.target.value = "";
if(str.length > 0){
var number_Id = 0;
List.children().each(function(index, el){
var element_Id = $(el).attr('data-itemid').slice(4);
if(element_Id > number_Id)
number_Id = element_Id;
})
number_Id++;
localStorage.setItem(Mask+number_Id,str);
$('<li></li>').addClass('task')
.attr('data-itemid', Mask+number_Id)
.text(str).appendTo(List);
}
});
$(document).on('click','.task', function(e){
var jet = $(e.target);
localStorage.removeItem(jet.attr('data-itemid'));
jet.remove();
})
</script>
</body>
</html>
Found this walkthrough helpful? Explore Practicum. We make it simple to learn programming, data science, and more tech skills from expert mentors.