go to part...
Here's an example of a single form field from the default login.blade.php
view:
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
This is massive. Imagine having 5-10 inputs like this in a single view file? Not only does it look gross for something as simple as an input field, it is also hard to read and is error prone. To add a new field you'd probably copy an existing block and then manually rename all the instances of email
to, say, username
- easy to make a mistake or to miss something there.
We can't strip this HTML since this is all essential for the field to look and work right. What we can do though is extract this to a Blade component and make it more general.
Let's do exactly that. Let's create a folder to store our components, for example resources/views/components/form
. Then create a file inside that folder called input.blade.php
. Grab the HTML above and paste it in.
We'll start by replacing all the occurrences of email
to a variable called $name
. This is the result:
<div class="form-group{{ $errors->has($name) ? ' has-error' : '' }}">
<label for="{{ $name }}" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="{{ $name }}" type="email" class="form-control" name="{{ $name }}" value="{{ old($name) }}" required autofocus>
@if ($errors->has($name))
<span class="help-block">
<strong>{{ $errors->first($name) }}</strong>
</span>
@endif
</div>
</div>
Now let's make the label editable and optional:
@if (isset($label))
<label for="{{ $name }}" class="col-md-4 control-label">{{ $label }}</label>
@endif
The type of the input should be flexible as well with text
being the default. The placeholder should be optional. This is what the input
element should look after these modifications:
<input id="{{ $name }}"
type="{{ isset($type) ? $type : 'text' }}"
class="form-control"
name="{{ $name }}"
placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
value="{{ old($name) }}" required autofocus>
required autofocus
should be removed as well to make the component more generic. Instead, we're going to add a variable called attributes
to provide the ability to add any additional attributes we might need.
<input id="{{ $name }}"
type="{{ isset($type) ? $type : 'text' }}"
class="form-control"
name="{{ $name }}"
placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
value="{{ old($name) }}"
{{ isset($attributes) ? $attributes : '' }}>
This is already great, but I'd like to work on the value
attribute a little bit more. We'll accept a value from a Model object if there is an object passed to the component. This allows us to use the same component (and ultimately the same view) for both create
and edit
forms.
<input id="{{ $name }}"
type="{{ isset($type) ? $type : 'text' }}"
class="form-control"
name="{{ $name }}"
placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
value="{{
old($name) ?: (isset($object) ? $object->{$name} : '')
}}"
{{ isset($attributes) ? $attributes : '' }}>
What we do here is we set the value to the old()
value if there's any. If there is none, we're trying to get the value from the provided object, otherwise we're setting the value to an empty string.
Finally, this is the complete result:
<div class="form-group{{ $errors->has($name) ? ' has-error' : '' }}">
@if (isset($label))
<label for="{{ $name }}" class="col-md-4 control-label">{{ $label }}</label>
@endif
<div class="col-md-6">
<input id="{{ $name }}"
type="{{ isset($type) ? $type : 'text' }}"
class="form-control"
name="{{ $name }}"
placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
value="{{
old($name) ?: (isset($object) ? $object->{$name} : '')
}}"
{{ isset($attributes) ? $attributes : '' }}>
@if ($errors->has($name))
<span class="help-block">
<strong>{{ $errors->first($name) }}</strong>
</span>
@endif
</div>
</div>
Let's go back to our login.blade.php
view. We can now replace the old HTML block with the email
input with this:
@component('components.form.input', [
'name' => 'email',
'label' => 'E-Mail Address',
])@endcomponent
Looks much nicer, more readble, and way more compact, doesn't it?
Another example. Imagine we have a single view file edit.blade.php
for creating and editing blog posts. You have to pass a $post
variable to this view in both create
and edit
methods of the controller, except there's no post in the create
method yet so you should simply pass null
. This is what the component for the title
field could look like:
@component('components.form.input', [
'name' => 'title',
'label' => 'Title',
'placeholder' => 'Enter the title of the blog post',
'object' => $post,
])@endcomponent
Final Words
Hopefuly you have an understanding of how Blade components and the whole process work now. You can further modify our component according to your needs. Based on this component you can easily create components for other form elements like textarea
or checkbox
- I'm leaving this up to you.
All the materials at voerro are absolutely free and are worked on in the author's spare time. If you found any of the tutorials helpful, please consider supporting the project. Thank you!