0

I am building a quiz and what i am doing now is working on taking the user's input and checking the user's submission with an answers table in my database and return the user the score.

My quiz is in the form of multiple choice for users to select, and each option carries its own value. What i have done to capture the data is to serialize the form data and store all of the form's data in a object. The object looks something like this:

{ question1: '1', question2: '2', question3: '3', question4: '4', question5: '5' }

So it sorts of stores the question and user answer as a key value pair, with the question number coming first, and the user selected option coming next. As you can see from the code below, i am using an .each to take out the key value pairs, and what im thinking of doing is everytime the .each runs, to run an ajax command to an external checkanswer.php script to verify the user's chosen option. Everytime the server returns a match, the php returns a text string "correct" to the ajax, which then increments 1 to a created count variable. I have also appended the php script below. With @barmar's advice, i have removed json entirely, but the count variable under .each stil isnt giving the correct number based on the number of correct answers returned from the ajax call. ++ Upon reading up more about the way ajax works, it seems like ajax does not wait for the submit handler and therefore i must change the code. One way is to actually send the entire string across and for php to loop through the key value pairs and do the counting there and return the value to ajax. What do you all think?

                 <script>
            $('#quizform').submit(function() {
            var data = $(this).serializeArray();
            count = 0;
            $.each(data, function(i, el) {
                //display the key and value pair
                var k = el.name;
                 var v = el.value;

                 var request = $.ajax({
                        url: "checkanswer.php",
                        type: "POST",
                        data:{ k:k, v:v},
                        dataType:"text",


                   success: function(data) { 
                   if (data=="correct") {
                    count++;


                   } 
                   },
                   error: function(request, err){ 


                  alert(err);



                   }
                 });


});
            alert(count);
             return false;
});



            </script>

The PHP script:

    <?php
session_start();
include_once("config.php");
if (isset($_POST['k']) && isset($_POST['v'])){

    $questionid=$_POST['k'];
    $option=$_POST['v'];

    $result=mysqli_query($mysqli, "SELECT COUNT(*) FROM answer WHERE question_id = ".$questionid." AND optionid = ".$option."");

    if($result==0) {
        echo"wrong";

    }else if ($result == 1) {

        echo"correct";

    }



}

?>

I have edited the code above

hacker
  • 37
  • 8
  • You need to set your HTTP "Content-Type" header. I would suggest using Chrome debugger and going to the network panel and using the "preserve log" checkbox to see what is being returned by your server. Needs to be a JSON response. – unobf Dec 29 '14 at 13:12
  • yeah, i think it is something with the header, currently whenever i submit the form, it redirects me to another php header found in my page, which is very weird to me – hacker Dec 29 '14 at 13:13
  • Look at what is in your config.php file, that may be including the header and causing the problem – unobf Dec 29 '14 at 13:14

3 Answers3

0

json is a string. The argument to $.each() must be an array or object. There's no need for you to create a JSON string, you should just loop over obj directly:

$.each(obj, function(k, v) {
    ...
});

Actually, there's no reason to create obj, either, just loop over data:

$.each(data, function(i, el)
    var k = el.name;
    var v = el.value;
    ...
});

Finally, this will not be JSON. $.ajax uses x-www-form-urlencoded format, which PHP decodes automatically. So you should not use json_decode() in the PHP.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • hi there, this clarifies alot about JSON, but the count still always returns me 0, even if i have a correct answer, since you mentioned that theres no need for me to use JSON, that means i must remove json_decode from the PHP file, and also change datatype in ajax call to text? – hacker Dec 29 '14 at 13:24
  • yup, i have removed all json_decode, and changed datatype to text, however, i think the loop is still not working, as its not looping all of the question (lets say i have 5 question), it isnt looping through each one and firing the ajax request for every question to increment count whenever a correct answer is there. – hacker Dec 29 '14 at 13:29
  • The first A in AJAX stands for Asynchronous. All the AJAX requests are firing simultaneously, and then the `submit` handler returns, it doesn't wait for the responses. See http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call – Barmar Dec 29 '14 at 13:31
  • Instead of firing a separate AJAX request for each question, send all of them in a single request. Then the `success` function can process all the results and display what you want. – Barmar Dec 29 '14 at 13:32
  • i guess that means sending all the key value pairs in one string, for example, q1:1, q2:2, q3:3, and then in my php code do a for loop to check one by one and do the count in the php script? – hacker Dec 29 '14 at 13:34
0

You seem to have an issue with the asynchronous behaviour of javascripts. You cannot guess when the increment of count finishes in your code as ajax calls are asynchronous.

Instead use jQuery.when() to determine when all the ajax calls finishes and use the count variable when done..

var count = 0;
var ajaxCalls = [];
$.each(data, function(i, el) {
    //display the key and value pair
    var k = el.name;
    var v = el.value;

    ajaxCalls.push($.ajax({
                    url: "checkanswer.php",
                    type: "POST",
                    data:{ k:k, v:v},
                    dataType:"text",
                    success: function(data) { 
                      if (data=="correct") {
                        count++;
                      } 
                    },
                    error: function(request, err){ 
                            alert(err);
                    }
                  }));
});

$.when.apply(null, ajaxCalls ).done(function () { alert(count);});
Sampath Liyanage
  • 4,776
  • 2
  • 28
  • 40
0

In my opinion your code is not well formatted, you should show the your full code with your HTML too, also I don't know why you are making an array of question id, if they can be sent to server without looping them with dimensional array of elements.

And use IN operator in mysql as you are using json_decode() which returns array or object, so try your query like,

$result=mysqli_query($mysqli, "SELECT COUNT(*) FROM answer WHERE question_id IN (".$questionid.") AND optionid IN (".$option.")");

For example, you have questionid as array of html elements then just pass it in ajax like,

$('#form').on('submit',function(e){
    e.preventDefault();
    var data=$(this).serialize();
    $.ajax({...});/// using post method
    return false;
});

And in php-mysql query use it like,

$sqlQuery = "SELECT COUNT(*) FROM answer WHERE question_id IN (".implode(',',$_POST['questionid'].") ";
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
  • Hi there, i think i cannot use jsondecode, as it returns me a parseerror from the ajax call – hacker Dec 29 '14 at 13:20
  • hmm, do you think i could run a for loop and then when COUNT returns a 1, then count++ or would implode be the best solution here, since my string will contain multiple key value pairs – hacker Dec 29 '14 at 13:39
  • For this take a look at http://stackoverflow.com/questions/18723357/get-array-element-and-use-it-in-mysql-query-with-php – Rohan Kumar Dec 29 '14 at 13:41
  • hmm, thanks for the link, but im not very sure how to foreach a string that is in this format {q1:1, q2:2, q3:2, q4:3} – hacker Dec 29 '14 at 13:42