Web-interface for Delphi method

I recently worked on a fun project at work. I developed a web-interface for administering a questionnaire using the Delphi method. The Delphi method aims to bring consensus on a given topic using a concept similar to ‘the wisdom of crowds‘.

In essence, with the Delphi method a panel of experts express their opinion on a subject multiple times (i.e. rounds). In our specific case the topic was functional magnetic resonance imaging in patients with tinnitus. During the first round each expert expresses his/her opinion and in the following rounds the experts receive feedback from the whole panel of experts before expressing their opinion again. Basically the idea is that through multiple rounds/exposures only the really relevant items survive, because those are the items receiving everyone consensus.

The final version of the web-interface for the first round of the Delphi study is visible at this page. Since my co-workers were very pleased with the result, I thought of sharing and describing the code I wrote to implement it. Maybe someone else finds it useful and can use it. In this post I will focus on round one only. The code is written principally in PHP, but there is also some MySQL and a tiny bit of HTML, CSS and Javascript.

The first step in the creation of the Delphi method’s webpage was displaying the questions themselves. I stored the text of all forty questions into an array.

$questions = array(
	"Method of participant recruitment", 
	"Informed consent statement", ...)

The questions were grouped in subsets and a title header identified each subset. I grouped the subsets’ titles in the array $headers. Since I planned to create only one loop going through the $questions array I created another array $itemsPerHeader. $itemsPerHeader contains integers specifying when to change from one header title to another depending on the current question number.

$headers = array("Participants Characteristics - Demographics",
	"Participants Characteristics - General health",...)
$iheader = 0;
$itemsPerHeader = array(0, 7, 12, 19, 30, 34, 37, 40);

To define the look of the questionnaire display I used a table. A table allows fine control on the specification of the display’s look, as for example the width of the question’s text display and the corresponding 10 radio buttons (with values ranging from 1 to 9 for ‘Not important’ to ‘Critical’ and 10 for ‘Unable to score’). Surrounding the arrays’ text with the proper HTML tags and CSS style directives, and wrapping everything into a loop creates the page and keeps the PHP script neat.

$nQuestions = count($questions);
for ($iQuest = 0; $iQuest < $nQuestions; $iQuest++) {
	if ($iQuest == $itemPerHeader[$iheader]){
		echo "<h3>$headers[$iheader]</h3><table>";
		include("tableHeader.php");
		echo "<tbody>";
		$iheader++;
	}
	echo "<tr> <td class='firstRow'> $questions[$iQuest] </td>";
	for ($item = 1; $item <= 9; $item++) {
		echo "<td> <center> <input type='radio' name='q" 
                     . ($iQuest+1) ."'"; 
		if (isset($q[$iQuest]) && $q[$iQuest]==$item){ 
                     echo "checked='' "}; 
		echo "value='" . $item . "'> </center> </td>";
	}
	echo "<td class='unscored'> <center> 
              <input type='radio' name='q" . ($iQuest+1) ."' ";
	if (isset($q[$iQuest]) && $q[$iQuest]=="10") {
              echo "checked='' "}; 
	echo " value='10'> </center> </td>";
	echo "<td class='asterisk'><center><span class='error'>"  
              . $qErr[$iQuest] . "</span></center></td></tr>";
	// close table for last item
	if ($iQuest == ($itemPerHeader[$iheader] - 1)){
		echo "</tbody> </table>";
	}
}

In the code above include("tableHeader.php"); groups the HTML code to create the table’s head, which is styled with the CSS directives stored in the file styleTable.css. Both files are very simple files, therefore I will not discuss them. Both files are available in the project’s github repository and can be browsed there.

