Update May 2021
Please note that this post is currently 3 years old. As you know, things move fast in our tech world and event though the principles described in this post are still valid, there might be better ways to achieve the same result; You are free to continue reading, but I recently wrote a post about our current approach.
Additionally, Laravel 8 brings a new starter kit to quickly scaffold the frontend of your next project. It’s called Laravel Jetstream and is definitely worth taking a look. I’ll choose Laravel Jetstream with Inertia scaffolding for my next project.
Therefore, I am removing the code repository that originally came with this post.
So far we created a registration form in a blade view and the next step is to add the desired behaviour to the form:
- Choosing a gender should add a text field to the form to enter your name. The label of the text field should become either Mr. or Ms. depending on the chosen gender.
- Validatie the email address is valid when the email field looses focus and if it is valid, check whether the email is still available (via AJAX request to the server). Show a message reflecting this.
- Check the combination of zipcode and country when choosing one or the other. Show a message if the zipcode does not comply with the rules for the specific country.
Including <script> tags in head and view
The initial approach described here uses jQuery. It is the oldest (and quickest and easiest) way I know and in some of my legacy projects it is still used. Either because this code is still working properly or due to limited time or budget to update the code.
Back in the day I used jQuery to add any special behaviour. Hence, jQuery is loaded from a CDN in the
<head> section of the document (in
app.blade.php). Since our sample project has a Bootstrap menu, the Popper.js and Bootstrap.js scripts must be included to make it work. Note that the order of these scripts is important!
app.blade.php looks like this:
The sample app only has a single page at the moment. The contents of the page are inserted at the
@yield('content') you see in line 34 of
In this view we include the form, a blade partial (see line 17)
Since we have jQuery available via the include in the head section, let’s add the following script tag inside the page:
The script starts with the traditional jQuery ready line to make sure that jQuery is fully loaded and initialised to do its magic. Then we wrap the whole code inside an immediately invoked function expression (IIFE) to be able to use the $ instead of jQuery. The latter shouldn’t be necessary for this post on its own, but in upcoming posts we’ll show why this is needed.
Inside the IIFE we add Laravel’s CSRF token to the AJAX headers. This way we won’t get any errors when doing a POST request.
Then we come to the event listeners attached to the DOM elements. The code is rather self explanatory so I won’t discuss it in detail. One thing to point out though: this approach requires us to add and remove DOM nodes to react to user input.
For example, the error messages from previous events need to be removed before the event listener’s callback continues (line 41). In addition, a text field is inserted after the user chooses its gender (line 35), a message is displayed after entering the email address (line 48 and 80) and so on.
This is typically the way jQuery works. It is an imperative language that works directly on the DOM by adding, removing, updating, hiding and showing DOM nodes.
Pros and cons of this approach
- it just makes your code work across browsers
Back in the day this was a huge win, today most browsers are converting to very similar behaviour.
- it has (should I say had?) a vibrant community creating huge amounts of plugins
- it lets you write code without bothering about bundling and stuff a like.
However, as time went by and webapplications were growing and became more complex, the downsides using jQuery became clear:
- script tags need to be inserted in the correct order
- difficult to reason about the flow of the code
- callback hell awaits you
- difficult (or even impossible) to test the code
- jQuery is defined as a global variable which comes with its problems as described in great detail in this post:
This makes maintaining code tricky. It makes removing old code or script tags a game of roulette. You don’t know what might break. The dependencies between these different parts of your code are implicit. Any function can grab anything on the global, so you don’t know which functions depend on which scripts.
A second problem is that because these variables are on the global scope, every part of the code that’s inside of that global scope can change the variable. Malicious code can change that variable on purpose to make your code do something you didn’t mean for it to, or non-malicious code could just accidentally clobber your variable.