Reputation: 69
I am currently working on a part of a Laravel app that tracks reading progress for books. I am using Livewire and have two components. The main component is the BookManager class, which shows all the books and updates when books are updated or deleted.
class BookManager extends Component
{
public $name;
public $books;
protected $listeners = ['refreshBookManager' => '$render'];
public function mount()
{
$this->books = Book::all();
}
public function render()
{
return view('livewire.book-manager');
}
}
It loops over all the books in the blade-file and renders a BookField component for each book.
// livewire/book-manager.blade.php
<div>
<table class="table table-striped">
@foreach($books as $book)
<livewire:book-field :book="$book" :key="$book->id" />
@endforeach
</table>
</div>
I figured that each BookField component could keep track of its own individual Book and so this is where the user can update their progress for each book individually or mark the book as finished.
class BookField extends Component
{
public $pages_read;
public Book $book;
public function render()
{
return view('livewire.book-field');
}
public function update()
{
//...
}
public function finish()
{
//...
}
}
// livewire/book-field.blade.php
<div>
<tr>
<td>
{{$book->name}}
</td>
<td>
<progress value="{{ ($book->pages_read / $book->pages_total) * 100 }}" max="100"></progress>
</td>
<td>
<input class="form-control" type="number" wire:model.defer="pages_read" placeholder="{{$book->pages_read}}">
</td>
<td>
/ {{$book->pages_total}}
</td>
<td width="15%">
<button class="btn btn-primary" type="submit" wire:click="update()">Update</button>
<button class="btn btn-success" type="submit" wire:click="finish()">Finish</button>
</td>
</tr>
</div>
I've had a hard time trying to get each BookField to be bound properly to their Book model. The error I get when I click the update button is:
Livewire\Exceptions\MethodNotFoundException
Unable to call component method. Public method [update] not found on component: [book-manager]
I get a similar error for the properties:
Livewire\Exceptions\PropertyNotFoundException
Property [$pages_read] not found on component: [book-manager]
All the BookFields are rendered successfully with the correct information for their particular Book model. When I dump the $book variable in a BookField component I get the correct Book instance with all its properties and methods.
But for some reason it seems to be looking for the $pages_read property or the update() or finish() methods on the parent class instead of its own instance of the BookField class. I don't have enough experience with Livewire to know what could be causing this problem or how to fix it, so if someone could help me out that would be much appreciated.
Upvotes: 4
Views: 4833
Reputation: 56
Wrapping a table row with the div causes this error.
Livewire required that your blade template has a single root, so, removing the wrapping "div" tag and using the "tr" tag as root fixes it.
So, your code on livewire/book-field.blade.php should be as below:
<tr>
<td>
{{$book->name}}
</td>
<td>
<progress value="{{ ($book->pages_read / $book->pages_total) * 100 }}" max="100"></progress>
</td>
<td>
<input class="form-control" type="number" wire:model.defer="pages_read" placeholder="{{$book->pages_read}}">
</td>
<td>
/ {{$book->pages_total}}
</td>
<td width="15%">
<button class="btn btn-primary" type="submit" wire:click="update()">Update</button>
<button class="btn btn-success" type="submit" wire:click="finish()">Finish</button>
</td>
</tr>
Upvotes: 4
Reputation: 11
Make sure view is wrapped with div TAG view of the component should have tag DIV
Upvotes: 1
Reputation: 211
Try using :wire:key
and not :key
, here:
instead of:
<livewire:book-field :book="$book" :key="$book->id" />
use
<livewire:book-field :book="$book" :wire:key="$book->id" />
Upvotes: -1