webdeveloper123 Posted April 11, 2023 Share Posted April 11, 2023 Hi guys, I am making a Quiz using PDO. I've got my HTML/CSS done and I have a div container where the questions are held and the 4 possible choices. Problem is when I try to show the 4 possible answers on the screen (eg for A,B,C,D) I can only get A to display and then A is the same even for B,C,D. So you basically have a question (which displays fine) but A,B,C,D are all the same choices. Here is my code: $sql = "SELECT questions.question, quiz_options.choice FROM questions JOIN quiz_options ON questions.qid = quiz_options.qid;"; $statement = $pdo->query($sql); $questions = $statement->fetchAll(); <?php foreach ($questions as $question) { ?> <div class="quizContent"> <p><?php echo($question["question"]); ?></p> <div class="answerA"> <p><?php echo($question["choice"]); ?></p> </div> <div class="answerB"> <p><?php echo($question["choice"]); ?></p> </div> <div class="answerC"> <p><?php echo($question["choice"]); ?></p> </div> <div class="answerD"> <p><?php echo($question["choice"]); ?></p> </div> </div> <?php } ?> Now this displays every question in the database 4 times, with each time having the same choice answer. I know it's in a loop and that's why it's showing so many times but I've been at this for hours and Can't seem to figure it out. This is as far as I have got. Many thanks Quote Link to comment Share on other sites More sharing options...
Solution ginerjm Posted April 11, 2023 Solution Share Posted April 11, 2023 (edited) Here is my much-abbreviated copy of your code. Let's see what you get from it without all of the css and the needless fetchall. $sql = "SELECT a.question, b.choice FROM questions a, quiz_options b where a.qid = b.qid"; if (!$results = $pdo->query($sql)) { echo "Could not run query: $sql"; exit(); } $last_q = 'x'; while ($row = $qresults->fetch()) { if ($last_q <> $row['question']) { echo $row['question']; } $last_q = $row['question']; echo $row['choice'] . '<br>'; } I'm trying to give you something that displays the data just to be sure that your query is providing what you think it is. Edited April 11, 2023 by ginerjm Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 11, 2023 Author Share Posted April 11, 2023 Thanks ginerjm, I got your code working and it does the job! Now all I have to do is fit it into my HTML! Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 11, 2023 Share Posted April 11, 2023 (edited) But did you learn why your original code was not doing the job? That's the Important thing. Hope you learned something about how my code worked to make it easier for you the next time. Staying in php mode and using echo lines is so much better (IMHO) than leaving php mode and having to switch in and out while writing your hmtl is so much more complicated. Edited April 11, 2023 by ginerjm Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 11, 2023 Author Share Posted April 11, 2023 10 minutes ago, ginerjm said: But did you learn why your original code was not doing the job? That's the Important thing. Sort of. You assign 'x' to last_q, then fetch the results using a while loop (assuming reason being your fetching one record at a time) then test to see if last_q is less than or greater than the question , if it is echo it. Then you assign the question to last_q then echo the choices, and seeing it's in a loop, it prints out all the choices 17 minutes ago, ginerjm said: Staying in php mode and using echo lines is so much better I sort of agree, although I rarely do it. For smaller projects sometimes it's just easier just to go in and out of php. But for larger projects I can understand why people do it I'm actually trying to create a for loop within your code so I can generate some HTML (which I'm going to echo) so each choice is within the div classes in my original post (eg. answerA, answerB etc) Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 11, 2023 Share Posted April 11, 2023 I used last_q to only show the question once. I disagree with your thought on switching modes being easier at any time. FWIW - my scripts, short or long start PHP mode at the top and never end it. I never, EVER use the end-php-tag in my code. Never. When I have to output lots of non-php code I use the php Heredocs command. Try it - I think you'll like it. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 11, 2023 Author Share Posted April 11, 2023 5 minutes ago, ginerjm said: php Heredocs command I googled it, sounds interesting. Thanks Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 11, 2023 Share Posted April 11, 2023 (edited) 5 hours ago, webdeveloper123 said: I'm actually trying to create a for loop within your code so I can generate some HTML (which I'm going to echo) so each choice is within the div classes in my original post (eg. answerA, answerB etc) Curious why you think you need a loop to add the css/html. The loop is already there. You just need to do the formatting. I would add a div to begin the question box and when I output the choice I would add that inside that first box and close it. Then add a second one for the next choice. And when I had to show a new question, I would end the first question box and begin the new question box. No new loop needed? Edited April 11, 2023 by ginerjm Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted April 11, 2023 Share Posted April 11, 2023 if you index/pivot the data using the question as the main array index, you can directly produce the output using two nested foreach() loops, without needing extra variables and conditional logic to keep track of where each group of data changes or to output the starting/ending markup for each section, since there will be specific single points in the code for the start and end of each question section and of each option section. PDO even has a fetch mode to do this - PDO::FETCH_GROUP, which will index/pivot the data by the first column being SELECTed. to do this, change the fetchAll() line to this - $questions = $statement->fetchAll(PDO::FETCH_GROUP); you can then produce the output using this logic - foreach($questions as $question=>$group) { // start of question section echo $question; // loop over the rows in the 'group' to display the choices foreach($group as $row) { // start of choice section echo $row["choice"]; // end of choice section } // end of question section } to apply the answerA, answerB, ... classes to each choice section, you would store them in an array, e.g. $choice_styles = ['answerA', 'answerB', 'answerC', 'answerD'];, and change the second foreach loop to - foreach($group as $index=>$row) you can then get the correct style name in the choice section using - $choice_styles[$index]. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 12, 2023 Author Share Posted April 12, 2023 14 hours ago, ginerjm said: Curious why you think you need a loop to add the css/html. Yes, your right. I only realised that after logging off. I initially tried to echo the HTML inside your while loop (just in case I could use the same loop) , got about 30% of the way there then logged off. Thanks mac_gyver. I should have pointed out I am only displaying one question at a time, but I just added a WHERE clause at the end of the SQL. 12 hours ago, mac_gyver said: to apply the answerA, answerB, ... classes to each choice section mac_gyver, I have implemented your code and am trying the above advice now. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 12, 2023 Author Share Posted April 12, 2023 Hi Guys, I've got most of the code done, I just can't figure out how to increment the array to output div classes: answerA, answerB etc This is my code: <?php foreach($questions as $question=>$group) { ?> <div class="quizContent"> <p><?php echo $question;?></p> <?php $choice_styles = ['answerA', 'answerB', 'answerC', 'answerD']; foreach($group as $index=>$row) { ?> <?php echo "<div class='$choice_styles[0]'> ".$row["choice"]." </div>"; ?> <?php } ?> <?php } ?> I've tried using counters, putting a ++ right there in the array index position but can't get it to work. Just outputs 4 x answerA classes. Many thanks Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 12, 2023 Share Posted April 12, 2023 (edited) If your foreach is looping thru the query results what is that "key=>value" pairing supposed to represent? A query results doesn't have a key value on each row so I don't know what you think you getting there. And - Why do you need a unique class definition for the different question answers? Can't you just use one class? Showing the entire code might be helpful Edited April 12, 2023 by ginerjm Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 12, 2023 Author Share Posted April 12, 2023 15 minutes ago, ginerjm said: If your foreach is looping thru the query results what is that "key=>value" pairing supposed to represent? Which loop are you referring too? I was following mac_gyvers advice in he's earlier post. 16 minutes ago, ginerjm said: And - Why do you need a unique class definition for the different question answers? Can't you just use one class? For layout/CSS purposes <?php include 'includes/db.php'; $sql = "SELECT questions.question, quiz_options.choice FROM questions JOIN quiz_options ON questions.qid = quiz_options.qid WHERE questions.qid = 1;"; $statement = $pdo->query($sql); $questions = $statement->fetchAll(PDO::FETCH_GROUP); ?> <?php foreach($questions as $question=>$group) { ?> <div class="quizContent"> <p><?php echo $question;?></p> <?php $choice_styles = ['answerA', 'answerB', 'answerC', 'answerD']; foreach($group as $index=>$row) { ?> <?php echo "<div class='$choice_styles[0]'> ".$row["choice"]." </div>"; ?> <?php } ?> <?php } ?> The rest of it is just HTML Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 12, 2023 Share Posted April 12, 2023 (edited) Here is how I see your code with my questions interspersed. include 'includes/db.php'; $sql = "SELECT questions.question, quiz_options.choice FROM questions JOIN quiz_options ON questions.qid = quiz_options.qid WHERE questions.qid = 1;"; $statement = $pdo->query($sql); // query returns some rows each having 1 questions and 1 choice on it $questions = $statement->fetchAll(PDO::FETCH_GROUP); // never seen this option before // ps - all a fetchall does is copy your results to an array when // you could just loop thru the results a row at a time. Same result just a waste of memory // begin a loop foreach($questions as $question=>$group) // $question will be a numerical index of your array { echo "<div class='quizContent'>"; // one css setting for the entire q/a box? echo "<p>$question;?></p>"; $choice_styles = ['answerA', 'answerB', 'answerC', 'answerD']; // css class names? foreach($group as $index=>$row) // What is $group supposed to contain? echo "<div class='$choice_styles[0]'> ".$row["choice"]." </div>"; // you are using the SAME class name for every time thru // also you never show how $row got created } // end of loop Have you actually looked at your query results? It might make some of these issues go away if you see what your query gives you. Can we see these answera, answerb... css classes too? I want to see what you are doing that you need multiples Edited April 12, 2023 by ginerjm Quote Link to comment Share on other sites More sharing options...
kicken Posted April 12, 2023 Share Posted April 12, 2023 11 minutes ago, webdeveloper123 said: For layout/CSS purposes Do you actually need the separate classes though, or could you just use something like :nth-of-type? .quizContent > div:nth-of-type(1) { color: pink; } .quizContent > div:nth-of-type(2) { color: red; } .quizContent > div:nth-of-type(3) { color: black; } .quizContent > div:nth-of-type(4) { color: blue; } Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 12, 2023 Author Share Posted April 12, 2023 This was the original idea: <div class="quizContent"> <p>Quiz goes here</p> <div class="answerA"> <p>Answer A</p> </div> <div class="answerB"> <p>Answer B</p> </div> <div class="answerC"> <p>Answer C</p> </div> <div class="answerD"> <p>Answer D</p> </div> </div> 3 minutes ago, kicken said: Do you actually need the separate classes though hmm....never really thought of it that way...just have all the answers in one div class and use css to style them as if they were in separate containers. Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 12, 2023 Share Posted April 12, 2023 So you are putting the question in one box with 4 boxes inside of that box to show the current row's choice and the next 3 rows choices below the 1st. I gave you this code before and you have lost it. I don't think you understand how the results are coming to you and I think you need to do a print_r on one of the rows to get a visual look at what you have to work with. My original code will handle this. It just didn't have the css which I did mention would have to be added. Perhaps if you run the following code (assuming that I have no typos) it will give you a clear view of the data and then you can work with it to design it properly. Then you will see why I had that $last_q var in there. include 'includes/db.php'; $sql = "SELECT q.question, o.choice FROM questions q JOIN quiz_options o ON q.qid = o.qid WHERE q.qid = 1;"; $results = $pdo->query($sql); // this produces rows that contain a question and a choice for that question. // That means you have to handle the multiple choices by NOT showing the same question over and over. $last_q = 'x'; // a non-existent value $choice_num = 0; while(list($q, $c) = $results->fetch(PDO::FETCH_NUM)) // retrieve the contents of a single row as 2 vars { if($q <> $last_q) // starting a new question so close the last div and begin a new one { if ($last_q <> 'x') // is this the first question? If not, close the last question's box echo "</div>"; echo "<div class='question_box'>"; // start the new question box $choice_num = 0; // new question; new choice count } $choice_class = 'choice' . $choice_num; // setup the appropriate choice class $last_q = $q; // remember the current question echo "<p>$q</p>"; // show the question - figure out later how to prevent repetition (which I did earlier) echo "<div class='$choice_class'>"; // a box for this choice echo $c; echo "</div>"; // close this choice's box $choice_num++; // bump the choice cnt } echo "</div>"; // close the last question box If you don't want to pursue this effort I understand. It's your task and your option and I'll drop out. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 13, 2023 Author Share Posted April 13, 2023 18 hours ago, ginerjm said: If you don't want to pursue this effort I understand. It's your task and your option and I'll drop out. No I appreciate the code and I will implement it to see what it's like but I just remembered why I wanted 4 separate elements for the choices. I want to model the quiz to be similar to this one: https://www.bbc.co.uk/news/world-64825206 You see there is 3 choices, but mine will be 4 and you get the DOM scripting effect when You choose the correct answer and it goes green. Then you get green tick with a "Correct!". But I don't want the extra text underneath to explain why the answer was right (or wrong) But if you choose the wrong answer, you get a red X with "Wrong!" and then the correct answer goes green. But I don't want the percentages of how many people chose the choice. Should have mentioned all of this earlier. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 13, 2023 Author Share Posted April 13, 2023 Hey ginerjm, I tried that code and the questions prints out 4 times. Answers are fine though. This is what I get: Who plays Nicky Santoro in the film "Casino"? Joe Pesci Who plays Nicky Santoro in the film "Casino"? Anthony Hopkins Who plays Nicky Santoro in the film "Casino"? Robert De Niro Who plays Nicky Santoro in the film "Casino"? Christian Bale Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 13, 2023 Author Share Posted April 13, 2023 Oh right, I think you already knew that after reading your comments on the code Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 13, 2023 Share Posted April 13, 2023 You got 4 questions using MY code? Can I see the full script you are using to do that? I don't think my code does that. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 13, 2023 Author Share Posted April 13, 2023 The full script is the new code you provided me with, exact copy and paste of your earlier post, of the 2nd code you posted with the css/div class added in Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 13, 2023 Share Posted April 13, 2023 I would like to see exactly what you ran. Really. Copy and paste your code into a code block on your next post please so I can see how you may have altered it accidentally or on purpose. Quote Link to comment Share on other sites More sharing options...
webdeveloper123 Posted April 13, 2023 Author Share Posted April 13, 2023 <?php include 'includes/db.php'; $sql = "SELECT q.question, o.choice FROM questions q JOIN quiz_options o ON q.qid = o.qid WHERE q.qid = 1;"; $results = $pdo->query($sql); // this produces rows that contain a question and a choice for that question. // That means you have to handle the multiple choices by NOT showing the same question over and over. $last_q = 'x'; // a non-existent value $choice_num = 0; while(list($q, $c) = $results->fetch(PDO::FETCH_NUM)) // retrieve the contents of a single row as 2 vars { if($q <> $last_q) // starting a new question so close the last div and begin a new one { if ($last_q <> 'x') // is this the first question? If not, close the last question's box echo "</div>"; echo "<div class='question_box'>"; // start the new question box $choice_num = 0; // new question; new choice count } $choice_class = 'choice' . $choice_num; // setup the appropriate choice class $last_q = $q; // remember the current question echo "<p>$q</p>"; // show the question - figure out later how to prevent repetition (which I did earlier) echo "<div class='$choice_class'>"; // a box for this choice echo $c; echo "</div>"; // close this choice's box $choice_num++; // bump the choice cnt } echo "</div>"; // close the last question box ?> 4 minutes ago, ginerjm said: accidentally or on purpose. lol, why would I do it on purpose? Quote Link to comment Share on other sites More sharing options...
ginerjm Posted April 13, 2023 Share Posted April 13, 2023 OK - I should have echo'ed the $q inside the test of $last_q. This is the change: if($q <> $last_q) // starting a new question so close the last div and begin a new one { if ($last_q <> 'x') // is this the first question? If not, close the last question's box echo "</div>"; echo "<div class='question_box'>"; // start the new question box echo "<p>$q</p>"; // show the question - figure out later how to prevent repetition (which I did earlier) $choice_num = 0; // new question; new choice count } Remove the echo of $q from below this. Of course the css for the choice box should have (perhaps) and indent to position the answers neatly below the question. Maybe a label to identify the choice as well? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.