Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

baig's avatar
Level 1

Livewire component for displaying a pool of quiz quesiton one by one.

class UserQuizlv extends Component
{
    public $section_id;
    public $size;
    public $userAnser;
    public $currentQuestion;
    public $answeredQuestions = [];
    public $correctChoice;
    public $count = 0;
    public $quizid;

    public function showResults()
    {
        //dd($this->answeredQuestions);
    }
    public function render()
    {

        return view('livewire.user-quizlv');
    }

    public function mount()
    {
        $this->quizid = auth()->id() . '-' . time() . '-' . Str::random(12);
        $this->count = 0;
        $this->currentQuestion = $this->getQuestion()[0];
        //dd($this->currentQuestion->id);
    }

    public function getQuestion()
    {
        $question = Question::where('section_id', $this->section_id)
            ->whereNotIn('id', $this->answeredQuestions)
            ->with('answers')
            ->inRandomOrder()
            ->limit(1)
            ->get();
        array_push($this->answeredQuestions, $question[0]->id);
        return $question;
    }
    public function userAnswerClicked($id, $choice)
    {
        // dd($choice);
        // dd($this->currentQuestion->answers[1]->is_correct === '1');
    }

    public function nextQuestion()
    {
        if ($this->count <= $this->size - 1) {
            $storeQuestion = new Quiz();
            $storeQuestion->user_id = auth()->id();
            $storeQuestion->quizid = $this->quizid;
            $storeQuestion->question_id = $this->currentQuestion->id;
            $storeQuestion->section_id = $this->currentQuestion->section_id;
            $storeQuestion->answer_id = $this->currentQuestion->answers[1]->id;
            $storeQuestion->is_correct = '0';
            $storeQuestion->save();
            $this->count++;
            return $this->currentQuestion = $this->getQuestion()[0];
        }
        $this->showResults();
    }
}

0 likes
6 replies
baig's avatar
Level 1

I am trying to get a new unselected question on clicking next until it reaches the count of what the user has selected at the start of the quiz.

I want assistance in the right direction on template and component side how to check if the user has clicked the right choice. The $currentQuestion->answers object has the value of is_correct with it.

Thanks

webrobert's avatar

Love this build.

How bout this concept for the view blade… it probably will inspire revision in your component. …

A For each question loop to display the question and the possible answers (only send one question)

An If for questions count remains display next button otherwise show a see results button

Then for the loop when you send all their answered questions have a simple tenery on the possible answers (like you would for validation)

This keeps the blade super short.

Basically

@foreach($questions)

The loop content with teneray (when quiz answers are included)

@endforeach

@if($unansweredQuestions) button to call another question @else see your results button @endif

It’s not quite complete but I’m sure you get the idea.

baig's avatar
Level 1

Thank you for the direction,

I am kinda stuck at the view end where I've to evaluate the clicked choices for being the right choices.

I'm sending the question one at a time it has related answers and the is_correct status with it as $answer->is_correct= 1 or 0.

Once again Thanks!

baig's avatar
Level 1

#component part

class UserQuizlv extends Component
{
    public $section_id;
    public $size;
    public $userAnswer;
    public $currentQuestion;
    public $answeredQuestions = [];
    public $userAnswerIsCorrect;
    public $correctChoice;
    public $count = 0;
    public $quizid;

    public function showResults()
    {
        dd($this->answeredQuestions);
    }
    public function render()
    {

        return view('livewire.user-quizlv');
    }

    public function mount()
    {
        $this->quizid = auth()->id() . '-' . time() . '-' . Str::random(12);
        $this->count = 0;
        $this->currentQuestion = $this->getQuestion();
        // $correctAnswers = $this->currentQuestion->answers->filter(function ($value) {
        //     return $value->is_checked === '1';
        // });
    }

