I think that
it’s high time we moved on to some practical exercises. We’ve done the
rounds of a large number of basic Node.js features and we’ve learnt how
to use the Express micro-framework.
But
you only get a true feeling of understanding once you’ve practiced and
completed your first real app. This is what I’m going to suggest you do
in this practical exercise.
We’re going to create a to do list. The visitor will simply be able to add and remove tasks.
So we’ll start with something simple. Then you’ll be able to improve it in any way you want to!
So we’ll start with something simple. Then you’ll be able to improve it in any way you want to!
Before going any further, I’m going to show you the page that we’re going to create (next figure).
- We can add elements to the to do list via the form.
- We can delete items by clicking on the crosses in the list.
- The list is stored in the visitor’s session. If someone else connects to the site, they will have their own list.
The
instructions are simple and the final code won’t be very long. However,
if it’s your first more complex app using Node.js, you’ll probably
fumble around a bit and move forward slowly. Don’t worry, it’s perfectly
normal! Keep at it and if you really need to, read the "A bit of help"
section before comparing your work with mine.
You’ve got all the information, now it’s over to you!
Need help?
So you need a bit of help? You're lost and don't know where to start?
Remember how we want our final application to look like. I showed you a screenshot of it earlier (see next figure).
Modules and package.json
Let’s take a deep breath and look at things in the right order. What do we need?
- Express: without the Express framework the job will be very difficult. Now that you know how to use this framework, it would be a shame to leave it out.
- EJS (or another template system): this will allow us to easily construct the HTML page that displays the to do list and the form.
In theory, these modules are enough. A good first exercise would be to create a
package.json
file in our project’s folder:
{
"name": "my-todolist",
"version": "0.1.0",
"dependencies": {
"express": "~4.11.0",
"ejs": "~2.1.4",
"cookie-session": "~1.1.0",
"body-parser": "~1.10.1"
},
"author": "Mateo21 <mateo21@email.com>",
"description": "A very basic to do list manager"
}
Obviously, you can obviously replace the name, the author and the description with whatever you like.
For
the Express and EJS version numbers, I based myself on the versions
available when this course was written. As Node.js advances very
quickly, you will most likely have more recent versions. The tilde ( ~ )
allows for future patches on these modules, but not for new minor or
major versions, which guarantees that their API won’t change and that
our code will continue to work even with these updates.
Now that you have your
package.json
, install the dependencies using a simple:npm install
We’re ready to start working!
Routes
I
said earlier that the definition of your routes was important when
constructing a web app. If you’re hesitating and don’t know where to
start, I would suggest you list the routes of your app. What should it
do?
- List the tasks.
- Add a task.
- Delete a task.
In theory, we can associate a route to each of these features:
/todo
: list of tasks./todo/add
: add a task./todo/delete/:id
: delete task n°id.
So you’re going to write the routes in your app.js file like this:
.get('/todo', function(req, res) {
});
// ...
However,
it would be a good idea to take a quick look at the form. Generally,
forms send data using the POST method and not the GET method. So adding
tasks is going to be done on the /todo/add route but with the POST
method. That’s why instead of calling for
.get()
, we’ll call for.post()
for this route:
.post('/todo/add/', function(req, res) {
})
The right way to chain calls to middleware
We
know that we need a session system. The documentation on the
cookie-session piece of middleware I mentioned to you earlier tells us how to use the sessions.
Another thing: we would need to retrieve the data from the form in
/todo/add
.
We’ve learnt how to retrieve the settings from the URL but not from
forms. It’s actually really easy. You just need to include the
middleware body-parser. You’ll then have access toreq.body.nameOfField
.
Therefore, the start of our JavaScript code should look something like this:
var express = require('express');
var session = require('cookie-session'); // Loads the piece of middleware for sessions
var bodyParser = require('body-parser'); // Loads the piece of middleware for managing the settings
var urlencodedParser = bodyParser.urlencoded({ extended: false });
var app = express();
/* Using sessions */
app.use(session({secret: 'todotopsecret'}))
/* Route management below
.... */
The
secret
setting
sent to the session module is compulsory: it allows the session cookies
to be secured. Send the value of your choice. Note that you can send other options, such as the lifespan of your session cookie (by default, the session will last as long as the browser is open).
OK, I’ve already said too much, it’s up to you to get coding!
Correction
OK,
it’s time for correction. Don’t read this section unless you’ve
successfully completed the task or all your attempts have failed and
you’re desperate.
The
code isn’t that hard to read in the end. It’s not very long either, but
you had to think carefully to find exactly what needed writing.
The answer
This is the JavaScript code that I created in the main app.js file. Remember that this is just my version and that your code doesn’t have to be identical to mine!
var express = require('express');
var session = require('cookie-session'); // Loads the piece of middleware for sessions
var bodyParser = require('body-parser'); // Loads the piece of middleware for managing the settings
var urlencodedParser = bodyParser.urlencoded({ extended: false });
var app = express();
/* Using sessions */
app.use(session({secret: 'todotopsecret'}))
/* If there is no to do list in the session,
we create an empty one in the form of an array before continuing */
.use(function(req, res, next){
if (typeof(req.session.todolist) == 'undefined') {
req.session.todolist = [];
}
next();
})
/* The to do list and the form are displayed */
.get('/todo', function(req, res) {
res.render('todo.ejs', {todolist: req.session.todolist});
})
/* Adding an item to the to do list */
.post('/todo/add/', urlencodedParser, function(req, res) {
if (req.body.newtodo != '') {
req.session.todolist.push(req.body.newtodo);
}
res.redirect('/todo');
})
/* Deletes an item from the to do list */
.get('/todo/delete/:id', function(req, res) {
if (req.params.id != '') {
req.session.todolist.splice(req.params.id, 1);
}
res.redirect('/todo');
})
/* Redirects to the to do list if the page requested is not found */
.use(function(req, res, next){
res.redirect('/todo');
})
.listen(8080);
Nice middleware chaining, isn’t it?
There’s also a template file that goes with it. The
todo.ejs
file:
<!DOCTYPE html>
My todolist
a {text-decoration: none; color: black;}
My todolist
todolist.forEach(function(todo, index) {
href="/todo/delete/ index "✘ todo
});
action="/todo/add/" method="post"
for="newtodo"What should I do?
type="text" name="newtodo" id="newtodo" autofocus
type="submit"
And with that, the essential package.json that allows the dependencies to be installed with a simple
npm.install
:
{
"name": "my-todolist",
"version": "0.1.0",
"dependencies": {
"express": "~4.11.0",
"ejs": "~2.1.4",
"cookie-session": "~1.1.0",
"body-parser": "~1.10.1"
},
"author": "Mateo21 <mateo21@email.com>",
"description": "A very basic to do list manager"
}
The explanations
My code is already fairly well explained, which should allow you to navigate it easily.
You’ll see that I allowed myself to redirect the visitor to the list (
/todo
) after items were added or deleted, usingres.redirect(‘/todo’)
.
The
task list is stocked in an array. It is also this which causes the
slight subtlety of this program: as JavaScript doesn’t like going
through arrays that don’t exist, I created a piece of middleware which
creates an empty array if the visitor doesn’t have a to do list (because
they just started a session, for example). That’s the role of this
code:
.use(function(req, res, next){
if (typeof(req.session.todolist) == 'undefined') {
req.session.todolist = [];
}
next();
})
This middleware
function receives the request, the response and the next function to
run. So I wrote a piece of middleware myself along the lines of
cookie-parser
or cookie-session
.
Its role is very simple: it checks to see if there’s a to do list in
the session and, if this isn’t the case, it creates an empty array
(which is why we have the[]
). This prevents a lot of errors later on.
Why create the middleware? Because it’s the only way able to run the features before any pages load. So that the middleware ‘passes the hot potato to its neighbor’, I must finish by a
next()
call (for the following function). In this case,next()
refers to.get(‘/todo’, function (){})
.
This aside, there isn’t really anything special. I add items at the end of the array using
.push()
and I remove them with.splice()
, but that’s basic JavaScript.
What’s so special about the template? Not a lot, other than I browse my to do list with a forEach (again, it’s JavaScript):
todolist.forEach(function(todo, index) {
href="/todo/delete/ index "✘ todo
});
Downloading the project
I’ve given you all the code for the project, but if you must download it all in a .zip file, go to the following link below:
Download the Node.js project: my-todolist.zip.
Don’t forget to do annpm installto install the dependencies before running it!
Taking it further!
My little to do list is very basic. You can add numerous features to it:
- Modifying task names.
- Rearranging tasks amongst themselves.
- Exporting a CSV.
- Attributing priority and deadlines.
- Preserving the to do list (storing it in a database or an NoSQL base).
- Sharing a list amongst several people.
- Synchronizing the to do list in real time between people without needing to reload the page.
Some of these features are easier to do than others. If you want to create new ones, you’ll have to find and use new modules.
You’ve got enough to keep yourselves amused for a good while now, good luck!
No comments:
Post a Comment