vainway 's avatar

validations in laravel livewire

I installed livewire in my project and I am making multiple-step forms in livewire, am getting an error when I upload anything in my file input, it comes and disappear in a second, and when I click the button to go to the next step I tell me

the slug must be a file

post-projects.blade.php

<div>
    <form wire:submit.prevent="PostProjects">
        @csrf
        @if ($currentTab == 1)
        <div class="tab-1">
            <div class="form-group">
                <label>Project Title</label>
                <input type="text" name="title" wire:model="title" class="form-control @error('title') is-invalid @enderror" placeholder="" value="" required autocomplete="title" autofocus>

                @error('title')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
            </div>
            <div class=""> 
            <label>Attach files</label>
            <div class="file-drop-area">
                <span class="btn btn-outline-info">Choose files</span>
                <span class="file-msg js-set-number"> or drag and drop files here</span>
                <input class="file-input @error('slug') is-invalid @enderror" wire:model="slug" type="file" required multiple>

                @error('slug')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
            </div>
            </div>
            <div class="form-group">
            <label>Price</label>
                <div class="">
                    <input id="price" type="number" wire:model="price" class="form-control @error('price') is-invalid @enderror" name="price" placeholder="Price..." value="" required autocomplete="price" autofocus>

                    @error('price')
                        <span class="invalid-feedback" role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
                </div>
            </div>
            <div class="row">
                <div class="col-md-6 pr-1">
                    <div class="form-group">
                    <label>Choose a Category:</label>
                    <select id="name" name="cat_id" wire:model="cat_id" class="form-control @error('cat_id') is-invalid @enderror">
                        <option value="select">Select Category</option>
                        @foreach($categories as $cat)
                            <option value="{{ $cat->id }}">{{ $cat->name }}</option>
                        @endforeach
                    </select>
                    @error('cat_id')
                        <span class="invalid-feedback" role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
                    </div>
                </div>
                <div class="col-md-6 pl-1">
                    <div class="form-group">
                    <label>Choose a Sub-Category:</label>
                        <div class="content">
                            <div id="select" class="data">
                                <select class="form-control" disabled>
                                    <option value="">Select subcategory</option>
                                </select>
                            </div>
                            <div>
                            @if(!is_null($subcategories))
                            <select name="subcat_id" wire:model="subcat_id" class="form-control @error('subcat_id') is-invalid @enderror">
                                <option value="">Select Sub-Category</option>
                                @foreach($subcategories as $subcategory)
                                    <option value="{{ $subcategory->id }}">{{ $subcategory->name }}</option>
                                @endforeach
                            </select>
                                @error('subcat_id')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            @endif
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        @endif

        @if ($currentTab == 2)
        <div class="tab-2">
            <div class="form-group">
            <label>Describe Project You're Posting</label>
            <textarea rows="4" name="description" cols="180" wire:model="description" class="form-control @error('description') is-invalid @enderror" placeholder="Here can be your description" required></textarea>   
            
            @error('description')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
            </div>
            <br>
            <div class="">
            <h3>Frequently Asked Questions</h3>
            <hr>
            <div class="form-group">
                <label>Question Title</label>
                <input type="text" name="qt_title" wire:model="qt_title" class="form-control @error('qt_title') is-invalid @enderror" placeholder="Add a Question:" value="" required autocomplete="qt_title" autofocus>

                @error('qt_title')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
            </div>
            <div class="form-group">
                <label>Add Questions & Answers.</label>
                <textarea rows="7" cols="85" name="qt_answer" wire:model="qt_answer" class="form-control @error('qt_answer') is-invalid @enderror"  placeholder="Add an Answer: i.e. Yes,I also design 3D Logo" required></textarea>   

                @error('qt_answer')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
            </div>
            </div>
        </div>
        @endif
        <div style="overflow:auto;">
            <div class="">
                @if ($currentTab == 1)
                    <button type="button" wire:click="increaseStep()" class="btn btn-success float-right">Next</button>
                @endif

                @if ($currentTab == 2)
                    <button type="button" wire:click="decreaseStep()" class="btn btn-info float-left">Back</button>
                    <button type="submit" class="btn btn-success float-right">Submit</button>
                @endif
            </div>
        </div>
        <!-- Circles which indicates the steps of the form: -->
        <div style="text-align:center;margin-top:40px;">
            <span class="step"></span>
            <span class="step"></span>
        </div>
    </form>
