Interactive Quiz Game Using Vanilla JavaScript

I'm in the process of creating a drag-and-drop quiz using only HTML, CSS, and vanilla JavaScript. The concept involves having a div for answers and another for questions. The questions contain blank divs where draggable answers can be dropped.

For instance, if the answers are "a, b, c" and "x, y, z," and the question is "The 1st three letters of the alphabet are: ___"

I need assistance with two main tasks:

  1. I would like each blank div in the question to allow only one dropped element at a time (currently they can stack).
  2. After dropping an answer, I want to check if the answers in the current question divs are correct.

How can I achieve this?

P.S. I am new to HTML/CSS/JS, so please let me know if implementing this without external libraries and PHP is not possible.

/* Events fired on the drag target */

document.addEventListener("dragstart", function(event) {
 // The dataTransfer.setData() method sets the data type and the value of the dragged data
  event.dataTransfer.setData("Text", event.target.id);
  
  // Output some text when starting to drag the p element
 document.getElementById("demo").innerHTML = "Started to drag the p element.";
  
  // Change the opacity of the draggable element
  event.target.style.opacity = "0.4";
});

// While dragging the p element, change the color of the output text
document.addEventListener("drag", function(event) {
  document.getElementById("demo").style.color = "red";
});

// Output some text when finished dragging the p element and reset the opacity
document.addEventListener("dragend", function(event) {
 document.getElementById("demo").innerHTML = "Finished dragging the p element.";
  event.target.style.opacity = "1";
});

/* Events fired on the drop target */

// When the draggable p element enters the droptarget, change the DIVS's border style
document.addEventListener("dragenter", function(event) {
if ( event.target.className == "droptarget" ) {
 event.target.style.border = "3px dotted red";
 }
});

// By default, data/elements cannot be dropped in other elements. To allow a drop, we must prevent the default handling of the element
document.addEventListener("dragover", function(event) {
  event.preventDefault();
});

// When the draggable p element leaves the droptarget, reset the DIVS's border style
document.addEventListener("dragleave", function(event) {
  if ( event.target.className == "droptarget" ) {
    event.target.style.border = "";
  }
});

/* On drop - Prevent the browser default handling of the data (default is open as link on drop)
   Reset the color of the output text and DIV's border color
   Get the dragged data with the dataTransfer.getData() method
   The dragged data is the id of the dragged element ("drag1")
   Append the dragged element into the drop element
*/
document.addEventListener("drop", function(event) {
 event.preventDefault();
 if ( event.target.className == "droptarget" ) {
  document.getElementById("demo").style.color = "";
  event.target.style.border = "hidden";
  var data = event.dataTransfer.getData("Text");
  event.target.appendChild(document.getElementById(data));
  }
});
.droptarget {
    display: inline-block;
    min-width: 50px;
    height: 25px;
    border: 1px solid #aaaaaa;
    color: #000;
    text-align: center;
}
.container {
    display: inline-block;
    padding: 15px;
    margin: 10px;
    background: #eee;
    border: 2px solid black;
    border-radius: 5px;
    box-sizing:border-box;
}
.dragtarget {
    background-color: red;
    padding: 5px;
    border-radius: 5px;
    color: #fff;
    font-weight: bold;
    text-align: center;
}
domande {
    display: inline-block;
    padding: 15px;
    margin: 10px;
    background: #eee;
    border: 2px solid black;
    border-radius: 5px;
    box-sizing:border-box;
}
<p>Drag the answer into the right square</p>

<div class="container">
    <p draggable="true" class="dragtarget" id="dragtarget">A,B,C</p>
    <p draggable="true" class="dragtarget" id="dragtarget">1,2,3</p>
</div>

<div class="domande">
    <h3>First three letters of the alphabet<div class="droptarget"></div></h3>
    <h3>First three numbers<div class="droptarget"></div></h3>
</div>
<p id="demo"></p>

Answer №1

Reusing the same id can lead to issues, as it will only target the first element found with getElementById. Instead, a better approach would be to handle dragging events using dragstart and then utilize drop later on. When dropping, you should check if there are any child elements inside it and append them back to .container if needed.

You mentioned checking details but didn't provide specifics, making it difficult to offer assistance beyond understanding the question and providing an answer.

var dragP;
/* Events fired on the drag target */

