Jump to content

How to show multiple records with the same name on the same page?


Go to solution Solved by ginerjm,

Recommended Posts

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

  • Solution

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 by ginerjm

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 by ginerjm
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) 

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.

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 by ginerjm

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].

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.  

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

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 by ginerjm
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

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 by ginerjm
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;
}

 

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.

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.

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.

 

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

 

  <?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?

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?

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.