</div>

my controller: PostProjects.php

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;
use App\Models\PostProject;
use App\Models\Category;
use App\Models\Subcategory;
use Illuminate\Support\Facades\Auth;

class PostProjects extends Component
{
    use WithFileUploads;

    public $cat_id = null;
    public $subcat_id = null;
    public $subcategories = null;

    public $title;
    public $slug;
    public $price;
    public $description;
    public $qt_title;
    public $qt_answer;

    public $totalTabs = 2;
    public $currentTab = 1;

    public function mount()
    {
        $this->currentTab = 1;
    }

    public function render()
    {
        return view('livewire.post-projects', [
            'categories' => Category::all(),
        ]);
    }

    public function updatedCategory($cat_id)
    {
        $this->subcategories = Subcategory::where('cat_id', $cat_id)->get();
    }

    public function increaseStep ()
    {
        $this->resetErrorBag();
        $this->validateData();
        $this->currentTab++;
        if ($this->currentTab > $this->totalTabs) {
            $this->currentTab = $this->totalTabs;
        }
    }

    public function decreaseStep ()
    {
        $this->resetErrorBag();
        $this->currentTab--;
        if ($this->currentTab < 1) {
            $this->currentTab = 1;
        }
    }

    public function validateData ()
    {
        if ($this->currentTab == 1) {
            $this->validate([
                'title' => 'required|min:3',
                'slug' => 'required|file|max:5120',
                'price' => 'required|min:5',
                'cat_id' => 'required|string',
                'subcat_id' => 'required|string',
            ]);
        }
        elseif ($this->currentTab == 2) {
            $this->validate([
                'description' => 'required|min:10',
                'qt_title' => 'required|min:3',
                'qt_answer' => 'required|min:10',
            ]);
        }

    }

    public function PostProjects () {
        $upload = $this->file('slug');
        $path = $upload->store('public/storage/ProjectsPosted');

        PostProject::create([
            'title' => $this->title,
            'slug' => $path,
            'price' => $this->price,
            'cat_id' => $this->cat_id,
            'subcat_id' => $this->subcat_id,
            'description' => $this->description,
            'qt_title' => $this->qt_title,
            'qt_answer' => $this->qt_answer,
            'user_id' => Auth::user()->id
        ]);
        $this->reset();
        $this->currentTab = 1;
    }
}

I got another problem when I added my categories and subcategories because they must be stored in the same table, they were working well before putting them in the same controller cause they were separated one in Categories.php another in PostProjects.php this controller I posted

0 likes
20 replies
Snapey's avatar

don't call your file input attribute the same as the column on the database

change public $slug throughout your code to a different name, except for where you actually put the path in the model

Also remove multiple from the file input

vainway 's avatar

@snapey I changed "public $slug" to public $image; and I got a new error

no property found for validation [slug]

I changed also no my categories their public variable and wire:model it worked well as it were I removed "multiple" also, changed wire:model="image" what else am I missing?

migsAV's avatar

Because you changed to wire:model="image" you need to change the validation rule to 'image' => 'required|file|max:5120',

vainway 's avatar

@migsAV I changed it and I got another new error

BadMethodCallException Method App\Http\Livewire\PostProjects::file does not exist

If my validation doesn't match with the names of the input or in the table how will it submit anything?

Snapey's avatar

@niyo change

        //$upload = $this->file('slug');
        $path = $this->image->store('public/storage/ProjectsPosted');
1 like
vainway 's avatar

@Snapey I got another error while submitting the form

Property[$cat_id] not found on component: [post-projects]

I tried to replace

public function updatedCategory($cat_id)
    {
        $this->subcategories = Subcategory::where('cat_id', $cat_id)->get();
    }

to this also

public $selectedCategory = null;
public $selectedSubcategory = null;
public $subcategories = null;

public function updatedSelectedCategory($selectedCategory)
    {
        $this->subcategories = Subcategory::where('cat_id', $selectedCategory )->get();
    }

but still not working

migsAV's avatar

@niyo

public function updatedCategory()
    {
        $this->subcategories = Subcategory::where('cat_id', $this->cat_id)->get();
    }
vainway 's avatar

@migsAV I removed it and it's flowing another error