document.addEventListener("dragstart", function (event) {
    // The dataTransfer.setData() method sets the data type and the value of the dragged data
    // event.dataTransfer.setData("Text", event.target.id);
    dragP = event.target;

    // Output some text when starting to drag the p element
    document.getElementById("demo").innerHTML = "Started to drag the p element.";

    // Change the opacity of the draggable element
    event.target.style.opacity = "0.4";
});

// While dragging the p element, change the color of the output text
document.addEventListener("drag", function (event) {
    document.getElementById("demo").style.color = "red";
});

// Output some text when finished dragging the p element and reset the opacity
document.addEventListener("dragend", function (event) {
    document.getElementById("demo").innerHTML = "Finished dragging the p element.";
    event.target.style.opacity = "1";
});

/* Events fired on the drop target */

// When the draggable p element enters the droptarget, change the DIVS's border style
document.addEventListener("dragenter", function (event) {
    if (event.target.className == "droptarget") {
        event.target.style.border = "3px dotted red";
    }
});

// By default, data/elements cannot be dropped in other elements. To allow a drop, we must prevent the default handling of the element
document.addEventListener("dragover", function (event) {
    event.preventDefault();
});

// When the draggable p element leaves the droptarget, reset the DIVS's border style
document.addEventListener("dragleave", function (event) {
    if (event.target.className == "droptarget") {
        event.target.style.border = "";
    }
});

/* On drop - Prevent the browser default handling of the data (default is open as link on drop)
   Reset the color of the output text and DIV's border-color
   Get the dragged data with the dataTransfer.getData() method
   The dragged data is the id of the dragged element ("drag1")
   Append the dragged element into the drop element
*/
document.addEventListener("drop", function (event) {
    event.preventDefault();
    let targetDiv = event.target;
    if (targetDiv.className == "droptarget") {
        document.getElementById("demo").style.color = "";
        targetDiv.style.border = "hidden";
        if (targetDiv.childElementCount != 0){
            let childP = targetDiv.getElementsByTagName("p")[0];
            document.getElementById("answer").appendChild(childP);
        }
        targetDiv.appendChild(dragP);
        dragP = null;
    }
});

document.getElementById("checkAnswer").addEventListener("click", function () {
    let questions = document.getElementsByClassName("question");
    let resultP = document.getElementById("result");
    resultP.innerHTML = "";
    for (let index = 0; index < questions.length; index++) {
        const element = questions[index];
        let childP = element.getElementsByTagName("p")[0];
        let question = element.childNodes[0].textContent;
        let answer = childP != undefined ? childP.innerText : "no answer";
        resultP.append(`${question} : ${answer} ; `);
    }
})
.droptarget {
    display: inline-block;
    min-width: 50px;
    height: 25px;
    border: 1px solid #aaaaaa;
    color: #000;
    text-align: center;
}

.container {
    display: inline-block;
    padding: 15px;
    margin: 10px;
    background: #eee;
    border: 2px solid black;
    border-radius: 5px;
    box-sizing: border-box;
}

.dragtarget {
    background-color: red;
    padding: 5px;
    border-radius: 5px;
    color: #fff;
    font-weight: bold;
    text-align: center;
}

.domande {
    display: inline-block;
    padding: 15px;
    margin: 10px;
    background: #eee;
    border: 2px solid black;
    border-radius: 5px;
    box-sizing: border-box;
}
<p>Drag the answer into the correct square</p>

<div class="container" id="answer">
    <p draggable="true" class="dragtarget" id="dragtarget">A,B,C</p>
    <p draggable="true" class="dragtarget" id="dragtarget">1,2,3</p>
</div>

<div class="domande">
    <h3 class="question">First three letters of the alphabet<div class="droptarget"></div>
    </h3>
    <h3 class="question">First three numbers<div class="droptarget"></div>
    </h3>
</div>
<p id="demo"></p>
<button id="checkAnswer">Check</button>
<p id="result"></p>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can a link be created that consistently opens a new tab in "regular browsing mode," regardless of whether it is clicked from incognito mode or not?

Can a webpage link be designed to consistently open in regular mode, regardless if the user is in incognito browsing? ...

What are the steps to create a project template in WebStorm by saving an existing project?

Currently, I am working on my Express.js project in WebStorm 8 and I would like to save it as a project template. Can you please guide me on how to do this using WebStorm? ...

Utilizing Google Language API for bulk translation tasks

My current project involves using Google's AJAX Language API to translate each element in an array. for(var i=0; i < mytext.length; i++) { google.language.translate(mytext[i], originalLanguage, newLanguage, function(result){ if(!result.error){ ...

