Backstory
It started that I would like to have my students to vote for their peers’ presentations. And I don’t like to do it the old fashion paper way. I thought of using some commercial products. But since I was reading a little bit JavaScript couple weeks ago, I guess it probably would be a nice small project to hone my skill. It spent me two days to put together the pieces but it turns out the final thing is quite short and simple.
Before I started, I only knew a little bit of JavaScript and just realized that node.js was Google’s reply of JavaScript server-side programming. I have primitive understanding of server-client models and I knew some html but hardly expert on that also. I knew little to none web programming (I did some php more than a decade ago and I literally forgot everything). I am an electrical engineering (signal processing guy) by training. I am good at matlab, use some python/numpy, and know some java (don’t write it much tho). That’s about it.
I will try to go through my experience of learning the things. But if you just want to try it out yourself, you can skip right to here.
Form and Formidable
The first thing I wanted was some kind of a form that I can let my students submit their votes. After some google search, I settled with this example with the Formidable. The basic form is like
var formidable = require('formidable'); function processAllFieldsOfTheForm(req, res) { var form = new formidable.IncomingForm(); var user_id = req.param('id'); form.parse(req, function (err, fields, files) { ... // fields, files // contain dictionary structure of the form input
Great! It looks super simple and I can get all information after I hit the form submit button. That is exactly what I want.
Express-Formidable
I can’t help coming across with “express” after a bit more online reading of node.js. It is actually the most widely used package and its bare minimum definitely looks simple
var express = var app = app app
What I need though is how I may combine express with formidable, I am sure someone did that before. I came across this express-formidable package but couldn’t quite make that work. It turns out that it seems that I can just use (require) the two packages together without much issues. Anyway, problems (kind of) solved.
MySQL
Next, I need to store my students’ votes. Relational database should be sufficient. MySQL seems a reasonable choice for me. I got some help from this post.
var mysql = require('mysql'); ... var pool = mysql.createPool({ connectionLimit : 100, //important host : 'localhost', user : 'root', password : '12345678', database : 'votes', debug : false }); function handle_database(req,res) { pool.getConnection(function(err,connection){ if (err) { res.json({"code" : 100, "status" : "Error in connection database"}); return; } console.log('connected as id ' + connection.threadId); connection.query("select * from votes",function(err,rows){ connection.release(); if(!err) { res.json(rows); } }); connection.on('error', function(err) { res.json({"code" : 100, "status" : "Error in connection database"}); return; }); }); }
The above code looks a bit messy. But there is only just one statement pool.getConnection inside handle_database. And the connection.query function is simple enough to grasp. The rest is sort of boiling plate code.
Vote again?
The rest of my journey was mostly spent on how to check if my student has already cast his votes. I want to let them know they have already voted and ask if they want to overwrite their previous votes. I initialized their votes as null and so it is not difficult to make an SQL call to see if he or she has voted before. My biggest problem tho was how to alert them for the change. I initially would like to use the confirm box. Then I realized that I can’t do that because I am programming at the server side. Since I don’t know much web programming at all, the simplest thing I can think of is simply to create another page with a form to ask for confirmation.
Something as simple as the following should suits the purpose.
<html> <body> <H2>Are you sure to overwrite your votes?</H2> <form action="" method="post" enctype="multipart/form-data"> <fieldset> <input type="submit" name="action" value="Update" /> <input type="submit" name="action" value="Cancel" /> </fieldset> </form> </body> </html>
Passing previous form parameters
My bigger problem though is the parameters from previous form is now lost. And if my student clicks confirmed, I don’t know what votes I should update to. After several hours of struggling, I settled with an imperfect workaround.Ignoring security issues, I will just pass the votes that my student just cast as get parameters.And when he confirms, I will just read the parameters again from post. Okay. It probably is a bad solution but it kind of works for my simple toy application.
// sending vote information back to browser res.redirect('/confirm?name='+fields['name']+'&presenter1='+presenter1+ '&score1='+fields[presenter1]+'&presenter2='+presenter2+ '&score2='+fields[presenter2]); ... // read parameters from browser again var name = req.param('name'); var presenter1 = req.param('presenter1'); var presenter2 = req.param('presenter2'); var score1 = req.param('score1'); var score2 = req.param('score2');
Debugging
It was reasonably smooth. But since I didn’t read any documentation and just compiling stuff from what I guessed it meant, I did came across quite a bit trouble with res.send, res.end, res.write, and res.writehead. Basically, I just used them without knowing that I should follow some particular ordering rule. If you have similar troubles, just use res.write all the time and finish it with res.end. res.send is essentially the same as the combination of above and thus cannot be called more than once.
Putting things together
Setting up MySQL
I am using ubuntu and setting up mysql is very easy. Just run
sudo apt-get install mysql-server
and you will be asked for root password. I just used 12345678 for this example.
Preparing MySQL database and table
I will need to first make up a database containing a table to store my students’ votes. To make it simple, I use one column for each student voter and one row for each speaker. And I pre-constructed the entire table with the score first set to null. In command line, run
mysql -u root -p
and input 12345678 for password. Then use the following to create the database and table.
create database votes; use votes; CREATE TABLE votes ( id INT unsigned NOT NULL AUTO_INCREMENT, # Unique ID for the record speaker VARCHAR(150) NOT NULL, # Name of the speaker aakash float, # votes by aakash ahmad_a float, # votes by ahmad ahmad_m float, # ... dong float, muhanad float, naim float, obada float, siraj float, soubhi float, tamer float, varun float, PRIMARY KEY (id) # Make the id the primary key ); insert into votes (speaker) values ('aakash'),('ahmad_a'),('ahmad_m'),('dong'),('muhanad'),('naim'),('obada'),('siraj'),('soubhi'),('tamer'),('varun');
Setting up and start node.js
It is very easy to setup nodes.js in ubuntu. I can just install with apt-get install directly
sudo apt-get install nodejs sudo apt-get install npm
I can then update it with
sudo npm cache clean -f sudo npm install -g n sudo n stable
I should then setup and install required packages
npm init npm install express --save npm install formidable --save npm install mysql --save
Once you put all required files to the current folder. The server can be started with
node test2.js
and it will be listening at port 3000. Try it on your browser with http://localhost:3000.
Final words
It is my first node.js project and I am not a web developer by trade. I do host my own simple website but have skipped the entire web 2.0 thing. Overall I am quite impressed with node.js. It looks like that with some imagination, one can build lots of thing easily even for amateurs like me.