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

warpig's avatar
Level 12

Converting a Laravel form to Livewire

I want to submit an input to the database with Livewire but the problem is that in my ProfileController I am using $qualities to retrieve a collection to the view: profile.index, and in the Livewire component I use $quality to submit a form, when I rendered the component in the view I did this: @livewire('quality-form', ['quality' => $quality])

livewire.quality-form

        <form
            wire:submit.prevent="submitForm"
            action="{{ route('quality.store') }}"
            method="POST"
        >
        @csrf
            <input
                wire:model.lazy="quality"
                type="text"
                name="quality"
                value="{{ old('quality') ?? $quality->quality }}"
                placeholder="New quality"
            >
                @error('quality')
				...
                @enderror <!-- quality end -->
            <div>
                <button
                    type="submit">
                    Add
                </button>
            </div>
        </form> <!-- quality form end -->

QualityForm.php

class QualityForm extends Component
{
    public $quality;

    protected $rules = [
        'quality' => 'required|min:6',
    ];

    public function submitForm()
    {
        $qualities = Quality::create([
            'user_id' => Auth::user()->id,
            'quality' => $this->quality
        ]);

        $this->validate();

        $this->reset();
    }

    public function render()
    {
        return view('livewire.quality-form');
    }
}

In the view I have a @foreach in this way:

@foreach ($profile as $profile)
            <div>
                <div>
                    <img src="will use this space later for the profile table" alt="profile picture">
                    @livewire('quality-form', ['quality' => $quality])
                </div>
            </div> <!-- profile picture & qualities end -->
			...
@endforeach

Is the $quality variable here getting in the way of the foreach given that in fact, I do not have a $quality variable anywhere on my ProfileController? How could I use the $quality variable from the Livewire class?

ProfileController

    public function index()
    {
        $qualities = Auth::user()->qualities;

        return view('profile.index', compact('qualities'));
    }

The other instance I was using $quality was on QualityController store method and that worked

    public function store(Quality $quality)
    {
        $quality = request()->validate([
            'quality' => ['required', 'string'],
        ]);

        $quality['user_id'] = auth()->id();

        $qualityObject = new Quality($quality);
        $qualityObject->save();

        return redirect('/profile')->with('new_quality', 'Keep it up!');
    }
0 likes
12 replies
idew's avatar

You don't need to pass in $quality in the foreach since it's being created inside the Livewire component. You can just do @livewire('quality-form').

warpig's avatar
Level 12

@idew

Trying to get property 'quality' of non-object (View: /Users/$USER/Projects/15bucks/liveport/resources/views/livewire/quality-form.blade.php) 

It's pointing the $qualities from the form, on quality-form.blade.php this one:

            <input
                wire:model.lazy="quality"
                type="text"
                name="quality"
                value="{{ old('quality') ?? $quality->quality }}"
                placeholder="New quality"
            >
idew's avatar

@warpig In Livewire setting the value that way is no longer necessary. You can remove the value attribute. wire:model takes care of it for you.

1 like
warpig's avatar
Level 12

@idew Ah, didn't know that, good feature for sure. Problem is I can't see the item being listed on the page unless I refresh the page, the form seems to work, how do I make it "appear" as I submit the form?

I opened the Console tab and I see no errors 👀 everything seems to do fine.

@idew Do I need to have a way of returning the variable $quality from the class into profile.index?

1 like
idew's avatar

@warpig Awesome! Is the list within a Livewire component? You'll only get reactivity from within a component. When data changes only the component view will be re-rendered.

If it is within the component, make sure to add a wire:key attribute to each item element in the loop. This may be the reason it's not appearing - https://laravel-livewire.com/docs/2.x/troubleshooting.

warpig's avatar
Level 12

@idew The list is not within the component, I see what you mean I should pass {{ $quality }} but the list is inside of profile.index, how could I pass it there?

idew's avatar

@warpig You'll have to create a new parent component that contains the list, make sure your quality component has a key (@livewire('quality-form', key($loop->index))) and also emit a refresh event to the list from your submitForm method in the quality-form component.

List component -

class ProfileList extends Component {
	public $listeners = [
		'refreshProfileList' => '$refresh'
	];

	...
}

Then at the end of submitForm in QualityForm -