Undefined variable cat_id

migsAV's avatar

@niyo you do not have a public property called category, therefore this is not being called

public function updatedCategory()
    {       
    }

Livewire Lifecycle Hooks

Try and be consistent with your naming conventions

migsAV's avatar

@niyo

<div class="form-group">
                    <label>Choose a Category:</label>
                    <select id="category" name="category" wire:model="category" class="form-control @error('category') is-invalid @enderror">
                        <option value="select">Select Category</option>
                        @foreach($categories as $category)
                            <option value="{{ $category->id }}">{{ $category->name }}</option>
                        @endforeach
                    </select>
                    @error('category')
                        <span class="invalid-feedback" role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
                    </div>
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;
use App\Models\PostProject;
use App\Models\Category;
use App\Models\Subcategory;
use Illuminate\Support\Facades\Auth;

class PostProjects extends Component
{
    use WithFileUploads;

    public $category = '';

    public function updatedCategory()
    {
        $this->subcategories = Subcategory::where('cat_id', $category)->get();
    }
}
vainway 's avatar

@migsAV I tried it but it still gives me the same error

Undefined variable category

and if I add it again as an argument it push the same error

Property[$cat_id] not found on component: [post-projects]

and I ask myself where $cat_id is from even though it's not included in the codes

class PostProjects extends Component
{
    use WithFileUploads;

    public $category = ' ';
    public $selectedSubcategory = null;
    public $subcategories = null;

    public $title;
    public $image;
    public $price;
    public $description;
    public $qt_title;
    public $qt_answer;

    public $totalTabs = 2;
    public $currentTab = 1;

    public function mount()
    {
        $this->currentTab = 1;
    }

    public function render()
    {
        return view('livewire.post-projects', [
            'categories' => Category::all(),
        ]);
    }

    public function updatedcategory($category)
    {
        $this->subcategories = Subcategory::where('cat_id', $category)->get();
        
    }

    public function increaseStep ()
    {
        $this->resetErrorBag();
        $this->validateData();
        $this->currentTab++;
        if ($this->currentTab > $this->totalTabs) {
            $this->currentTab = $this->totalTabs;
        }
    }

    public function decreaseStep ()
    {
        $this->resetErrorBag();
        $this->currentTab--;
        if ($this->currentTab < 1) {
            $this->currentTab = 1;
        }
    }

    public function validateData ()
    {
        if ($this->currentTab == 1) {
            $this->validate([
                'title' => 'required|min:3',
                'image' => 'required|file|mimes:png,jpg,pdf|max:5120',
                'price' => 'required|min:5',
                'category' => 'required|string',
                'selectedSubcategory' => 'required|string',
            ]);
        }
        elseif ($this->currentTab == 2) {
            $this->validate([
                'description' => 'required|min:10',
                'qt_title' => 'required|min:3',
                'qt_answer' => 'required|min:10',
            ]);
        }

    }

    public function PostProjects () {
        // $upload = $this->file('slug');
        //$path = $upload->store('public/storage/ProjectsPosted');
        $path = $this->image->store('public/storage/ProjectsPosted');

        PostProject::create([
            'title' => $this->title,
            'slug' => $path,
            'price' => $this->price,
            'cat_id' => $this->cat_id,
            'subcat_id' => $this->subcat_id,
            'description' => $this->description,
            'qt_title' => $this->qt_title,
            'qt_answer' => $this->qt_answer,
            'user_id' => Auth::user()->id
        ]);
        $this->reset();
        $this->currentTab = 1;
    }
}

I am using everything you and @snapey 's methods

migsAV's avatar
migsAV
Best Answer
Level 31

@niyo I replicated your error and may have fixed it.

Try this code

<?php

namespace App\Http\Livewire;

use App\Models\Category;
use App\Models\PostProject;
use App\Models\Subcategory;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use Livewire\WithFileUploads;

class PostProjects extends Component
{
    use WithFileUploads;

    public $category = null;
    public $subcategory = null;
    public $listSubcategories = null;

    public $title;
    public $slug;
    public $price;
    public $description;
    public $qt_title;
    public $qt_answer;

    public $totalTabs = 2;
    public $currentTab = 1;

    public function mount()
    {
        $this->currentTab = 1;
    }

