I am making an Exam-Test Module. In which there will be more than one questions. Each questions has multiple choice answers. I am showing one question at a time. There will be a button called 'Next' till the last question appears. If there are no more questions, the button will say Submit Test
. When user clicks on Submit Test
button, all answers of all the questions will be passed to PHP function in the backend to check how many are correct and wrong? I tried doing the following thing but I am getting the array with only one answer and that of first question. How can I achieve this ? I want to store the answers of all the questions in one array and then pass that array to PHP function through AJAX .post
call or jQuery call ?
index.php
<div class="modal fade test-modal" id="Test">
<div class="modal-dialog">
<div class="modal-content">
<? foreach ($questions as $i=>$question) { ?>
<div class='question'>
<div class="modal-header">
<div class="row">
<h4>QUIZ</h4>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="quest">
<ul class="list-unstyled">
<? foreach ($question->getAnsChoice as $answer) { ?>
<li>
<div class="checkbox">
<input class="cb" type="checkbox" name="answer[]" value="<?=$answer->title?>">
<?=$answer->title?>
</div>
</li>
<? } ?>
</ul>
<br>
<br>
<p class='error'>Please select an answer</p>
</div>
</div>
</div>
<div class="modal-footer">
<p class='quest_num'><?=$question->number?> of <?=count($questions)?></p>
<? if( count($questions) === 1 ) { ?>
<a id="submit_quiz" class="btn button btn-lg quiz-btn">Submit Test</a>
<? } else if ( count($questions) === $i +1 ) { ?>
<a id="submit_quiz" class="btn button btn-lg quiz-btn">Submit Test</a>
<? } else { ?>
<a class=" btn button btn-lg quiz-btn">Next Question</a>
<? } ?>
</div>
</div>
<? } ?>
</div>
</div>
</div>
javascript
<script type="text/javascript">
$(document).on('ready', function(){
$('.quiz-btn').click(function(e){
e.preventDefault()
var checkbox = $(this).parents('.question').children('.modal-body').children('.row').children('.quest').children('ul').children('li').children('.checkbox').children('.icheckbox_square');
var btn = $(this).parents('.question').children('.modal-footer').children('.quiz-btn')
var next = false
var submit = false
var answers = [];
$(checkbox).each(function(){
if ( $(this).hasClass('checked') && $(btn).html() == 'Next Question' ) {
answers.push($('.cb:checked').val());
next = true
}
else if ($(this).hasClass('checked') && $(btn).html() == 'Submit Test') {
submit = true
}
});
if ( next ) {
e.preventDefault();
$(this).parents('.question').slideUp(500);
$(this).parents('.question').next('.question').delay(500).slideDown(500);
} else if ( submit ) {
e.preventDefault();
$.post('/student/submit_quiz',{asnwers: answers}, function(data){
});
} else {
console.log(next)
$('.quest .error').fadeIn();
}
});
}
</script>
There are a couple of issues with this code that I've noticed:
$(checkbox).each(function(){
if ( $(this).hasClass('checked') && $(btn).html() == 'Next Question' ) {
answers.push($('.cb:checked').val()); // LOGIC ERROR
next = true
}
else if ($(this).hasClass('checked') && $(btn).html() == 'Submit Test') {
submit = true
}
});
The line of code that I've marked with a comment is querying the entire document for all checkboxes matching '.cb:checked'
with $('.cb:checked')
. Then, JQuery's .val()
function gets the value of just the first element from that collection.
Here is the relevant JQuery API documentation :
Description: Get the current value of the first element in the set of matched elements.
So the JavaScript iterates through every checkbox, then repeatedly adds just the first checkbox in the document's value to the array.
To fix this, get the value from the current this
object:
if ( $(this).hasClass('checked') && $(btn).html() == 'Next Question' ) {
answers.push($(this).val()); // modified line
next = true
}
The second is that the variable answers
exists separately for each button. You have one button for each section and a new, separate function call for each button. You would need to hoist the answers
variable outside of the event function:
$(document).on('ready', function(){
var answers = [];
$('.quiz-btn').click(function(e){
// Bla bla bla
answers.push(the_correct_value);
// Bla bla bla
});
}
If you don't want the answers
variable to be available to everything in the document.ready
event listener, you can use a pattern called an Immediately Invoked Function Expression:
$(document).on('ready', function(){
(function(){ // Notice how this line starts with an open bracket
var answers = [];
$('.quiz-btn').click(function(e){
// Bla bla bla
answers.push(the_correct_value);
// Bla bla bla
});
})(); // This line closes the open bracket above,
// then immediately runs the result with no arguments
// the `answers` variable is unavailable in this scope
}
The JavaScript that you included was also missing a closing bracket at the very end of the script.
All that said, the solution I would use personally would be to wrap the whole thing in a form, use a submit button, listen for the form's submit
event and just create a JavaScript FormData
to send the answers:
<div class="modal fade test-modal" id="Test">
<div class="modal-dialog">
<div class="modal-content">
<form action="/student/submit-quiz" method="POST"><!-- Form tag -->
<?php foreach($questions as $i => $question): ?>
<div class="question">
<div class="modal-header">
<div class="row">
<h4>QUIZ</h4>
</div>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="quest">
<ul class="list-unstyled">
<?php foreach ($question->getAnsChoice as $answer): ?>
<li>
<div class="checkbox">
<input class="cb" type="checkbox" name="answer[]" value="<?= $answer->title ?>" />
<?= $answer->title ?>
</div>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
<div class="modal-footer">
<p class="quest_num"><?= $question->number ?> of <?= count($questions) ?></p>
<?php $last = $question->number === count($questions) - 1; ?>
<!--
Ternary operators, used in these attributes, are like if statements:
if the first thing is true, return the second,
otherwise return the third.
-->
<input type="<?= $last ? 'submit' : 'button' ?>" class="btn button btn-lg quiz-btn" value="<?= $last ? 'Submit Test' : 'Next Question' ?>" />
</div>
<?php endforeach; ?>
</form>
<script>
/*
* Where the real magic happens.
*/
$('form[action="/student/submit-quiz"]').on('submit', function(e) {
e.preventDefault();
data = new FormData(this);
$.ajax({
url: this.action,
data: data,
contentType: false,
processData: false,
type: 'POST',
success: function(response) {
// do something useful with the response
console.log(response);
},
});
});
$('form[action="/student/submit-quiz"] input[type="button"]').on('click', function(e) {
$(this).parents('.question').slideUp(500);
$(this).parents('.question').next('.question').delay(500).slideDown(500);
});
</script>
</div>
</div>
</div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.