JF Koh

2 June 2022

Javascript coding for online personality test

In May 2022, I coded an online personality test for a client. In this article, I share some technical details of how I did it.

Scope of project:

This is a relatively simple project which does not involve any form submission to be saved in a database or emailed to anyone. The purpose is for the user's own self-assessment and insight. The user simply clicks on some multiple choice options, and the web page performs some simple calculations and reveals a score of the user's personality.

I opted to code it in pure javascript.

Privacy issues:

Since no data is being submitted to the server, and all the interaction is happening only in the user's local browser, there are no troublesome privacy issues to worry about.

The actual content of the personality test is proprietary, so I cannot share that here. I replace the actual questions with dummy questions and dummy personality types of my own. Instead of the full set of questions, I include only 2 questions to demo how it works.

This is what the personality test looks like. Feel free to click on the answers to see what it does. You can pick 2 answers per question, a 1st choice and a 2nd choice. The 1st choice will score 2 points, and the 2nd choice scores 1 point.

1) You are on your way to work. You see a small dog limping across your path in front of you. What do you do? 1st choice 2nd choice
a. Call your office to say that you will be late for work, because you need to bring the dog to see a vet.
b. Ignore the dog and walk past it.
c. Yell at the dog and tell it not to block your way.
2) You are coming home after work. You see a kitten mewing in front of your door. What do you do? 1st choice 2nd choice
a. Offer it some food.
b. Ignore the kitten and walk past it.
c. Yell at the kitten and tell it not to block your way.

Your personlity score

Animal lover
Animal neutral
Animal hater

Here's the HTML source code. The important parts are the name, value and id of each input element, and the id of the square boxes that display the scores.

<table class="question">
    <tr>
        <td>1) You are on your way to work. You see a small dog
        limping across your path in front of you. What do you
        do?</td>
        <td>1st choice</td>
        <td>2nd choice</td>
    </tr>
    <tr>
        <td>a. Call your office to say that you will be late
        for work, because you need to bring the dog to see a
        vet.</td>
        <td>
            <input type="radio" name="q1_1" value="al" id="q1a1">
        </td>
        <td>
            <input type="radio" name="q1_2" value="al" id="q1a2">
        </td>
    </tr>
    <tr>
        <td>b. Ignore the dog and walk past it.</td>
        <td>
            <input type="radio" name="q1_1" value="an" id="q1b1">
        </td>
        <td>
            <input type="radio" name="q1_2" value="an" id="q1b2">
        </td>
    </tr>
    <tr>
        <td>c. Yell at the dog and tell it not to block your
        way.</td>
        <td>
            <input type="radio" name="q1_1" value="ah" id="q1c1">
        </td>
        <td>
            <input type="radio" name="q1_2" value="ah" id="q1c2">
        </td>
    </tr>
</table>

<table class="question">
    <tr>
        <td>2) You are coming home after work. You see a kitten
        mewing in front of your door. What do you do?</td>
        <td>1st choice</td>
        <td>2nd choice</td>
    </tr>
    <tr>
        <td>a. Offer it some food.</td>
        <td>
            <input type="radio" name="q2_1" value="al" id="q2a1">
        </td>
        <td>
            <input type="radio" name="q2_2" value="al" id="q2a2">
        </td>
    </tr>
    <tr>
        <td>b. Ignore the kitten and walk past it.</td>
        <td>
            <input type="radio" name="q2_1" value="an" id="q2b1">
        </td>
        <td>
            <input type="radio" name="q2_2" value="an" id="q2b2">
        </td>
    </tr>
    <tr>
        <td>c. Yell at the kitten and tell it not to block your
        way.</td>
        <td>
            <input type="radio" name="q2_1" value="ah" id="q2c1">
        </td>
        <td>
            <input type="radio" name="q2_2" value="ah" id="q2c2">
        </td>
    </tr>
</table>

<div style="text-align: center; margin: 40px;">
    <p><b>Your personlity score</b></p>

    Animal lover
    <div class="score" id="score-al"></div>

    Animal neutral
    <div class="score" id="score-an"></div>

    Animal hater
    <div class="score" id="score-ah"></div>

</div>
        

Here is the full text of the javascript, with comments to explain how it works.


<script>

// Add an event listener to body to detect any change events
// (i.e. a radio button being clicked), and attach the tallyAll
// function to it. So every time the user clicks on a radio
// button, the tallyAll function will be called.
document.body.addEventListener('change', tallyAll)

function tallyAll() {

    // Initialize some variables.
    // Arrays to collect all Choice 1 and 2 answers (without
    // knowing which answer is from which question):
    const choice1 = [];
    const choice2 = [];

    // Objects to store the Choice 1 and Choice 2 types:
    // al == animal lover
    // an == animal neutral
    // ah == animal hater
    const choice1counts = {
        al: 0,
        an: 0,
        ah: 0,
    }
    const choice2counts = {
        al: 0,
        an: 0,
        ah: 0,
    }
    // And the tallied scores:
    const totalScores = {
        al: 0,
        an: 0,
        ah: 0,
    }

    // Create an array to loop through all the questions.
    // The array makes the script more scalable, so that you just
    // need to change this number if you add more questions.
    let questions = [];
    for (let i = 1; i <= 2; i++) {
        questions.push(i);
    }

    // Iterate through Choice 1 of all questions and collect all
    // the answers:
    for (const question of questions) {
        // Select all Choice 1 radio groups:
        let radiogroup = document.querySelectorAll('input[name="q' +
            question + '_1"]');
        // Iterate through each radio button in the group:
        for (const radio of radiogroup) {
            if (radio.checked) {
                choice1.push(radio.value);
                break;
            }
        }
    }
    // Now do the same for Choice 2:
    for (const question of questions) {
        // Select all 17 Choice 2 radio groups:
        let radiogroup = document.querySelectorAll('input[name="q' +
            question + '_2"]');
        // Iterate through each radio button in the group:
        for (const radio of radiogroup) {
            if (radio.checked) {
                choice2.push(radio.value);
                break;
            }
        }
    }

    // Now we will tally up the score of each type, and put them
    // all in the chart.

    // Pop out all our Choice 1 and 2 selected types and add up
    // the count of each distinct type:
    while (choice1.length != 0) {
        let popped = choice1.pop();
        choice1counts[popped] = choice1counts[popped] + 1;
    }
    while (choice2.length != 0) {
        let popped = choice2.pop();
        choice2counts[popped] = choice2counts[popped] + 1;
    }

    // Calculate all the scores by iterating through the types:
    for (let type in totalScores) {
        // Tally the score for this type.
        // Choice 1 gets 2 points, and Choice 2 gets 1 point.
        totalScores[type] = choice1counts[type]*2 + choice2counts[type];

        // Put each score into the chart:
        // Template:
        // let score_node = document.querySelector('#score-aa');
        score_node = document.querySelector('#score-' + type);
        score_node.textContent = totalScores[type];
    }
}

</script>