jacobcollinsdev's avatar

Livewire - Bind to Model Relationship

I have a Member model which has a hasOne relationship with a MedicalNote model.

I want the ability to edit the medical note from within a form, so far I have:

  1. Set up a relationship in the Member class:
public function medicalNote()
    {
        return $this->hasOne(MedicalNote::class);
    }
  1. Added a validation entry in the $rules property for the EditMember livewire class:
protected $rules = [
        'member.medicalNote.note' => 'string'
    ];
  1. Bound the data inside a form input in a edit-member.blade.php view:
<input type="text" class="border-0 border-b border-gray-300 rounded py-1 text-sm col-span-4" wire:model="member.medicalNote.note"/>

I've been following the documentation set out here: https://laravel-livewire.com/docs/2.x/properties#binding-models

However, I think I may have overlooked something or am applying it incorrectly. When the Edit Member view loads, the Members' related medical note information is not appearing in the input element.

I appreciate any feedback!

0 likes
10 replies
Nakov's avatar

So you have a member_id in your member_notes table, right?

Have you checked if just the relation works at all?

jacobcollinsdev's avatar

@Nakov correct, there is a member_id column. The relation does work, as I can see it when I dump($member->medicalNote->note) into the view.

Nakov's avatar

@jacobcollinsdev any chance you can show your full component code? How is the member passed, loaded? Because I think that you syntax is right, now it won't show unless the eager load of the medicalNote hasn't happened yet I guess.

jacobcollinsdev's avatar

Sure, thanks for replying.

MemberDetails.php (i.e. Edit Member)

<?php

namespace App\Http\Livewire;

use App\Models\Contact;
use App\Models\Member;
use Livewire\Component;

class MemberDetails extends Component
{
    public $member_id = 1;
    public Member $member;
    public Contact $contact;
    public $showMember = false;
    protected $listeners = ['displayMember' => 'displayMember', 'reRenderParent' => 'reRenderParent'];

    protected $rules = [
        'member.date_of_birth' => 'required|date',
        'member.joined_at' => 'required|date',
        'member.school' => 'required',
        'member.address' => 'required',
        'member.email' => 'string',
        'member.info' => 'string',
        'member.source' => 'string',
        'member.medicalNote.note' => 'string'
    ];

    public function render()
    {
        return view('livewire.member-details');
    }

    public function displayMember($member_id)
    {
        $this->member_id = $member_id;
        $this->member = Member::where('id', $this->member_id)->first();
        $this->showMember = true;
    }

    public function save()
    {
        $this->validate();
        $this->member->save();
    }

    public function reRenderParent()
    {
        $this->render();
    }
}

member-details.blade.php

<aside 
    x-data="{ open: @entangle('showMember') }" >
    
@if ($member)

    <div>
        <h1 class="font-bold text-xl mb-4">{{ $member->first_name }} {{ $member->last_name }}</h1>
        <form wire:submit.prevent="save">
		    <input type="text" wire:model="member.medicalNote.note" />
		</form>
	</div>
				
@endif

</aside>

The member_id is received from another component that passes the id like so:

public function setMember($member_id)
    {
        $this->member_id = $member_id;
        $this->show_member = true;
        $this->emit('displayMember', $member_id); // this triggers displayMember in the MemberDetails.php component
    }
Nakov's avatar

@jacobcollinsdev sorry I didn't get a notification that you responded. Make sure you mention me when replying so that I get notified.

And what if you eager load the medicalNote ?

        $this->member = Member::with('medicalNote')->find($this->member_id);
jacobcollinsdev's avatar

@Nakov Unforunately, no luck eager loading the medical note. Out of curiousity, will this throw any errors for members that don't have a medical note?

Nakov's avatar

@jacobcollinsdev it might, because you will try to access a property on a null object. You can prevent that by always returning a default medical note like this:

public function medicalNote()
    {
        return $this->hasOne(MedicalNote::class)->withDefault();
    }
NorahDaniels's avatar

I found out that you can include data from One to One relationships in your form. But I cant get it to work.

In my Model I have:

public function info() { return $this->hasOne('UserInfo', 'users_id', 'id'); omegle.2yu.co } And when I

dd($user->info->town); I get my String as expected.

But in my view there is nothing in my input field:

{{ Form::model($user, ['route' => ['user.edit.submit', $user->id], 'method' => 'POST']) }}

{{ Form::label('info[town]', 'Town') }} {{ Form::text('info[town]'); }}

{{ Form::close(https://www.echat.date/omegle) }} I couldnt find this feature in the docs. Has anyone https://omegle.love used this before and can help me out?

Expream's avatar

Hello guys! Any solution to this request? Have the same problem as topic starter.

kokoshneta's avatar

@Expream Nope, no solution – it doesn’t work. Livewire doesn’t support data binding with camelCase relationship names, because during hydration and dehydration, Laravel converts camelCase to snake_case, which breaks things.

There is a workaround, though: rename the relationship method in your model to something that’s all lowercase (or snake_case, I think); e.g., for @jacobcollinsdev, the relationship method could look like this:

public function medicalnote() { // either this
public function medical_note() { // or this
	return $this->hasOne(MedicalNote::class);
}

Please or to participate in this conversation.