    public function getQuestion()
    {
        $question = Question::where('section_id', $this->section_id)
            ->whereNotIn('id', $this->answeredQuestions)
            ->with('answers')
            ->inRandomOrder()
            ->first();
        array_push($this->answeredQuestions, $question->id);
        return $question;
    }
    public function userAnswerClicked($id, $choice)
    {
        $this->userAnswer = $id;
        $this->userAnswerIsCorrect = $choice;
        //dd($id);
        // dd($this->currentQuestion->answers[1]->is_correct === '1');
    }

    public function nextQuestion()
    {
        $storeQuestion = new Quiz();
        $storeQuestion->user_id = auth()->id();
        $storeQuestion->quizid = $this->quizid;
        $storeQuestion->question_id = $this->currentQuestion->id;
        $storeQuestion->section_id = $this->currentQuestion->section_id;
        $storeQuestion->answer_id = $this->currentQuestion->answers[1]->id;
        $storeQuestion->is_correct = '0';
        $storeQuestion->save();
        $this->count++;
        if ($this->count == $this->size) {
            $this->showResults();
        }
        $this->currentQuestion = $this->getQuestion();
    }
}

blade part

 <div class="grid grid-cols-1 gap-6">
        <form wire:submit.prevent="nextQuestion">
            @csrf
            <div class="block p-2 m-2 font-extrabold bg-green-200 text-green-400">
                <p">{{$currentQuestion->question}} </p>
            </div>
            <div class="grid grid-cols-1 my-5 justify-center">
                @foreach($currentQuestion->answers as $answer)
                <div class="grid grid-cols-1 my-5 justify-center">
                    <label class="flex items-center">
                        <input id=question-{{$answer->id}} wire:click="userAnswerClicked({{ $answer->id }}, '{{$answer->is_checked}}')" type="checkbox">
                        <p p-1 m-1 bg-gray-400 text-gray-700 font-extrabold min-w-full mx-auto px-5> {{$answer->answer}}</p>
                    </label>
                </div>
                @endforeach
            </div>
            <div class="flex items-center justify-end mt-4">
                <button type="submit" class="ml-4">Next<button>
            </div>
        </form>
    </div>

webrobert's avatar

@baig here is what i was thinking... you'll have to add your logic to save and load the quiz.. and im not sure about how you want the user to interact with it but i think you get the idea.

class UserQuizlv extends Component
{

    Public $quiz, $unansweredCount, $questions, $userAnswer, $currentQuestionId, $showResults;

    public function Mount()
    {
        // my mockup for quiz data with the number of questions they requested.
        // this is just my dummy data. obviously dont render all the answers like this to the browser.

        $this->quiz = collect([
            [   'id' => 1,
                'question' => 'this is question 1',
                'answers'   => [
                    ['id' => 1, 'answer' => 'this is answer 1'],
                    ['id' => 2, 'answer' => 'this is answer 2'],
                    ['id' => 3, 'answer' => 'this is answer 3'],
                ],
                'userAnswer'    => null,
                'correctAnswer' => 2,
            ],
            [   'id' => 2,
                'question' => 'this is question 2',
                'answers'   => [
                    ['id' => 1, 'answer' => 'this is answer 1'],
                    ['id' => 2, 'answer' => 'this is answer 2'],
                    ['id' => 3, 'answer' => 'this is answer 3'],
                ],
                'userAnswerId'    => null,
                'correctAnswerId' => 2,
            ],
        ]);

        $this->GetQuestion(); // prepare a question on first render.
    }

    public function getQuestion()
    {
        $this->unansweredCount = 1; // logic here to check/update the count of unanswered questions
        $this->questions = $this->quiz->random(1);  // logic here to get another random unanswered question

        // set the new current question
        $this->currentQuestionId = $this->questions->first()['id'];
    }

    public function nextQuestion()
    {
        // save answer to Quiz from variables...
        $this->currentQuestionId;
        $this->userAnswer;


        $this->reset('userAnswer');
        $this->getQuestion();  // load a new question.
    }

    public function showResults()
    {
        $this->questions = $this->quiz; // assuming all the answers are now saved there.
        $this->showResults = true;
    }