    public function updatedCategory()
    {
        $this->listSubcategories = Subcategory::where('category_id', $this->category)->get();
    }

    public function increaseStep ()
    {
        $this->resetErrorBag();
        $this->validateData();
        $this->currentTab++;
        if ($this->currentTab > $this->totalTabs) {
            $this->currentTab = $this->totalTabs;
        }
    }

    public function decreaseStep ()
    {
        $this->resetErrorBag();
        $this->currentTab--;
        if ($this->currentTab < 1) {
            $this->currentTab = 1;
        }
    }

    public function validateData ()
    {
        if ($this->currentTab == 1) {
            $this->validate([
                'title' => 'required|min:3',
                'slug' => 'required|file|max:5120',
                'price' => 'required|min:5',
                'category' => 'required|string',
                'subcategory' => 'required|string',
            ]);
        }
        elseif ($this->currentTab == 2) {
            $this->validate([
                'description' => 'required|min:10',
                'qt_title' => 'required|min:3',
                'qt_answer' => 'required|min:10',
            ]);
        }

    }

    public function PostProjects () {
//        $upload = $this->file('slug');
        $path = $this->slug->store('public/storage/ProjectsPosted');

        PostProject::create([
            'title' => $this->title,
            'slug' => $path,
            'price' => $this->price,
            'cat_id' => $this->category,
            'subcat_id' => $this->subcategory,
            'description' => $this->description,
            'qt_title' => $this->qt_title,
            'qt_answer' => $this->qt_answer,
            'user_id' => Auth::user()->id
        ]);
        $this->reset();
        $this->currentTab = 1;
    }


    public function render()
    {
        return view('livewire.post-projects',  [
            'categories' => Category::all(),
        ]);
    }
}

You will notice I renamed subcategories to listSubcategories

<div>
    <form wire:submit.prevent="PostProjects">
        @csrf
        @if ($currentTab == 1)
            <div class="tab-1">
                <div class="form-group">
                    <label>Project Title</label>
                    <input type="text" name="title" wire:model="title" class="form-control @error('title') is-invalid @enderror" placeholder="" value="" required autocomplete="title" autofocus>

                    @error('title')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                    @enderror
                </div>
                <div class="">
                    <label>Attach files</label>
                    <div class="file-drop-area">
                        <span class="btn btn-outline-info">Choose files</span>
                        <span class="file-msg js-set-number"> or drag and drop files here</span>
                        <input class="file-input @error('slug') is-invalid @enderror" wire:model="slug" type="file">

                        @error('slug')
                        <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                        @enderror
                    </div>
                </div>
                <div class="form-group">
                    <label>Price</label>
                    <div class="">
                        <input id="price" type="number" wire:model="price" class="form-control @error('price') is-invalid @enderror" name="price" placeholder="Price..." value="" required autocomplete="price" autofocus>

                        @error('price')
                        <span class="invalid-feedback" role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                        @enderror
                    </div>
                </div>
                <div class="row">
                    <div class="col-md-6 pr-1">
                        <div class="form-group">
                            <label>Choose a Category:</label>
                            <select id="category" name="category" wire:model="category" class="form-control @error('category') is-invalid @enderror">
                                <option value="select">Select Category</option>
                                @foreach($categories as $category)
                                    <option value="{{ $category->id }}">{{ $category->name }}</option>
                                @endforeach
                            </select>
                            @error('category')
                            <span class="invalid-feedback" role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                            @enderror
                        </div>
                    </div>
                    <div class="col-md-6 pl-1">
                        <div class="form-group">
                            <label>Choose a Sub-Category:</label>
                            <div class="content">
                                <div id="select" class="data">
                                    <select class="form-control" disabled>
                                        <option value="">Select subcategory</option>
                                    </select>
                                </div>
                                <div>
                                    @if(!is_null($listSubcategories))
                                        <select name="subcategory" wire:model="subcategory" class="form-control @error('subcategory') is-invalid @enderror">
                                            <option value="">Select Sub-Category</option>
                                            @foreach($listSubcategories as $listCategory)
                                                <option value="{{ $listCategory->id }}">{{ $listCategory->name }}</option>
                                            @endforeach
                                        </select>
                                        @error('subcategory')
                                        <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                        @enderror
                                    @endif
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        @endif

        @if ($currentTab == 2)
            <div class="tab-2">
                <div class="form-group">
                    <label>Describe Project You're Posting</label>
                    <textarea rows="4" name="description" cols="180" wire:model="description" class="form-control @error('description') is-invalid @enderror" placeholder="Here can be your description" required></textarea>

                    @error('description')
                    <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
                    @enderror
                </div>
                <br>
                <div class="">
                    <h3>Frequently Asked Questions</h3>
                    <hr>
                    <div class="form-group">
                        <label>Question Title</label>
                        <input type="text" name="qt_title" wire:model="qt_title" class="form-control @error('qt_title') is-invalid @enderror" placeholder="Add a Question:" value="" required autocomplete="qt_title" autofocus>

                        @error('qt_title')
                        <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                        @enderror
                    </div>
                    <div class="form-group">
                        <label>Add Questions & Answers.</label>
                        <textarea rows="7" cols="85" name="qt_answer" wire:model="qt_answer" class="form-control @error('qt_answer') is-invalid @enderror"  placeholder="Add an Answer: i.e. Yes,I also design 3D Logo" required></textarea>

                        @error('qt_answer')
                        <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                        @enderror
                    </div>
                </div>
            </div>
        @endif
        <div style="overflow:auto;">
            <div class="">
                @if ($currentTab == 1)
                    <button type="button" wire:click="increaseStep()" class="btn btn-success float-right">Next</button>
                @endif

                @if ($currentTab == 2)
                    <button type="button" wire:click="decreaseStep()" class="btn btn-info float-left">Back</button>
                    <button type="submit" class="btn btn-success float-right">Submit</button>
                @endif
            </div>
        </div>
        <!-- Circles which indicates the steps of the form: -->
        <div style="text-align:center;margin-top:40px;">
            <span class="step"></span>
            <span class="step"></span>
        </div>
    </form>

    @if($errors->any())
        {!! implode('', $errors->all('<div>:message</div>')) !!}
    @endif

