Back to Course |
Livewire 3 From Scratch: Practical Course

Property Attributes: Locked, URL, Computed

Livewire 3 was released with a few features using PHP Attributes on top of Component properties. In this lesson, let's look at them.


Locked Properties

Livewire properties can be modified on both the frontend and backend. Sometimes this could be a security breach if someone tries to change the input value in their browser console. To prevent it, we can lock public properties.

To lock a public property, you must add a #[Locked] attribute.

use Livewire\Attributes\Locked;
 
class ShowPost extends Component
{
#[Locked]
public int $id;
 
public function mount($postId): void
{
$this->id = $postId;
}
 
// ...
}

If you try to modify the $id property, Livewire will throw an Exception.

locked property exception

When using Model as a property, Livewire automatically will protect model's ID.

use App\Models\Post;
 
class ViewPost extends Component
{
public Post $post;
 
public function mount(Post $post): void
{
$this->post = $post;
}
 
// ...
}

Properties with URL Attribute

Sometimes you might want to store component's properties in the URL. For example, when building a search or table filtering.

Let's return to a ShowPosts Livewire component and add a simple search by title.

app/Livewire/ShowPosts.php:

class ShowPosts extends Component
{
public string $search = '';
 
public function render(): View
{
return view('livewire.show-posts', [
'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(),
]);
}
}

resources/views/livewire/show-posts.blade.php:

<div class="py-12">
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm dark:bg-gray-800 sm:rounded-lg">
<div class="p-6 text-gray-900 space-y-1 dark:text-gray-100">
 
<input type="text" wire:model.live="search" class="block mb-2 w-full border-gray-300 rounded-md shadow-sm">
 
@foreach($posts as $post)
<h2 class="text-lg">{{ $post->title }}</h2>
@endforeach
 
</div>
</div>
</div>
</div>

search input

Now to add ?search= to the URL, we need to add a #[Url] attribute to the search property.

app/Livewire/ShowPosts.php:

use Livewire\Attributes\Url;
 
class ShowPosts extends Component
{
#[Url]
public string $search = '';
 
public function render(): View
{
return view('livewire.show-posts', [
'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(),
]);
}
}

After writing ab into a search input, the URL bar in the browser should show:

https://example.com/posts?search=ab

If you want to alias search into, for example, q, the #[Url] attribute accepts parameter as.

use Livewire\Attributes\Url;
 
class ShowPosts extends Component
{
#[Url(as: 'q')]
public string $search = '';
 
public function render(): View
{
return view('livewire.show-posts', [
'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(),
]);
}
}

Now instead of ?search=ab, you will see ?q=ab.

By default, Livewire replaces the URL. This means that the browser's back button won't work. To make it work, you must set the history parameter to true.

use Livewire\Attributes\Url;
 
class ShowPosts extends Component
{
#[Url(history: true)]
public string $search = '';
 
public function render(): View
{
return view('livewire.show-posts', [
'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(),
]);
}
}

Computed Properties

Computed Properties are underrated and not used or used in the wrong place. Let's see how to define them and where they could be used.

To create a Computed Property, we must add the #[Computed] attribute to the method in the Livewire component.

use Livewire\Attributes\Computed;
use Illuminate\Support\Collection;
 
class ShowComments extends Component
{
public Post $post;
 
public function mount(Post $post): void
{
$this->post = $post;
}
 
#[Computed]
public function comments(): Collection
{
return $this->post->comments()->get();
}
 
public function render(): View
{
return view('livewire.show-comments');
}
}

We need to add the $this object to access Computed Property. So in this example, in the Blade file, we would do $this->comments.

<div class="space-y-1">
@foreach($this->comments as $comment)
<p>{{ $comment->body }}</p>
@endforeach
</div>

When to use? One great usage of Computed Properties is to reduce queries. For example, if we want to show comments only for authenticated users, we would wrap foreach with a @auth directive.

<div class="space-y-1">
@auth
@foreach($this->comments as $comment)
<p>{{ $comment->body }}</p>
@endforeach
@endauth
</div>

In this situation, when Computed Property is used, and the user can't view comments, the query isn't even made.

computed property no query for guest But when the user is authenticated, the comments are only fetched from the DB.

computed property query for auth user