★ Introducing BladeX View Models
Tags: laravel, php
Published: 2020-01-02 23:04:26

---
title: ★ Introducing BladeX View Models
published: true
date: 2018-09-30 22:00:00 UTC
tags: laravel, php
canonical_url: https://freek.dev/1170-introducing-bladex-view-models
---

Earlier today we released [BladeX](https://github.com/spatie/laravel-blade-x), a package that allows you to use [Blade components](https://laravel.com/docs/master/blade#components-and-slots) using a Vue inspired syntax. Read all about it in [my previous blogpost](https://freek.dev/use-custom-html-components-in-your-blade-views).

In the latest [North Meets South podcast](https://www.northmeetssouth.audio/48) [Jacob](https://twitter.com/jacobbennett) and [Michael](https://twitter.com/michaeldyrynda) discussed BladeX and wondered if the package could be married with [view models](https://github.com/spatie/laravel-view-models) or [Laravel's View Composers](https://laravel.com/docs/master/views#view-composers). Our team discussed this too last Friday but we decided to release the core features of BladeX first. After the release today it became apparent pretty fast that we needed some sort of view model support in our projects too. So we got to work!

I'm happy to share that v1.1 of BladeX now has support for view models. In this blogpost I'd like to walk you through the feature.

### Using view models #

View models are used to transform data before a BladeX component is rendered. Let's make the usage clear with an example. We are going to render a `select` element to render a `select` element with some countries.

To make a BladeX component use a view model you need to tack on a call to `viewModel` when you register the component. The class name of the view model is pass to that method.

```
BladeX::component('select-field')->viewModel(SelectViewModel::class);
```

Before reviewing the contents of the component and the view model itself, let's take a look first on how we are going to use component.

```
@php
// in a real app this data would most likely come from a controller
$countries = [
    'be' => 'Belgium',
    'fr' => 'France',
    'nl' => 'The Netherlands',
];
@endphp

<select-field name="countries" :options="$countries" selected="fr" />
```

Next, let's take a look at what the `SelectViewModel::class` looks like:

```
class SelectViewModel extends ViewModel
{
    /** @var string */
    public $name;

    /** @var array */
    public $options;

    /** @var string */
    public $selected;

    public function __construct(string $name, array $options, string $selected = null)
    {
        $this->name = $name;

        $this->options = $options;

        $this->selected = $selected;
    }

    public function isSelected(string $optionName): bool
    {
        return $optionName === $this->selected;
    }
}
```

Notice that this class extends `\Spatie\BladeX\ViewModel`. Every attribute on `select-field` is being passed to the constructor. This passing is being done name based, the `name` attribute will be passed to a constructor argument named `$name`, the `options` attribute will be passed to `$options` and so on. Any other argument will be resolved out of the ioc container. This can be handy for dependency injection.

All public properties and methods of the view model will be passed to the Blade view that will render the `select-field` component. Public methods will be available in as a closure stored in the variable that is named after the public method in view model. This is what that view looks like.

```
<select name="{{ $name }}">
    @foreach($options as $value => $label)
        <option {!! $isSelected($value) ? 'selected="selected"' : '' !!} name="{{ $value }}">{{ $label }}</option>
    @endforeach
</select>
```

When rendering the BladeX component, this is the output:

```
<div>
  <select name="countries">
    <option name="be">Belgium</option>
    <option selected="selected" name="fr">France</option>
    <option name="nl">The Netherlands</option>
  </select>
</div>
```

If you have any remarks of questions about this, let me know in the comments below.