Michael Dyrynda
Home Blog Podcasts
 
Elegant form handling in Laravel May 15th, 2017

Introduction

On episode 28 of the North Meets South Web Podcast, Jake and I were discussing packages that we always pull into our Laravel projects. Jacob mentioned that he still uses the Laravel Collective HTML package, which was forked from the functionality that was present before Laravel 5, which is something I suggested I hadn't done for a long time.

If this is how you want to go about things, there's nothing wrong with that but I personally feel there's no real benefit in pulling in yet another package, just to handle writing HTML for me. This is largely because I can handle that kind of stuff with a combination of Emmet and/or snippets in Sublime Text.

Jacob went on to explain that a big part of using the form package is because it handles binding form data directly to the forms for you, allowing you to separate form inputs from the create / edit components themselves.

Using the HTML package

1// resources/views/users/edit.blade.php
2{!! Form::model($user, ['route' => ['users.update', $user->id], 'method' => 'put']) !!}
3 @include('users._form')
4 // Your cancel / update buttons
5{!! Form::close() !!}
6 
7// resources/views/users/_form.blade.php
8<div class="form-group">
9 {!! Form::label('first_name', 'First Name') !!}
10 {!! Form::text('first_name') !!}
11</div>

This will generate HTML for you that looks something along the following lines:

1<form method="POST" action="http://example.com/users/1" accept-charset="UTF-8">
2 <input name="_token" type="hidden" value="somegeneratedtoken">
3 <input name="_method" type="hidden" value="PUT">
4 <div class="form-group">
5 <label for="first_name">First Name</label>
6 <input name="first_name" type="text" value="Michael">
7 </div>
8</form>

Passing the $user variable along to the form's model method will pre-populate your form inputs, meaning that if the user had a first_name, it would automatically be assigned to the value parameter of the corresponding input.

Using vanilla Laravel and Blade

I suggested that you can go about this simply enough in your applications by using a combination of the old() helper method and an empty model.

1class UserController extends Controller
2{
3 public function create()
4 {
5 return view('users.create', ['user' => new User]);
6 }
7 
8 public function edit(User $user)
9 {
10 return view('users.edit', ['user' => $user]);
11 }
12}

This way, you can still extract the form parts into their own Blade template, and delegate display of the existing values to the model instance, leaving Eloquent to return null where the value doesn't exist i.e. in the blank User model.

1// In resources/views/users/_form.blade.php
2<div class="form-group">
3 <label for="first_name">First Name</label>
4 <input type="text"
5 name="first_name"
6 value="{{ old('first_name', $user->first_name) }}"
7 class="form-control"
8 >
9</div>

Conclusion

As I mentioned at the top of this post, it is entirely optional if you want to take this approach. I personally feel that I'm not gaining anything by bringing in another package just to handle generating HTML on my behalf when it's just as fast to use the tools available to me in my editor. It also means there's no implied knowledge of a now non-standard external package, should a new developer be brought on to the projects that I've worked on. HTML is HTML, after all.

I will concede that I miss the HTML package making things like <select> fields simpler, taking into account selected values but a simple @foreach loop and inline conditional aren't too bad in this instance, either.

How do you go about handling your HTML forms, do you have another approach? I'd love to hear about other options.

I'm a real developer ™
Michael Dyrynda

@michaeldyrynda

I am a software developer specialising in PHP and the Laravel Framework, and a freelancer, blogger, and podcaster by night.

Proudly hosted with Vultr

Syntax highlighting by Torchlight