$this->emit('refreshProfileList');
idew's avatar

@warpig No, you wouldn't have to include the QualityForm. You'll want to add the emit within the QualityForm submitForm function. Yes! Those are great guides.

warpig's avatar
Level 12

@idew I found this on Scope on Events, https://laravel-livewire.com/docs/2.x/events#scope-to-parents so I added the listener like this:

ProfileList

class ProfileList extends Component
{   
    public Quality $quality;

    public $listeners = [
		'refreshProfileList' => '$refresh'
	];

    public function qualityList()
    {
        $this->quality = Quality::get();
    }

    public function render()
    {
        return view('livewire.profile-list');
    }
}

QualityForm

    public function submitForm()
    {
        $qualities = Quality::create([
            'user_id' => Auth::user()->id,
            'quality' => $this->quality
        ]);

        $this->validate();

        $this->reset();

        $this->emit('refreshProfileList');
    }

profile.index

I have this : @livewire('quality-form', key($loop->index)) does it loops over the Quality model from the QualityForm? so the $loop should be $quality and since I want the string, $quality->quality ? And then in this same view, pass the ProfileList component and inside of it do a @foreach like this? Sorry in advanced I have never done this before! ☺️

@foreach ($qualities as $quality)
<ul>
    <li>
        {{ $quality->quality }}
        <span>
            @include('qualities.destroy')
        </span>
    </li>
</ul>
@endforeach
warpig's avatar
Level 12

@idew I got the functionality working, I submit the form and as soon as i hit the "Add" button I see the list getting refreshed, but the qualities list is shown as multiple arrays like this, how do I make this look nicer, I'd want the "quality" field.

    [{"id":1,"user_id":1,"quality":"Corporis amet aut.","created_at":"2021-12-14T06:39:46.000000Z","updated_at":"2021-12-14T06:39:46.000000Z"},{"id":2,"user_id":1,"quality":"Consequuntur non ut odio.","created_at":"2021-12-14T06:39:46.000000Z","updated_at":"2021-12-14T06:39:46.000000Z"},{"id":3,"user_id":1,"quality":"Repudiandae eum consectetur.","created_at":"2021-12-14T06:39:46.000000Z","updated_at":"2021-12-14T06:39:46.000000Z"},{"id":4,"user_id":1,"quality":"Eum doloremque vero aliquam.","created_at":"2021-12-14T06:39:46.000000Z","updated_at":"2021-12-14T06:39:46.000000Z"},{"id":6,"user_id":1,"quality":"nfjekmdsdsf","created_at":"2021-12-14T06:41:11.000000Z","updated_at":"2021-12-14T06:41:11.000000Z"},{"id":7,"user_id":1,"quality":"fasdsdfsd","created_at":"2021-12-14T06:45:29.000000Z","updated_at":"2021-12-14T06:45:29.000000Z"},{"id":8,"user_id":1,"quality":"fadsfadsd","created_at":"2021-12-14T06:47:59.000000Z","updated_at":"2021-12-14T06:47:59.000000Z"},{"id":9,"user_id":1,"quality":"qualities","created_at":"2021-12-14T06:48:50.000000Z","updated_at":"2021-12-14T06:48:50.000000Z"}]

In the view the child component is @livewire('quality-form', key($qualities->quality)) And the parent is: @livewire('profile-list')

Inside the parent, profile-list im only returning the $quality variable

<ul>
    <li>
        {{ $quality }}
        <span 
            x-show="show" 
            style="display: none;"
        >
            {{-- @include('qualities.destroy') --}}
        </span>
    </li>
</ul>

I am returning that collection through the parent component, ProfileList in this way:

    public function render()
    {
        return view('livewire.profile-list', [
            'quality' => Quality::get()
        ]);
    }
idew's avatar

@warpig Nice! Looks like you'll want something like this -

<ul>
	@foreach($quality as $quality) 
    <li>
        {{ $quality->quality }}
        <span 
            x-show="show" 
            style="display: none;"
        >
            {{-- @include('qualities.destroy') --}}
        </span>
    </li>
	@endforeach
</ul>

Also, might be nice to pass $quality to the template in ProfileList as $qualities since it's a collection to avoid confusion.

Please or to participate in this conversation.