Introducing BladeX View Models
Earlier today we released BladeX, a package that allows you to use Blade components using a Vue inspired syntax. Read all about it in my previous blogpost.
In the latest North Meets South podcast Jacob and Michael discussed BladeX and wondered if the package could be married with view models or Laravel's 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.
What are your thoughts on "Introducing BladeX View Models"?