lukeboy_2002's avatar

No validation on save

I created a comment section with some help of the internet (YouTube) If commit my comment without any text is will save it to the database. I can not find my error and why. In my Livewire component I have a rule but is fails I think.

my livewire component

<?php

namespace App\Livewire;

use App\Models\Comment;
use App\Models\Post;
use Livewire\Attributes\Rule;
use Livewire\Component;

class CommentCreate extends Component
{
    #[Rule('required|min:3|max:200')]
    public string $comment;

    public Post $post;

    public ?Comment $commentModel = null;
    public ?Comment $parentComment = null;

    public function mount(Post $post, $commentModel = null, $parentComment = null)
    {
        $this->post = $post;
        $this->commentModel = $commentModel;
        $this->comment = $commentModel ? $commentModel->comment : '';

        $this->parentComment = $parentComment;
    }

    public function render()
    {
        return view('livewire.comment-create');
    }

    public function createComment()
    {
        $user = auth()->user();
        if (!$user) {
            return $this->redirect('/login');
        }

        if ($this->commentModel) {
            if ($this->commentModel->user_id != $user->id) {
                return response('You are not allowed to perform this action', 403);
            }

            $this->commentModel->comment = $this->comment;
            $this->commentModel->save();

            $this->comment = '';
            $this->dispatch('commentUpdated');
        } else {
            $comment = Comment::create([
                'comment' => $this->comment,
                'post_id' => $this->post->id,
                'user_id' => $user->id,
                'parent_id' => $this->parentComment?->id
            ]);

            $this->dispatch('commentCreated', $comment->id);
            $this->comment = '';
        }
    }
}

My blade file


<div>
    @auth
    <div x-data="{
            focused: {{ $parentComment ? 'true' : 'false' }},
            isEdit: {{ $commentModel ? 'true' : 'false'}},
            init() {
                if (this.isEdit || this.focused)
                    this.$refs.input.focus();

                $wire.on('commentCreated', () => {
                    this.focused = false;
                })
            }
    }" class="mb-4" >
        <div class="mb-2">
            <textarea x-ref="input" wire:model="comment" @click="focused = true"
                      id="comment"
                      name="comment"
                      class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
                      :rows="isEdit || focused ? '2' : '1'"
                      placeholder="Leave a comment"
                      required
            ></textarea>
            <x-forms.input-error for="comment" class="mt-2" />
        </div>
        <div class="flex justify-end space-x-2" :class="isEdit || focused ? '' : 'hidden'">
            <x-buttons.secondary @click="focused = false; isEdit = false; $wire.dispatch('cancelEditing')" type="button" class="px-3 py-2 text-xs font-medium">
                Cancel
            </x-buttons.secondary>
            <x-buttons.primary wire:click="createComment" type="submit" class="px-3 py-2 text-xs font-medium">
                Submit
            </x-buttons.primary>
        </div>
    </div>
    @else
        <div class="flex justify-end items-center space-x-1">
            <p class="text-gray-900 dark:text-white text-xs">Only registered users can leave a comment.</p>
            <x-links.primary href="{{ route('login') }}"> Login</x-links.primary>
        </div>
    @endauth
</div>

Can someone help me?

0 likes
5 replies
LaryAI's avatar
Level 58

It looks like you're trying to use an attribute-based validation rule in your Livewire component, but you're not using it correctly. The #[Rule] attribute is not a standard way to define validation rules in Livewire. Instead, you should define a rules method that returns an array of validation rules.

Here's how you can update your Livewire component to include proper validation:

namespace App\Livewire;

use App\Models\Comment;
use App\Models\Post;
use Livewire\Component;

class CommentCreate extends Component
{
    public $comment;
    public Post $post;
    public ?Comment $commentModel = null;
    public ?Comment $parentComment = null;

    protected function rules()
    {
        return [
            'comment' => 'required|min:3|max:200',
        ];
    }

    public function mount(Post $post, $commentModel = null, $parentComment = null)
    {
        $this->post = $post;
        $this->commentModel = $commentModel;
        $this->comment = $commentModel ? $commentModel->comment : '';
        $this->parentComment = $parentComment;
    }

    public function render()
    {
        return view('livewire.comment-create');
    }

    public function createComment()
    {
        $this->validate();

        $user = auth()->user();
        if (!$user) {
            return $this->redirect('/login');
        }

        if ($this->commentModel) {
            if ($this->commentModel->user_id != $user->id) {
                return response('You are not allowed to perform this action', 403);
            }

            $this->commentModel->comment = $this->comment;
            $this->commentModel->save();

            $this->comment = '';
            $this->dispatch('commentUpdated');
        } else {
            $comment = Comment::create([
                'comment' => $this->comment,
                'post_id' => $this->post->id,
                'user_id' => $user->id,
                'parent_id' => $this->parentComment ? $this->parentComment->id : null
            ]);

            $this->dispatch('commentCreated', $comment->id);
            $this->comment = '';
        }
    }
}

In the createComment method, I've added $this->validate(); which will trigger the validation rules defined in the rules method. If the validation fails, Livewire will automatically throw an exception and render the validation errors in the view.

Make sure your blade file is set up to display these validation errors. You can use the @error directive to show specific error messages:

<div>
    <!-- Validation Errors -->
    @error('comment')
        <span class="text-red-500 text-xs">{{ $message }}</span>
    @enderror

    <!-- Rest of your form -->
</div>

With these changes, your Livewire component should now properly validate the comment input before saving it to the database.

Snapey's avatar

bear in mind that Lary's answer is from early 2023 (ie, Livewire 2)

Snapey's avatar

@lukeboy_2002 you dont yave to do realtime validation, but if you dont you need to include $this->validate()

Please or to participate in this conversation.