</div>

vainway 's avatar

@migsAV thanks man It worked, I only had to change this down below to make it work

PostProject::create([
            'title' => $this->title,
            'slug' => $path,
            'price' => $this->price,
            'cat_id' => $this->category,
            'subcat_id' => $this->subcategory,
            'description' => $this->description,
            'qt_title' => $this->qt_title,
            'qt_answer' => $this->qt_answer,
            'user_id' => Auth::user()->id
        ]);

These two guys right here were the ones causing this problem

'cat_id' => $this->cat_id,
'subcat_id' => $this->subcat_id,

man, I don't what to say it's like I owe you a lot, thank you so much

migsAV's avatar

@niyo you're welcome. That's why Laracast is here, to help :) Mark the answer as the best answer so others know it has been resolved.

Happy coding

vainway 's avatar

@snapey @migsav I have another question for guys on validation. I want to ask you which method can I use to ask a user to add an amount above a certain price to my project If a user types in the price input the price below example: $100 and I tell them the price must be above $100 to continue.

an example

if ($this->price < 100) {
            $this->validate([
                'title' => 'required|min:3',
                'slug' => 'required|file|max:5120',
                'price' => 'required',
                'category' => 'required|string',
                'subcategory' => 'required|string',
            ]);
   }

I seen online methods like number_format(), money_format(), etc... I need to use this method on this form

vainway 's avatar

@migsAV I am getting the validation right The price must be at least 100.but I want it like The price must be at least $100. Is there a way I can change it

migsAV's avatar

@niyo in the validation you need to add an additional array to customise the error message

$this->validate([
                'title' => 'required|min:3',
                'slug' => 'required|file|max:5120',
               'price' => 'required|numeric|min:100',
                'category' => 'required|string',
                'subcategory' => 'required|string',
            ], [
				'price.min' => 'The price must be at least $100.'
				]);

https://laravel-livewire.com/docs/2.x/input-validation - half way down the page

1 like
vainway 's avatar

@migsAV I have another small question for you, I want to make another multi-step-form but this will be submitting on different tables like step1 to table1 and step2 to table2 also step3 to table3 I need to know if it can work the way am thinking or not.

migsAV's avatar

@niyo I'm sure it is possible. I have never done it myself, you might need to play around with it. Maybe look for a thread on Laracast, someone might have asked the same question already.

1 like

Please or to participate in this conversation.