Selenium not registering click on enabled element

I am trying to trigger a click event on an element on the page, but for some reason the Selenium click function is not working as expected. Here is the relevant code snippet: username_form = driver.find_element_by_id('form3-username') passwor ...

Surprising occurrence of page scrolling upward upon clicking a link

I crafted a web page in HTML specifically designed for viewing on an iPad. The layout features an FAQ list with a hover effect applied to each question. In order to trigger the hover effect on the iPad, I had to include a dummy link similar to this: <a ...

Using jQuery to dynamically assign default selection in HTML

Currently, I have a line of code that dynamically sets the default selection of a selection box in html using jQuery. var y=...a value from the DB; this.$(".status option[value=y]").attr("selected", "selected"); The issue is that it only works if I ...

Utilizing a mouse-over script for image popup alignment

I recently came across the mouse over script below on a website, and I must say it works really well and is very easy to use. The only issue I have with it is the placement of the image. Currently, the image follows the cursor as it moves. Question: Is th ...

Testing of onClick event in a React component using styled-components with Sinon spies

Utilizing sinon to test a react component and verify that an onClick function is triggered. Struggling to target the element to click on due to the use of styled-components. Encountering this error message: The "simulate" method should only be run on ...

What is the best way to align a button within a Jumbotron?

Struggling to find the right CSS placement for a button within a jumbotron. I attempted using classes like text-left or pull-left, but nothing seemed to work as I hoped. I believe a simple CSS solution exists, but it's eluding me at the moment. Ideall ...

Erase text from an ASP TextBox within a user control by utilizing jQuery on the main page

I am facing a challenge with an ASP .NET webpage that contains dynamically generated user controls (multiple instances of a single control) within multiple repeaters. Each user control has a text box, and I want to clear its content using an HTML button lo ...

What steps can I take to create a fixed footer using CSS Flexbox?

"How can I make the footer stay at the bottom of the page" I've encountered challenges with footers in the past and have struggled to achieve the desired outcome. Is there a straightforward method to create a fixed footer using CSS Flexbox ...

Can Vue allow for the inclusion of HTML elements to store data seamlessly?

One example involves displaying array elements in an <ul>, with each element starting with <li> and ending with </li>. Here is the attempted code: clearedtaskslist: function(){ this.template='<ul>' for(let i=0;i<t ...

Customize your Jquery UI Calendar with Changing Background Images for Each Month!

How can I change the background of jQuery UI datepicker based on the selected month? I have created 12 classes, each representing a month, and the selected month already has the background. I tried using "onChangeMonthYear: function(year, month, inst) { ...

Troubleshooting Parallax Logic in NextJS

import Head from 'next/head' import styles from '../styles/Home.module.css' import Image from 'next/image' import React, { useRef ,useEffect, useState } from 'react'; export default function Home() { let ref = use ...

The significance of Buffer in node.js

I see the importance of using Buffer, but I'm a bit unclear on how to properly use buffer syntax. In the example provided below, const parsedBody = Buffer.concat(body).toString(); const message = parsedBody.split('=')[1]; ...

Div sections with a parallax slant

Could you guide me on creating multiple homepage sections with parallax background images and a slanted edge? This is the design I'm aiming for: For reference, I am working on this within Wordpress using the Avada theme as my foundation. ...

Adjust the template within a directive to dynamically include an additional directive

Challenge Create a custom directive that dynamically adds the ng-bind attribute, allowing for the use of ng-bind, ng-bind-html, or ng-bind-html-unsafe without needing to manually add it to the template definition throughout. Illustrative Example http://j ...

Adjust the size of the text only when there is limited space available

Is there a way to make text shrink to fit inside a container only if it's too long, but remain the same size otherwise? I'm working on a chart with keyboard commands overlaid on an image of a keyboard and want the text to adjust dynamically. Any ...

Endlessly triggering document.execCommand, the JavaScript selectionchange-EventListener seems to have a mind of

I recently implemented an event listener for selectionchange in the following manner: document.addEventListener("selectionchange", function() { highlight(); console.log("selectionchange-triggered"); }, false); After that, I included the code bel ...

The dynamic ID stops functioning once a row is deleted from the table

I have a table with feeSetting id containing dynamic data. I am able to add and remove rows from the table. The issue arises when a row is removed and a new row is added, as it overrides the unique ID of the last row. I need the table to generate unique ...