Properties
- Introduction
- Initializing Properties
- Data Binding
- Binding Directly To Model Properties
- Custom (Wireable) Properties
- Computed Properties
Introduction
Livewire components store and track data as public properties on the component class.
1class HelloWorld extends Component2{3 public $message = 'Hello World!';4 ...
Public properties in Livewire are automatically made available to the view. No need to explicitly pass them into the view (although you can if you want).
1class HelloWorld extends Component2{3 public $message = 'Hello World!';4}
1<div>2 <h1>{{ $message }}</h1>3 <!-- Will output "Hello World!" -->4</div>
Important Notes
Here are three ESSENTIAL things to note about public properties before embarking on your Livewire journey:
- Property names can't conflict with property names reserved for Livewire (e.g.
rules
ormessages
) - Data stored in public properties is made visible to the front-end JavaScript. Therefore, you SHOULD NOT store sensitive data in them.
- Properties can ONLY be either JavaScript-friendly data types (
string
,int
,array
,boolean
), OR one of the following PHP types:Stringable
,Collection
,DateTime
,Model
,EloquentCollection
.
protected
and private
properties DO NOT persist between Livewire updates. In general, you should avoid using them for storing state.You should also note that while
null
data type is Javascript-friendly, public
properties set to null
DO NOT persist between Livewire updates.
Initializing Properties
You can initialize properties using the mount
method of your component.
1class HelloWorld extends Component2{3 public $message;4 5 public function mount()6 {7 $this->message = 'Hello World!';8 }9}
Livewire also makes a $this->fill()
method available to you for cases where you have to set lots of properties and want to remove visual noise.
1public function mount()2{3 $this->fill(['message' => 'Hello World!']);4}
Additionally, Livewire offers $this->reset()
and $this->resetExcept()
to programmatically reset public property values to their initial state. This is useful for cleaning input fields after performing an action.
1public $search = ''; 2public $isActive = true; 3 4public function resetFilters() 5{ 6 $this->reset('search'); 7 // Will only reset the search property. 8 9 $this->reset(['search', 'isActive']);10 // Will reset both the search AND the isActive property.11 12 $this->resetExcept('search');13 // Will only reset the isActive property (any property but the search property).14}
Data Binding
If you've used front-end frameworks like Vue, or Angular, you are already familiar with this concept. However, if you are new to this concept, Livewire can "bind" (or "synchronize") the current value of some HTML element with a specific property in your component.
1class HelloWorld extends Component2{3 public $message;4}
1<div>2 <input wire:model="message" type="text">3 4 <h1>{{ $message }}</h1>5</div>
When the user types something into the text field, the value of the $message
property will automatically update.
Internally, Livewire will listen for an input
event on the element, and when triggered, it will send an AJAX request to re-render the component with the new data.
wire:model
to any element that dispatches an input
event. Even custom elements, or third-party JavaScript libraries.
Common elements to use wire:model
on include:
Element Tag |
---|
<input type="text"> |
<input type="radio"> |
<input type="checkbox"> |
<select> |
<textarea> |
Binding Nested Data
Livewire supports binding to nested data inside arrays using dot notation:
1<input type="text" wire:model="parent.message">
Debouncing Input
By default, Livewire applies a 150ms debounce to text inputs. This avoids too many network requests being sent as a user types into a text field.
If you wish to override this default (or add it to a non-text input), Livewire offers a "debounce" modifier. If you want to apply a half-second debounce to an input, you would include the modifier like so:
1<input type="text" wire:model.debounce.500ms="name">
Lazy Updating
By default, Livewire sends a request to the server after every input
event (or change
in some cases). This is usually fine for things like <select>
elements that don't typically fire rapid updates, however, this is often unnecessary for text fields that update as the user types.
In those cases, use the lazy
directive modifier to listen for the native change
event.
1<input type="text" wire:model.lazy="message">
Now, the $message
property will only be updated when the user clicks away from the input field.
Deferred Updating
In cases where you don't need data updates to happen live, Livewire has a .defer
modifier that batches data updates with the next network request.
For example, given the following component:
1<input type="text" wire:model.defer="query">2<button wire:click="search">Search</button>
As the user types into the <input>
field, no network requests will be sent. Even if the user clicks away from the input field and onto other fields on the page, no requests will be sent.
When the user presses "Search", Livewire will send ONE network request that contains both the new "query" state, AND the "search" action to perform.
This can drastically cut down on network usage when it's not needed.
Binding Directly To Model Properties
If an Eloquent model is stored as a public property on a Livewire component, you can bind to its properties directly. Here is an example component:
1use App\Post; 2 3class PostForm extends Component 4{ 5 public Post $post; 6 7 protected $rules = [ 8 'post.title' => 'required|string|min:6', 9 'post.content' => 'required|string|max:500',10 ];11 12 public function save()13 {14 $this->validate();15 16 $this->post->save();17 }18}
1<form wire:submit.prevent="save">2 <input type="text" wire:model="post.title">3 4 <textarea wire:model="post.content"></textarea>5 6 <button type="submit">Save</button>7</form>
Notice in the above component we are binding directly to the "title" and "content" model attributes. Livewire will take care of hydrating and dehydrating the model between requests with the current, non-persisted data.
Additionally, you can bind to models within an Eloquent Collection.
1use App\Post; 2 3class PostForm extends Component 4{ 5 public $posts; 6 7 protected $rules = [ 8 'posts.*.title' => 'required|string|min:6', 9 'posts.*.content' => 'required|string|max:500',10 ];11 12 public function mount()13 {14 $this->posts = auth()->user()->posts;15 }16 17 public function save()18 {19 $this->validate();20 21 foreach ($this->posts as $post) {22 $post->save();23 }24 }25}
1<form wire:submit.prevent="save"> 2 @foreach ($posts as $index => $post) 3 <div wire:key="post-field-{{ $post->id }}"> 4 <input type="text" wire:model="posts.{{ $index }}.title"> 5 6 <textarea wire:model="posts.{{ $index }}.content"></textarea> 7 </div> 8 @endforeach 9 10 <button type="submit">Save</button>11</form>
Livewire also supports binding to relationships on Eloquent models like so:
1class EditUsersPosts extends Component 2{ 3 public User $user; 4 5 protected $rules = [ 6 'user.posts.*.title' 7 ]; 8 9 public function save()10 {11 $this->validate();12 13 $this->user->posts->each->save();14 }15}
1<div> 2 @foreach ($user->posts as $i => $post) 3 <input type="text" wire:model="user.posts.{{ $i }}.title" /> 4 5 <span class="error"> 6 @error('user.posts.'.$i.'.title') {{ $message }} @enderror 7 </span> 8 @endforeach 9 10 <button wire:click="save">Save</button>11</div>
Custom (Wireable) Properties
Sometimes you may want to set a component property to a non-model object that's available inside your app, like a DTO (Data Transfer Object).
For example, let’s say we have a custom object in our app called Settings
. Rather than just store settings data as a plain array on our Livewire component, we can attach associated behavior to this data with a convenient wrapper object or DTO like Settings
:
1class Settings implements Livewire\Wireable 2{ 3 public $items = []; 4 5 public function __construct($items) 6 { 7 $this->items = $items; 8 } 9 10 ...11 12 public function toLivewire()13 {14 return $this->items;15 }16 17 public static function fromLivewire($value)18 {19 return new static($value);20 }21}
Now you can freely use this object as a public property of your component as long as that object implements the Livewire\Wireable
interface AND the property is typehinted like so:
1class SettingsComponent extends Livewire\Component 2{ 3 public Settings $settings; 4 5 public function mount() 6 { 7 $this->settings = new Settings([ 8 'foo' => 'bar', 9 ]);10 }11 12 public function changeSetting()13 {14 $this->settings->foo = 'baz';15 }16}
And as you can see, changes to the component are persisted between requests because, with Wireable
, Livewire knows how to “dehydrate” and “re-hydrate” this property on your component.
If words like “hydrate” or “dehydrate” in the context of Livewire are fuzzy for you, give this post a quick read.
Computed Properties
Livewire offers an API for accessing dynamic properties. This is especially helpful for deriving properties from the database or another persistent store like a cache.
1class ShowPost extends Component2{3 // Computed Property4 public function getPostProperty()5 {6 return Post::find($this->postId);7 }
Now, you can access $this->post
from either the component's class or Blade view:
1class ShowPost extends Component 2{ 3 public $postId; 4 5 public function getPostProperty() 6 { 7 return Post::find($this->postId); 8 } 9 10 public function deletePost()11 {12 $this->post->delete();13 }14}
1<div>2 <h1>{{ $this->post->title }}</h1>3 ...4 <button wire:click="deletePost">Delete Post</button>5</div>