    public function render()
    {
        return view('livewire.demo.user-quizlv');
    }

and my demo blade...

<div>
    @foreach($questions as $question)
        <div class="grid grid-cols-1 gap-6">
            <div class="block p-2 m-2 font-extrabold bg-green-200 text-green-400">
                <p class="text-xl">{{ $question['question'] }} </p>
            </div>
            
            <div class="grid grid-cols-1 my-5 justify-center">
                <div class="space-y-4 px-2">
                    @foreach($question['answers'] as $answer)
                        
                    @if($showResults) {{-- show answer logic here . --}} @endif
                    
                    <div class="flex items-start">
                        <div class="flex items-center h-5">
                            <input wire:click="$set('userAnswer', '{{ $answer['answer'] }}')" id="q_{{ $question['id'] }}_{{ $answer['id'] }}" name="q_{{ $question['id'] }}_{{ $answer['id'] }}" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
                        </div>
                        <div class="ml-3 text-sm">
                            <label for="q_{{ $question['id'] }}_{{ $answer['id'] }}" class="font-medium text-gray-700">{{ $answer['answer'] }}</label>
                        </div>
                    </div>

                    @endforeach
                </div>
            </div>
        </div>
    @endforeach

    {{ $userAnswer }}

    @if($unansweredCount > 1)
        <div class="flex items-center justify-end mt-4">
            <button wire:click="nextQuestion" type="submit" class="ml-4 bg-gray-400 p-2 rounded-md">Next</button>
        </div>
    @else
        <div class="flex items-center justify-end mt-4">
            <button wire:click="showResults" type="submit" class="ml-4 bg-gray-400 p-2 rounded-md">See Results</button>
        </div>
    @endif

</div>

it's not complete by any means but it puts the data where you want it. Let me know what you think.

1 like
baig's avatar
baig
OP
Best Answer
Level 1

Thank you @webrobert

Your blade part helped me in getting what I wanted. Here is the complete code that works perfectly for me.

<?php

namespace App\Http\Livewire;

use App\Models\Quiz;
use Livewire\Component;
use App\Models\Question;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class UserQuizlv extends Component
{
    public $totalQuizQuestions;
    public $currectQuizAnswers;
    public $quizPecentage;
    public $quizInProgress = true;
    public $showResult = false;
    public $sectionId;
    public $quizSize;
    public $currentQuestion;
    public $answeredQuestions = [];
    public $userAnswered = [];
    public $count = 0;
    public $quizid;

    public function showResults()
    {
        $this->totalQuizQuestions = Quiz::where('quizid', $this->quizid)->count();
        $this->currectQuizAnswers = Quiz::where('quizid', $this->quizid)
            ->where('is_correct', '1')
            ->count();
        $this->quizPecentage = round(($this->currectQuizAnswers / $this->totalQuizQuestions) * 100, 2);
        $this->showResult = true;
        $this->quizInProgress = false;
    }
    public function render()
    {
        return view('livewire.user-quizlv');
    }

    public function mount()
    {
        $this->quizid = auth()->id() . '-' . time() . '-' . Str::random(12);
        $this->count = 0;
        $this->currentQuestion = $this->getNextQuestion();
    }

    public function getNextQuestion()
    {
        $question = Question::where('section_id', $this->sectionId)
            ->whereNotIn('id', $this->answeredQuestions)
            ->with('answers')
            ->inRandomOrder()
            ->first();
        if ($question === null) {
            return $this->showResults();
        }
        array_push($this->answeredQuestions, $question->id);
        return $question;
    }

    public function nextQuestion()
    {
        $storeQuestion = new Quiz();
        list($answerId, $isChoiceCorrect) = explode(',', $this->userAnswered[0]);
        $storeQuestion->user_id = auth()->id();
        $storeQuestion->quizid = $this->quizid;
        $storeQuestion->question_id = $this->currentQuestion->id;
        $storeQuestion->section_id = $this->currentQuestion->section_id;
        $storeQuestion->answer_id = $answerId;
        $storeQuestion->is_correct = $isChoiceCorrect;
        $storeQuestion->save();
        $this->count++;
        $answerId = '';
        $isChoiceCorrect = '';
        $this->reset('userAnswered');
        if ($this->count == $this->quizSize) {
            $this->showResults();
        }
        $this->currentQuestion = $this->getNextQuestion();
    }
}

