---
title: "Livewire v3: Modelable, Events, and Data Sharing"
description: "Share dynamic attributes between parent and child components using Livewire Modelable, and share data between separate components thriftily with client side events."
---

# Livewire v3: Modelable, Events, and Data Sharing

![A bunch of Livewire-alien like creatures sharing strawberries and floating. Below them is a bunch of strawberry houses!](https://fly.io/laravel-bytes/modelable-events-data-livewire/assets/strawberry-estate-cover.webp)

[Annie Ruygt](https://annieruygtillustration.com/)

Need a place for your [Laravel app in the cloud](https://docs.fly.io/laravel)? Fly it with Fly.io, it’ll be up and running in minutes!

Oftentimes, we use drop-downs in combination with other html elements to make our website interactive.

One kind of interaction is inter-dependency amongst several drop-downs. This happens when changing a selected option of one drop-down affects the choices given for another drop-down. In our [last article](https://fly.io/laravel-bytes/dependent-dropdowns-livewire/), we created dynamic, inter-dependent drop-downs. These drop-downs were dynamically instantiable as they all used one Livewire component as template( *named `filter` component* ). Then, to allow inter-dependency among the drop-downs, we created another component called `filter-section` to manage data and data-dependency for each `filter` drop-down instance.

Another kind of interaction involves the drop-downs affecting other html elements, like say, filtering data on a table.

Of course, given the nature of dynamically instantiated elements, we need to be able to uniquely identify and track each drop-down instantiated. Furthermore, if our table element is found in a *separate* Livewire component, we need to find a way to share the data from each `filter` drop-down to the `table` component.

Today, we’ll get around this data sharing easily with [Livewire Modelable](https://livewire.laravel.com/docs/nesting#binding-to-child-data-using-wiremodel) *and* [client-side dispatched events](https://livewire.laravel.com/docs/nesting#improving-performance-by-dispatching-client-side).

—Let’s get to it!

## Dynamic Drop-Down Set Up

Let’s say we use a `filter-section` [component](https://livewire.laravel.com/docs/components) to manage a bunch of drop-downs. It would have a public attribute `$filters` that contains an [array of data](https://github.com/KTanAug21/SampleApp/blob/master/app/Livewire/FilterSection.php#L19) which we’ll use to initialize a bunch of drop-downs:

```
<!-- resources/livewire/filter-section.blade.php -->
<div>
    <button>Apply</button>
    @foreach( $filters as $key=> $filter )
        <livewire:filter
          :key="$key.now()"
          :label="$filter['label']"
          :options="$filter['options']"
        />
    @endforeach     
</div>
```

Notice however that each item initializes another Livewire component called `filter`. This component contains the template we use to create our drop-downs:

```
<!-- resources/views/livewire/filter.blade.php -->
<div>
  <!-- Show the label of the filter -->
  <label>{{ $label }}</label>

  <!-- Filter -->
  <select wire:model="value">
    @foreach( $options as $option )
      <option value="{{ $option['id'] }}">{{ $option['name'] }}</option>
    @endforeach
  </select>
</div>
```

Let’s say that the `$filters` array contains three drop-down data: “Offer Type”, “Property Type”, and “Sub Property Type”. We should get a view like so: ![A filter section containing a button labeled "Apply", and three drop-downs: "Offer Type", "Property Type", "Sub Property Type"](https://fly.io/laravel-bytes/modelable-events-data-livewire/assets/img_1.png?card)

We’re going to use these drop-downs to show filtered results in a table. The first thing we need to do, then, is to get the selected option of each filter drop-down.

How exactly do we do that?

## Uniquely Identifying Drop-Downs

In our setup, we have a parent component `filter-section`, and it dynamically initializes a bunch of child `filter` components through an array of data. Each `filter` component instance contains a drop-down element.

If we want to get the selected option for *each* drop-down, we’ll have to of course, uniquely identify each one. So, first, make sure that the `$filters` array includes a unique key value for each drop-down data. Then, we’ll need a ‘value’ attribute that will represent the option selected for each drop-down:

```
public function mount()
{
  $this->filters = [
+       'offer_type'=>[     // Unique key
            'label'=> 'OFFER TYPE',
            'options'=> OfferType::all()->toArray(),
+           'value' => 0    // Value attr
        ],
+        'property_type'=>[  // Unique key
            'label'=>'PROPERTY TYPE',
            'options'=> PropertyType::all()->toArray(),
+           'value' => 0  // Value attr
        ],
+        'sub_property_type'=>[ // Unique key
            'label'=>'SUB PROPERTY TYPE',
            'options'=> SubPropertyType::all()->toArray(),
+           'value'=>0   // Value attr
        ]
  ];
}
```

With this setup, we can refer to each drop-down’s selected value through the attribute `$filters.[drop_down_key].value`.

Now that we have an attribute name to identify each drop-down value, the next step is to *link* each attribute to its respective drop-down element in our view. In Livewire, we link server attributes with elements in the blade through the use of `wire:model` [directives](https://livewire.laravel.com/docs/properties#data-binding):

```
<!-- resources/livewire/filter-section.blade.php -->

@foreach( $filters as $key=> $filter )
  <livewire:filter
    ...
+   :wire:model="'filters.'.$key.'.value'"
  />
@endforeach     
```

*Usually* , that’s how we would link attributes to *html elements* . But notice that `filter-section` only has direct access to its `filter` child instances and not the drop-down elements we want to wire to.

This syntax then won’t work alone. Because, after all, how would Livewire know which element in the `filter` component’s blade should it wire an attribute with?

## Enter Modelable: Linking Parent and Child Attributes

Livewire provides us with its [Modelable attribute](https://livewire.laravel.com/docs/nesting#binding-to-child-data-using-wiremodel) feature. It allows us to match a parent wire:model with any of its child components’ attributes, and ultimately, that child component’s html element.

With it, we can have attributes in our parent component *in sync* with child components’ attributes!

Applying this directive is just a two-step process. The first step we’ve already done above, which is wiring a specific `filter-section`‘s attribute to the instance of its `filter` child component.

Next, we need to let the `filter` component know where to map the wired model it received. We can do this by attaching “Modelable” to the attribute we want to link with. Since our `filter` component has `$value` wired to its select element, we want to specifically attach to *this* attribute:

```
/* app/Livewire/Filter.php */

+  use Livewire\Attributes\Modelable;

class Filter extends Component
{
+  #[Modelable] 
   public $value = '';
```

And that’s it! Now that we’ve attached Modelable to `$value` and wired it to the parent’s `$filters.[drop_down_key].value` attribute, any changes to `$value` would also be reflected in its corresponding `$filters.[drop_down_key].value`, thereby giving `filter-section` access to the drop-down values found in each instantiation of `filter` child components.

Neat, right?

Let’s test that out with a little bit of Alpine and console logging. From our parent component, `filter-section`, we have an Apply button. When the user clicks on this button, we can log the value of a specific drop-down:

```
<button
  x-on:click="console.log( $wire.filters.sub_property_type.value )"
>
```

![Selecting different options in "Sub Property Type" drop-down and clicking on the Apply button logs the selected values' id in the browser console.](https://fly.io/laravel-bytes/modelable-events-data-livewire/assets/gif_1.gif?card) And…tada! Clicking on the Apply button shows us the value of our intended drop-down!

## Sharing Data Outside

Now that we have a way to get each selected drop-down data, let’s finish this by sharing them to another component — our `table` component.

The `table` component will make use of Livewire’s [WithPagination](https://livewire.laravel.com/docs/pagination#basic-usage) trait to display rows of our data. And to allow filtering, we’ll also add in a public attribute `$filterList` which we’ll pass to the pagination query:

```
/* app/Livewire/Table.php */
use Livewire\WithPagination;

class Table extends Component
{
  use WithPagination;

  public $filters = [];

  public function render()
  {
      return view('livewire.property-table',[
          'rows'=>Property::filter( $this->filters )->paginate(10)
      ]);
  }
}
```

Then, with the data passed through the `$rows` variable in `render()`, we create the view which includes the data and pagination links:

```
<!-- resources/views/livewire/table.blade.php -->
<table>
    <thead>
        <tr>
            <th class="bg-blue-100 border text-left px-8 py-4">Name</th>
            <th class="bg-blue-100 border text-left px-8 py-4">Price</th>
        </tr>
    </thead> 
    <tbody>
        @foreach( $rows as $row )
          <tr>
              <td>{{$row['name']}}</td>
              <td>{{$row['price']}}</td>
          </tr>
        @endforeach
    </tbody>
    {{ $rows->links() }}
</table>
```

Now if we declare this table component in our main page, we should finally get a complete setup like so: ![A page that contain a filters section with three dropdowns, and a tabletion below showing 10 out of 30 rows of data.](https://fly.io/laravel-bytes/modelable-events-data-livewire/assets/img_2.png?card)

The final question in this article we’ll be answering is, how do we pass data from one component, to another?

## Client-Dispatched Events

To share data from one component to another, we usually [dispatch events](https://livewire.laravel.com/docs/events) in Livewire. Livewire components can then listen to these events and react accordingly.

To immediately *and* thriftily dispatch an event, we’ll [dispatch one](https://livewire.laravel.com/docs/events#dispatching-events-from-blade-templates) in our blade template.

When the user clicks on the Apply button in our `filter-section` component, we want to take the selected drop-downs data it has access to, and share these with the `table` component.

To do so, we can dispatch an event containing each drop-down’s selected value from a button click:

```
<!-- resources/views/livewire/filter-section.blade.php -->

<button 
  wire:click="$dispatch('apply-filter', { 
    offer_type_id: $wire.filters.offer_type.value,
    property_type_id: $wire.filters.property_type.value,
    sub_property_type_id: $wire.filters.sub_property_type.value,
  })"
>Apply</button>
```

Since this `apply-filter` event is available on our entire page, we can listen to this from our `table` component’s view( or *any* other component really! ) and *react* .

We can take the selected drop-down data from `event.detail`, and directly update the `$filtersList` variable in our `table` component with it:

```
<script>
window.addEventListener('apply-filter', event => {
    console.log( 'received event from apply filter in table!', event.detail );
+   @this.set( 'filtersList', event.detail );
});
</script>
```

And that’s it! We’ve shared our selected drop-down values with the `table` component!

## Fly.io ❤️ Laravel

Fly your servers close to your users—and marvel at the speed of close proximity. Deploy globally on Fly in minutes!

[Deploy your Laravel app! →](https://docs.fly.io/laravel)

Once Livewire updates the `$filtersList` attribute in the server using `@this.set()`, Livewire would afterward call the `render()` method of `table` component due to an update to its public attribute.

This time, the `$filtersList` will contain data the user selected, and will now be used to filter the rows for our table! ![Clicking on the Apply button triggers a change in the rows of data contained in the table.](https://fly.io/laravel-bytes/modelable-events-data-livewire/assets/gif_3.gif?card)
