Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Laravel Blade Views

Creating Views

The default "welcome" view is located under resources/views/welcome.blade.php within the stock laravel installation.

To create a new view, simply create a new file under resources/views with the .blade.php extension, and then call it from your route like so:

Route::get('/my-path', function () {
    return view('my-view');
});

Notice how we don't include the .blade.php extension in the call.

Subfolders

If you want to put your views into a sub-folder, you can do. You just need to remember to put that subfolder in the function call. E.g.

return view('subfolder/my-view');

You can also use "dot" notation instead of using slashes. E.g.

return view('subfolder.my-view');

I don't like the fact that we rely on string values "matching up". If you rename a file, you need to manually find it everywhere that you called it within a view function and rename it there. Don't forget to check for both slashes and dots.

Checking View Exists

You can do the following to check if a view exists...

use Illuminate\Support\Facades\View;

if (View::exists('emails.customer')) {
    //
}

In my opinion, if you have to use this, there's probably something seriously wrong...

Passing Data To Views

Variables can be put into views with {{$variableNameHere}} like so:

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>My Project</title>
    </head>
    <body>
        <h1>{{$title}}</h1>
        <p>{{$body}}</p>
    </body>
</html>

The example view above needs a $title, and a $body, which can be given to it like so:

Route::get('/blog', function () {
    $viewData = array(
        'title' => "Programster's Blog", 
        'body' => 'Hello world'
    );

    return view('programster', $viewData);
});

Alternatively, you can use with to pass one piece of information at a time, like so:

Route::get('/blog', function () {
    return view('programster')
        ->with('title', "Programster's Blog")
        ->with('body', 'Hello world!');
});

Again, I don't like this as we are relying on variable names "matching" so renaming things can become a bugger. Not to mention if you need to add another variable, you need to manually find all the calls to the view and add to the array. When removing a variable, you may just not bother, leading to confusion later when another developer sees a variable being passed but can't find its usage.

Templates

The above examples were really simple with calling one view which may contain variables that you pass data to the view for. However, this can lead to a lot of duplicate code for the "layout" of your views which would be hard to maintain when you make changes. It would be nicer if you could write the HTML "shell" once and then just write views for the main body of content within it. You can do this with "inheritance" like so:

First create a "template" or "parent" outer shell like so which contains all your CSS/JS includes etc that you don't need to keep re-writing:

<html>
    <head>
        <title>Programster's Blog</title>
       <link rel="stylesheet" type="text/css" href="/css/style.css">
    </head>
    <body>
        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

...Notice the @yield('content'). This is the key for us to inject with our "child" views that "extend" this template.

Then "extend" it with a "child" view that will fill in the content. For this example I am assuming the "parent" was called MyParentView.

@extends('MyParentView')

@section('content')
Hello there! This is my content!
@endsection

Notice that we have to declare the view that we are "extending" right at the top. E.g. @extends('MyParentView')

Then when you want to render this, you just call the child view (not having to mention the parent), like so:

Route::get('/blog', function () {
    return view('MyChildView');
}

Multiple Sections

The previous example was really simple and basic as the "template" only had one "section". Your templates can have any number of sections. The following example template has a "sidebar", and a "content" section for filling in:

<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        @yeld('sidebar')

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

This template can be used with a child like so:

@extends('MyParentView')

@section('sidebar')
<ul>
    <li>Menu Item 1</li>
    <li>Menu Item 2</li>
    <li>Menu Item 3</li>
    <li>Menu Item 4</li>
</ul>
@endsection

@section('content')
Hello there! This is my content!
@endsection

Extending Sections

Templates really are like programmatic inheritance, in that you can call parent's content and extend it like the following example:

<html>
    <head>
        <title>Programster's Blog</title>
       <link rel="stylesheet" type="text/css" href="/css/style.css">
    </head>
    <body>
        <div class="container">
            @section('content')
            <p>This is my first sentence...</p> 
            @show
        </div>
    </body>
</html>

You can then "append" to the content with the child view like so:

@extends('MyParentView')

@section('content')
    @parent
    <p>This is my second sentence.</p>
@endsection

Variables Are Shared

Just in case you were wandering, yes variables are shared between the views. This is best to illustrate with example code:

Create your "parent" template with a variable for the meta title and the first sentence:

<html>
    <head>
        <title>{{$metaTitle}}</title>
    </head>
    <body>
        <div class="container">
            @section('content')
            <p>{{$sentence1}}</p> 
            @show
        </div>
    </body>
</html>

... then you can use variables in the child view as well:

@extends('MyParentView')

@section('content')
    @parent
    <p>{{$sentence2}}</p>
@endsection

... and then you can render the view with the variables from your controller like so:

Route::get('/blog', function () {
    $viewData = array(
        'metaTitle' => "Programster's Blog - Home", 
        'sentence1' => 'This is my first sentence...',
        'sentence2' => 'This is my second sentence...'
    );

    return view('MyChildView', $viewData);
});

At this point you are probably thinking this is pretty neat/cool/powerful and it can be if used with careful thought and attention (starting with using separate folders for layouts/templates). However, from my perspective of having had to debug and extend other people's legacy code over the years, I just see the opportunity for spaghetti code that is hard/impossible for someone to understand if they weren't the person to write it in the first place.

References

Last updated: 19th February 2020
First published: 16th February 2020