 <div class="bg-white rounded-lg shadow-lg p-5 md:p-20 mx-2">
    @if($quizInProgress)
    <div class="text-center">
        <h2 class="text-2xl tracking-tight leading-10 font-extrabold text-gray-900 md:text-3xl sm:leading-none">
            AppUser<span class="text-indigo-600 ml-2">Home</span>
        </h2>
        <p class="text-md mt-10"> Welcome <span class="font-extrabold text-blue-600 mr-2"> {{Auth::user()->name.'!'}} </span> As a registered user, you can access all resources on our website. Thankyou!</p>
    </div>
    <div class="grid grid-cols-1 gap-6">
        <form wire:submit.prevent="nextQuestion">
            @csrf
            <div class="block p-2 m-2 font-extrabold bg-green-200 text-green-400">
                <p">{{$currentQuestion->question}} </p>
            </div>
            <div class="grid grid-cols-1 my-5 justify-center">
                @foreach($currentQuestion->answers as $answer)
                <div class="grid grid-cols-1 my-5 justify-center">
                    <label class="flex items-center">
                        <input id=question-{{$answer->id}} value={{$answer->id .','.$answer->is_checked}} wire:model="userAnswered" type="checkbox">
                        <p p-1 m-1 bg-gray-400 text-gray-700 font-extrabold min-w-full mx-auto px-5> {{$answer->answer}}</p>
                    </label>
                </div>
                @endforeach
            </div>
            <div class="flex items-center justify-end mt-4">
                @if($count < $quizSize-1) <button type="submit" class="ml-4">Next<button>
                        @else
                        <button type="submit" class="ml-4">Show Result<button>
                                @endif
            </div>
        </form>
    </div>
    @endif
    @if($showResult)
    <div class="bg-white rounded-lg shadow-lg p-5 md:p-20 mx-2">
        <div class="text-center">
            <h2 class="text-2xl tracking-tight leading-10 font-extrabold text-gray-900 md:text-3xl sm:leading-none">
                AppUser<span class="text-indigo-600 ml-2">Home</span>
            </h2>
            <p class="text-md mt-10"> Welcome <span class="font-extrabold text-blue-600 mr-2"> {{Auth::user()->name.'!'}} </span> You have secured {{$quizPecentage}}%</p>
        </div>
        <div class="md:grid grid-cols-3 mt-10 justify-center gap-5">
            <div class="m-3  min-w-full mx-auto">
                <p class="bg-white tracking-wide text-gray-800 font-bold rounded border-2 border-blue-500 hover:border-blue-500 hover:bg-blue-500 hover:text-white shadow-md py-2 px-6 items-center">
                    <span class="mx-auto font-extrabold text-blue-800 pr-2">{{$totalQuizQuestions}}</span><span> Total Questions</span>
                </p>
            </div>
            <div class="m-3  min-w-full mx-auto">
                <p class="bg-white tracking-wide text-gray-800 font-bold rounded border-2 border-blue-500 hover:border-blue-500 hover:bg-blue-500 hover:text-white shadow-md py-2 px-6 items-center">
                    <span class="mx-auto font-extrabold text-blue-800 pr-2">{{$currectQuizAnswers}}</span><span> Correct Answers</span>
                </p>
            </div>
            <div class="m-3  min-w-full mx-auto justify-center">
                <p class="bg-white tracking-wide text-gray-800 font-bold rounded border-2 border-blue-500 hover:border-blue-500 hover:bg-blue-500 hover:text-white shadow-md py-2 px-6 items-center">
                    <span class="mx-auto font-extrabold text-blue-800 pr-2">{{$quizPecentage}}</span><span> Percentage</span>
                </p>
            </div>
        </div>
    </div>
    @endif
</div>

Cheers!!

1 like

Please or to participate in this conversation.