Courses

Creating a Quiz System with Laravel 10 + Livewire 3: Step-by-Step

Admin: Answer Options for Questions

In this tutorial, we will add the ability to add the possible answer options to the question. This is the first time in this course where Livewire will actually shine:

edit question

Let's start by creating a Model with Migration and adding relationships.

php artisan make:model QuestionOption -m

database/migrations/xxxx_create_question_options_table.php:

return new class extends Migration
{
public function up(): void
{
Schema::create('question_options', function (Blueprint $table) {
$table->id();
$table->string('option');
$table->boolean('correct')->default(0)->nullable();
$table->foreignId('question_id')->nullable()->constrained();
$table->timestamps();
$table->softDeletes();
});
}
};

app/Models/QuestionOption.php:

class QuestionOption extends Model
{
use HasFactory;
use SoftDeletes;
 
protected $fillable = [
'option',
'correct',
'question_id',
];
 
protected $casts = [
'correct' => 'boolean',
];
 
public function question(): BelongsTo
{
return $this->belongsTo(Question::class);
}
}

To the QuestionOption Model we also add a Cast to the correct field, so that it would always return a boolean.

class Question extends Model
{
use SoftDeletes;
 
protected $fillable = [
'question_text',
'code_snippet',
'answer_explanation',
'more_info_link',
];
 
public function questionOptions(): HasMany
{
return $this->hasMany(QuestionOption::class)->inRandomOrder();
}
}

Next, we need to extend the Livewire component for the questions form that we created in an earlier lesson.

app/Livewire/Questions/QuestionForm.php:

class QuestionForm extends Component
{
public Question $question;
 
public bool $editing = false;
 
public array $questionOptions = [];
 
public function mount(Question $question): void
{
$this->question = $question;
 
if ($this->question->exists) {
$this->editing = true;
 
foreach ($question->questionOptions as $option) {
$this->questionOptions[] = [
'id' => $option->id,
'option' => $option->option,
'correct' => $option->correct,
];
}
}
}
 
public function addQuestionsOption(): void
{
$this->questionOptions[] = [
'option' => '',
'correct' => false
];
}
 
public function removeQuestionsOption(int $index): void
{
unset($this->questionOptions[$index]);
$this->questionOptions = array_values(($this->questionOptions));
}
 
public function save(): Redirector
{
$this->validate();
 
if (empty($this->question)) {
$this->question = Question::create($this->only(['question_text', 'code_snippet', 'answer_explanation', 'more_info_link']));
} else {
$this->question->update($this->only(['question_text', 'code_snippet', 'answer_explanation', 'more_info_link']));
}
 
$this->question->questionOptions()->delete();
 
foreach ($this->questionOptions as $option) {
$this->question->questionOptions()->create($option);
}
 
return to_route('questions');
}
 
public function render(): View
{
return view('livewire.questions.form');
}
 
protected function rules(): array
{
return [
'question_text' => [
'string',
'required',
],
'code_snippet' => [
'string',
'nullable',
],
'answer_explanation' => [
'string',
'nullable',
],
'more_info_link' => [
'url',
'nullable',
],
'questionOptions' => [
'required',
'array',
],
'questionOptions.*.option' => [
'required',
'string',
],
];
}
}

Now, what have we added here?

  • First, the $questionOptions public property, where all options will be added.
  • In the mount() where we check if Question exists, we add code to add all options into the $questionOptions public array property.
  • Next, two methods addQuestionsOption() and removeQuestionsOption(). Both the name says what they do. First, adds a new question option to the array, and second, removes and indexes an array.
  • In the save() method we added the creation of the options for the questions.
  • And last, additional rules for question options.

Now, let's show question options in the form. We will add it right after the question text.

resources/views/livewire/questions/form.blade.php:

// ...
<div class="mt-4">
<x-input-label for="question_options" value="Question options"/>
@foreach($questionOptions as $index => $questionOption)
<div class="flex mt-2">
<x-text-input type="text" wire:model="questionOptions.{{ $index }}.option" class="w-full" name="questions_options_{{ $index }}" id="questions_options_{{ $index }}" autocomplete="off"/>
 
<div class="flex items-center">
<input type="checkbox" class="mr-1 ml-4" wire:model.defer="questionOptions.{{ $index }}.correct"> Correct
<button wire:click="removeQuestionsOption({{ $index }})" type="button" class="ml-4 rounded-md border border-transparent bg-red-200 px-4 py-2 text-xs uppercase text-red-500 hover:bg-red-300 hover:text-red-700">
Delete
</button>
</div>
</div>
<x-input-error :messages="$errors->get('questionOptions.' . $index . '.option')" class="mt-2" />
@endforeach
 
<x-input-error :messages="$errors->get('questionOptions')" class="mt-2" />
 
<x-primary-button wire:click="addQuestionsOption" type="button" class="mt-2">
Add
</x-primary-button>
</div>
 
// ...

After visiting create the form you should see a button ADD, and after pressing it you should see appearing input for adding an option to a question.

create question with question options

Now you can create questions with question options.

edit question

Previous: Admin: Questions CRUD
avatar

Hello, I cant get this code to work! Follow all the processes.

avatar
You can use Markdown
avatar

Hi, the reference

resources/views/livewire/questions/form.blade.php

shoud be

resources/views/livewire/questions/question-form.blade.php

avatar

Many thanks,

In my case, I missed out the livewire asset and script tag in the app.blade.php.

Regards

avatar
You can use Markdown
avatar

Thanks @asequeira well noticed, fixed in the lesson text!

avatar

Hi, I want the repository link please Thanks

avatar

https://github.com/LaravelDaily/Livewire-Laraquiz-Course

avatar
You can use Markdown
avatar

Hi many thanks for this good offer. When I login I don't see the question form. How do I find it? I did this "/questions/create" but still did not find it

avatar

What question form are you talking about?

avatar
You can use Markdown
avatar

Hi please im getting error . Livewire page component layout view not found: [components.layouts.app]

avatar

i followed the direction but cant acces question but the above error

avatar

Set the proper layout in the config https://livewire.laravel.com/docs/components#global-layout-configuration

avatar
You can use Markdown
avatar
You can use Markdown