Now is validation time! Validation concerns at least two aspects of the questionnaire. One aspect is that participants must respond to all items which require a response. Another aspect is determining whether each field with a response has a valid input (e.g. text into text, e-mail into e-mail, numbers into numbers etc.). The implementation of the validation of the questionnaire requires more coding than the display of the questionnaire because the validity and completeness of each item must be checked. Determining if all required fields have been completed requires four steps. First is the definition of an empty variable which is going to be filled with the user’s response. Saving the input of the participant also prevents the loss of input on form submission if the form is submitted incomplete or with wrong values because the input can be checked before submitting the response to the server! Second is the definition of an error message if the users enters the wrong value (e.g. writing a text instead of the e-mail address in the e-mail input field). Third is the definition of a boolean variable specifying whether the item was responded to. Fourth is determining the action following entry of the input (e.g. sending the values to the database or tell the user values are missing/incorrect). For the sake of simplicity I provided a very stripped down example of validation which shows these four steps for one text input field:

// initialize variable for empty responses
$surname = "";
// set variables for 'required' option, 
// will be 'filled' if value == empty
$surnameErr = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
  $surnameIsGiven = FALSE;
  if (empty($_POST['surname'])) { $surnameErr="*"; } 
  else { 
       $surname=test_input($_POST["surname"]); 
       $surnameIsGiven=TRUE;}
  if( $surnameIsGiven){
       // .. send surname to server
  }     
}

Determining whether the input is valid can be quite a laborious task. I kept it simple using a very simple function which is checking that the text is actual text and not an injection.

function test_input($data) {
   $data = trim($data);
   $data = stripslashes($data);
   $data = htmlspecialchars($data);
   return $data;
}

Note that the HTML form must include a small PHP script displaying the feedback to the user when an input is invalid. If the response in the input field was not completed the variable $surnameErr will be set with an ‘*’, identifying a required field. We need to include a printout of this error message in the HTML page. For example,

<form method="post" action="
   <?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>
">
<p>
<input type="text" name="surname" value="<?php echo $surname;?>">
<span class="error"><?php echo $surnameErr;?></span>
Surname
</p>
<p><input type='submit' name='submit' value='Submit'></p>
</form>

An alternative way to do form validation is using the ‘required’ html attribute and then validating the input using javascipt. The ‘required‘ html attribute implies that the form cannot submitted if the field does not have an input value. However since required is html5 specific I thought it was better to perform the form validation with php. This solution might require a bit more coding, but it should work in (I hope) any browser.

At the bottom of the page, before the submit button, there is the comments section. Comments are for experts to leave feedback about the questionnaire and add items if they think some are missing or ask for clarification if items are unclear. We decided to store the comments into a database instead of pasting them into automatically generated e-mails. To not initialize too much empty space in the database I limited the comments’ fields to 2000 characters. To help the commentator know how many characters were left I added a short javascript function counting how many characters are still available.

function textCounter(field,field2,maxlimit){
    var countfield = document.getElementById(field2);
    if ( field.value.length > maxlimit ) {
         field.value = field.value.substring( 0, maxlimit );
         return false;
    } else {
         countfield.value = maxlimit - field.value.length;
    }}

This counter is placed on top of the text input area in which one can write the comments.

<p>
Characters available: <input disabled  maxlength="3" size="3" 
    value="1000" id="counterQ"><br>
<textarea name="commentQuestionnaire" rows="10" cols="50" 
    onkeyup="textCounter(this,'counterQ',1000);" id="messageQ">
    <?php echo $commentQuestionnaire;?>
</textarea>
</p>

Moreover, because SQL does not accept apostrophes, I included a line to the php code sanitizing the comments’ text so that comments with apostrophes could also be posted.

$mergedComment = mysqli_real_escape_string($conn, $mergedComment);

That is it. All the code is available on github including an sql file with the commands to create the tables. The code on the github repository is more complete than the extract I posted here. Some bits in the final page I did not address as, for example, the creation of an unique ID to identify the participants in the second round. In any case, I tried to make the code as general as possible so that it could be used simply by replacing the questions and section headers’ titles. Any other modification should be straightforward.

Said that, building round II was much more exciting than round one, because I built visual displays of the votes of each single item. You can check how I did in a few days.

Advertisements
Web-interface for Delphi method

One thought on “Web-interface for Delphi method

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s