Learning Management Platform for Written Tutorial Series.

Laravel 5 Views

Laravel 5 Views

Introduction

In this tutorial, we are going to convert a HTML 5 admin template Gentelella into fully functionally Laravel blade templates. We will also take advantage of blade layouts and partials to promote component reuse.

By the time that you are done, you would have built the following views for all of the defined routes for our tutorial project.

Laravel Views Organization

Laravel Blade Flash Messages

Laravel Blade Foreach

Laravel Blade Form Create

Laravel Blade Form Edit

Laravel Blade Form Delete

Topics to be covered

In this tutorial, we will cover the following topics;

  • Tutorial pre-requisites
  • Tutorial starter code
  • Laradmin templates organization
  • Blade template master layout
  • Blade template partials
  • Blade CRUD templates
  • Tutorial complete code

Tutorial pre-requisites

You will need to know / have the following tools to successfully complete this tutorial;

  • You understand the basics of Laravel 5. If you do then I recommend you start with these Laravel 5 Tutorial series.
  • You have PHP, MySQL and a web server i.e. Apache up and running
  • Laravel Homestead – this is optional but provides a great development environment. If you are new to Laravel homestead then I recommend you read the series on Laravel Homestead
  • You have composer installed
  • You have a text editor or IDE that supports PHP.
  • You have a modern web browser that supports HTML5
  • Git – this is optional but highly recommended. This tutorial has a repository on GitHub, with Git, you will be able to clone starter code for each tutorial.

Tutorial starter code

This tutorial builds on from the previous tutorial. If you have not been following the tutorial series, then you can download starter code for this tutorial from GitHub

If you have git installed, run the following command to clone the project

git clone -b 02_routes https://github.com/KodeBlog/Laradmin.git laradmin

HERE,

  • git clone -b 02_routes clones the branch 02_routes from the repository https://github.com/KodeBlog/Laradmin.git into a local folder laradmin.

Laradmin templates organization

The following image shows how our templates will be organized

Laravel Blade Organization

As you can see from the above image, we will create two directories in /resources/views namely

  • admin – this is where all of the templates for our admin panel will be stored
  • templates/admin – this is where all of the master layouts and partials will be stored

The directories inside /resources/views/admin/* i.e. brands contain similar templates. We will look at the contents of brands that we have expanded as shown in the image above.

  • brands_create.blade.php – this template will contain the markup for the form used to create a new brand
  • brands_delete.blade.php – this template will contain the markup for the form that asks you to confirm before deleting the brand.
  • brands_edit.blade.php – this template will contain the markup for form that will be used to edit brands.
  • brands_listing.blade.php – contains the markup for listing all brands from the database.

Tutorial exercise

Using the starter code for this project, create the necessary directories as shown in the image above and create the blade templates in each directory.

Blade template master layout

If you are completely new to blade template, then I recommend you read this tutorial blade template

The master layout contains elements that are common to all the pages. These include the header, navigation, footer etc.

All of the other pages i.e. products_list.blade.php will be extending the master layout template.

Create a new file layout.blade.php in /resources/views/templates/admin

Add the following code to the new file

html>
<html lang="en">
<head>
    <!-- head items -->
</head>
<body class="nav-md">
    <div class="container body">
        <div class="main_container">
            <div class="col-md-3 left_col">
                <div class="left_col scroll-view">
                    <div class="navbar nav_title" style="border: 0;">
                        <a href="#" class="site_title"><i class="fa fa-paw"></i> <span>Larashop CPanel!</span></a>
                    </div>

                    <div class="clearfix"></div>

                    <!-- menu profile quick info -->
                    <div class="profile">
                        <div class="profile_pic">
                            <img src="{{asset('admin/images/img.jpg')}}" alt="..." class="img-circle profile_img">
                        </div>
                        <div class="profile_info">
                            <span>Welcome,</span>
                            <h2>John Doe</h2>
                        </div>
                    </div>
                    <!-- /menu profile quick info -->

                    <br />

                    <!-- sidebar menu -->
                    <div id="sidebar-menu" class="main_menu_side hidden-print main_menu">
                        <div class="menu_section">
                            <h3>General</h3>
                            <ul class="nav side-menu">
                                <li><a hef="#"><i class="fa fa-home"></i> Home </a></li>
                                <li><a><i class="fa fa-edit"></i> Products <span class="fa fa-chevron-down"></span></a>
                                    <ul class="nav child_menu">
                                        <li><a href="{{route('brands.index')}}">Brands list</a></li>
                                        <li><a href="{{route('product-categories.index')}}">Categories</a></li>
                                        <li><a href="{{route('products.index')}}">Products list</a></li>
                                    </ul>
                                </li>
                                <li><a href="{{route('customers.index')}}"><i class="fa fa-user"></i> Customers </a></li>
                                <li><a href="{{route('orders.index')}}"><i class="fa fa-shopping-cart"></i> Orders </a></li>
                                <li><a href="{{route('users.index')}}"><i class="fa fa-users"></i> Users </a></li>
                            </ul>
                        </div>
                    </div>
                    <!-- /sidebar menu -->

                    <!-- /menu footer buttons -->
                    <div class="sidebar-footer hidden-small">
                        <a data-toggle="tooltip" data-placement="top" title="Settings">
                            <span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
                        </a>
                        <a data-toggle="tooltip" data-placement="top" title="FullScreen">
                            <span class="glyphicon glyphicon-fullscreen" aria-hidden="true"></span>
                        </a>
                        <a data-toggle="tooltip" data-placement="top" title="Lock">
                            <span class="glyphicon glyphicon-eye-close" aria-hidden="true"></span>
                        </a>
                        <a data-toggle="tooltip" data-placement="top" title="Logout">
                            <span class="glyphicon glyphicon-off" aria-hidden="true"></span>
                        </a>
                    </div>
                    <!-- /menu footer buttons -->
                </div>
            </div>

            <!-- top navigation -->
            <div class="top_nav">
                <div class="nav_menu">
                    <nav>
                        <div class="nav toggle">
                            <a id="menu_toggle"><i class="fa fa-bars"></i></a>
                        </div>

                        <ul class="nav navbar-nav navbar-right">
                            <li class="">
                                <a href="javascript:;" class="user-profile dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                                    <img src="{{asset('admin/images/img.jpg')}}" alt="">John Doe
                                    <span class=" fa fa-angle-down"></span>
                                </a>
                                <ul class="dropdown-menu dropdown-usermenu pull-right">
                                    <li><a href="#"> Profile</a></li>
                                    <li><a href="#"><i class="fa fa-sign-out pull-right"></i> Log Out</a></li>
                                </ul>
                            </li>


                        </ul>
                    </nav>
                </div>
            </div>
            <!-- /top navigation -->

            <!-- page content -->
            <div class="right_col" role="main">
                @include('templates.admin.partials.alerts')
                @yield('content')
            </div>
            <!-- /page content -->

            <!-- footer content -->
            <footer>
                <div class="pull-right">
                    Gentelella - Bootstrap Admin Template by <a href="https://colorlib.com">Colorlib</a>
                </div>
                <div class="clearfix"></div>
            </footer>
            <!-- /footer content -->
        </div>
    </div>

<!-- javascript resources -->
</body>
</html>

HERE,

  • <!-head items --> represents all of the resources i.e. title, css etc. which have been removed on purpose to reduce the number of lines of code. You can get the complete header resources from the complete tutorial files
  • <!-javascript resources --> represents JavaScript resources which have been removed on purpose to reduce the number of lines of code. You can get the complete js resources from the complete tutorial files
  • {{route('name')}} i.e. {{route('brands.index')}} uses named routes to create links. This is considered a best practice because when you change the path of the route in /routes/web.php, you won’t have to update all of the views. The route function will automatically pick the updated name. -@include('templates.admin.partials.alerts') includes the partial view that is responsible for displaying alerts. i.e. displaying success when a new record is added or displaying an error message.
  • @yield('content') is used to display the contents of the template that is extending the master layout.

Blade template partials

Partials are reused components that can be embedded into a view. A good example of a partial view is an alert message. You only have to create one partial view that can be embedded into any view. You can also use partials for navigation, sidebars etc.

Create a new file alerts.blade.php in /resources/views/templates/admin/alerts

The alerts partial will be used to display flash messages. Flash messages are displayed only once.

Add the following code to alerts.blade.php

@if (Session::has('info'))
<div class="clearfix"></div>
<div class="alert alert-info" role="alert">
    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
    {!! Session::get('info') !!}
</div>
@endif

@if (Session::has('success'))
<div class="clearfix"></div>
<div class="alert alert-success" role="alert">
    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
    {!! Session::get('success') !!}
</div>
@endif

@if (Session::has('warning'))
<div class="clearfix"></div>
<div class="alert alert-warning" role="alert">
    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
    {!! Session::get('warning') !!}
</div>
@endif

@if (Session::has('error'))
<div class="clearfix"></div>
<div class="alert alert-danger" role="alert">
    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
    {!! Session::get('error') !!}
</div>
@endif

HERE,

  • @if (Session::has('info')) uses the if statement to check of the Session variable has a key of info and if it is true, then blade should display an alert with the class of info and the value of the key info {!! Session::get('info') !!} the double exclamation marks are used to our raw HTML because we want to be able to format the message using HTML when displaying alerts.
  • The same logic applies to the rest of the conditional statements. We are supporting info, success, warning and error classes.

The session data will be set by the controllers. Consider the following code

return redirect()->route('brands.index')->with('success', "The brand <strong>Brand</strong> has successfully been created.");

HERE,

  • The above code redirects to the named route brands.index and sets a session variable success with the value of The brand <strong>Brand</strong> has successfully been created. Note: the value contains HTML elements <strong>…</strong>

The above code would produce something similar to the following

Laravel Blade Flash Messages

Blade CRUD templates

In this section, we will look at the four major blade templates that represent a resource.

  • Create
  • Edit
  • Delete
  • List

The code for /resources/views/admin/brands/brands_create.blade.php is as follows

@extends('templates.admin.layout')

@section('content')
<div class="">
    <div class="clearfix"></div>
    <div class="row">
        <div class="col-md-12 col-sm-12 col-xs-12">
            <div class="x_panel">
                <div class="x_title">
                    <h2>Create Brand <a href="{{route('brands.index')}}" class="btn btn-info btn-xs"><i class="fa fa-chevron-left"></i> Back </a></h2>
                    <div class="clearfix"></div>
                </div>
                <div class="x_content">
                    <br />
                    <form method="post" action="{{ route('brands.store') }}" data-parsley-validate class="form-horizontal form-label-left">

                        <div class="form-group{{ $errors->has('brand') ? ' has-error' : '' }}">
                            <label class="control-label col-md-3 col-sm-3 col-xs-12" for="brand">Brand <span class="required">*</span>
                            </label>
                            <div class="col-md-6 col-sm-6 col-xs-12">
                                <input type="text" value="{{ Request::old('brand') ?: '' }}" id="brand" name="brand" class="form-control col-md-7 col-xs-12">
                                @if ($errors->has('brand'))
                                <span class="help-block">{{ $errors->first('brand') }}</span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('description') ? ' has-error' : '' }}">
                            <label class="control-label col-md-3 col-sm-3 col-xs-12" for="description">Description <span class="required">*</span>
                            </label>
                            <div class="col-md-6 col-sm-6 col-xs-12">
                                <input type="text" value="{{ Request::old('description') ?: '' }}" id="description" name="description" class="form-control col-md-7 col-xs-12">
                                @if ($errors->has('description'))
                                <span class="help-block">{{ $errors->first('description') }}</span>
                                @endif
                            </div>
                        </div>

                        <div class="ln_solid"></div>

                        <div class="form-group">
                            <div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
                                <input type="hidden" name="_token" value="{{ Session::token() }}">
                                <button type="submit" class="btn btn-success">Create Brand</button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@stop

HERE,

  • @extends('templates.admin.layout') extends the master layout that provides us with the header, navigation and footer plus all the required resources i.e. css, JavaScript etc.
  • @section('content') defines a section named content. This is the section that is displayed in the master layout using @yield('content')
  • {{route('name')}} uses named routes to create the necessary links in the form that is used to create a new resource.
  • <form method="post" action="{{ route('brands.store') }}" data-parsley-validate class="form-horizontal form-label-left"> creates a form that uses the POST verb and the action URL is brands.store which is used to create new resources.
  • <div class="form-group{{ $errors->has('brand') ? ' has-error' : '' }}">…</div> adds the has-error class to the input form if an error occurs during validation of the relevant input field. We will look at this in more detail when we look at Laravel Validation.
  • {{ Request::old('brand') ?: '' }} is used to output what the user had entered when server-side validation fails. This saves the user a lot of time repeating what they had entered before they submitted the form.
  • @if ($errors->has('brand')) <span class="help-block">{{ $errors->first('brand') }}</span> @endif displays the validation error message if the validation has returned an error message with the key of brand. The same logic applies to the other fields as well
  • <input type="hidden" name="_token" value="{{ Session::token() }}"> adds the CSRF security field that is required by Laravel before processing any submitted forms.
  • @stop marks the end of the section content

The code for /resources/views/admin/brands/brands_edit.blade.php is as follows

@extends('templates.admin.layout')

@section('content')
<div class="">
    <div class="clearfix"></div>
    <div class="row">
        <div class="col-md-12 col-sm-12 col-xs-12">
            <div class="x_panel">
                <div class="x_title">
                    <h2>Edit Brand <a href="{{route('brands.index')}}" class="btn btn-info btn-xs"><i class="fa fa-chevron-left"></i> Back </a></h2>
                    <div class="clearfix"></div>
                </div>
                <div class="x_content">
                    <br />
                    <form method="post" action="{{ route('brands.update', ['id' => 1]) }}" data-parsley-validate class="form-horizontal form-label-left">

                        <div class="form-group{{ $errors->has('brand') ? ' has-error' : '' }}">
                            <label class="control-label col-md-3 col-sm-3 col-xs-12" for="brand">Brand <span class="required">*</span>
                            </label>
                            <div class="col-md-6 col-sm-6 col-xs-12">
                                <input type="text" value="" id="brand" name="brand" readonly="1" class="form-control col-md-7 col-xs-12">
                                @if ($errors->has('brand'))
                                <span class="help-block">{{ $errors->first('brand') }}</span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('description') ? ' has-error' : '' }}">
                            <label class="control-label col-md-3 col-sm-3 col-xs-12" for="description">Description <span class="required">*</span>
                            </label>
                            <div class="col-md-6 col-sm-6 col-xs-12">
                                <input type="text" value="" id="description" name="description" class="form-control col-md-7 col-xs-12">
                                @if ($errors->has('description'))
                                <span class="help-block">{{ $errors->first('description') }}</span>
                                @endif
                            </div>
                        </div>

                        <div class="ln_solid"></div>

                        <div class="form-group">
                            <div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
                                <input type="hidden" name="_token" value="{{ Session::token() }}">
                                <input name="_method" type="hidden" value="PUT">
                                <button type="submit" class="btn btn-success">Save Brand Changes</button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@stop

HERE,

  • Most of the code for editing is very similar to the one for create with the following exceptions
  • <form method="post" action="{{ route('brands.update', ['id' => 1]) }}" data-parsley-validate class="form-horizontal form-label-left"> most web browsers only support GET and POST methods. We need PUT for updating an existing resource. Laravel allows us to use POST as the form method then add a hidden field _method <input name="_method" type="hidden" value="PUT"> which specifies the HTTP verb PUT.
  • value="{{$data->brand}}" replaces Request::old('brand') with $data->field_name to output values. For now, we have set value= "" because we are not yet passing the $data variable.

The code /resources/views/admin/brands/brands_delete.blade.php is as follows

@extends('templates.admin.layout')

@section('content')
<div class="">
    <div class="clearfix"></div>

    <div class="row">
        <div class="col-md-12">
            <div class="x_panel">
                <div class="x_title">
                    <h2>Confirm Delete Record <a href="{{route('brands.index')}}" class="btn btn-info btn-xs"><i class="fa fa-chevron-left"></i> Back </a></h2>
                    <div class="clearfix"></div>
                </div>
                <div class="x_content">
                    <p>Are you sure you want to delete <strong>Brand</strong></p>

                    <form method="POST" action="{{ route('brands.destroy', ['id' => 1]) }}">
                        <input type="hidden" name="_token" value="{{ Session::token() }}">
                        <input name="_method" type="hidden" value="DELETE">
                        <button type="submit" class="btn btn-danger">Yes I'm sure. Delete</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@stop

HERE,

  • We have a form that uses post method but adds a hidden input <input name="_method" type="hidden" value="DELETE"> that tells Laravel to use the DELETE verb.

The code for /resources/views/admin/brands/brands_list.blade.php is as follows

@extends('templates.admin.layout')

@section('content')
<div class="">

    <div class="row">

        <div class="col-md-12 col-sm-12 col-xs-12">
            <div class="x_panel">
                <div class="x_title">
                    <h2>Brands <a href="{{route('brands.create')}}" class="btn btn-primary btn-xs"><i class="fa fa-plus"></i> Create New </a></h2>
                    <div class="clearfix"></div>
                </div>
                <div class="x_content">
                    <table id="datatable-buttons" class="table table-striped table-bordered">
                        <thead>
                            <tr>
                                <th>Brand</th>
                                <th>Description</th>
                                <th>Action</th>
                            </tr>
                        </thead>
                        <tfoot>
                            <tr>
                                <th>Brand</th>
                                <th>Description</th>
                                <th>Action</th>
                            </tr>
                        </tfoot>
                        <tbody>
                            <tr>
                                <td>Tiger Nixon</td>
                                <td>System Architect</td>
                                <td>
                                    <a href="{{ route('brands.edit', ['id' => 1]) }}" class="btn btn-info btn-xs"><i class="fa fa-pencil" title="Edit"></i> </a>
                                    <a href="{{ route('brands.show', ['id' => 1]) }}" class="btn btn-danger btn-xs"><i class="fa fa-trash-o" title="Delete"></i> </a>
                                </td>
                            </tr>
                            <tr>
                                <td>Garrett Winters</td>
                                <td>Accountant</td>
                                <td>
                                    <a href="{{ route('brands.edit', ['id' => 1]) }}" class="btn btn-info btn-xs"><i class="fa fa-pencil" title="Edit"></i> </a>
                                    <a href="{{ route('brands.destroy', ['id' => 1]) }}" class="btn btn-danger btn-xs"><i class="fa fa-trash-o" title="Delete"></i> </a>
                                </td>
                            </tr>
                            <tr>
                                <td>Ashton Cox</td>
                                <td>Junior Technical Author</td>
                                <td>
                                    <a href="{{ route('brands.edit', ['id' => 1]) }}" class="btn btn-info btn-xs"><i class="fa fa-pencil" title="Edit"></i> </a>
                                    <a href="{{ route('brands.destroy', ['id' => 1]) }}" class="btn btn-danger btn-xs"><i class="fa fa-trash-o" title="Delete"></i> </a>
                                </td>
                            </tr>
                            <tr>
                                <td>Cedric Kelly</td>
                                <td>Senior Javascript Developer</td>
                                <td>
                                    <a href="{{ route('brands.edit', ['id' => 1]) }}" class="btn btn-info btn-xs"><i class="fa fa-pencil" title="Edit"></i> </a>
                                    <a href="{{ route('brands.destroy', ['id' => 1]) }}" class="btn btn-danger btn-xs"><i class="fa fa-trash-o" title="Delete"></i> </a>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
@stop

HERE,

  • The above template doesn’t yet contain the code for displaying the brands. We will cover that in the next tutorial so we will skip it for now.

Controllers

All of the controllers have also been update to load the necessary views and take relevant actions i.e. redirecting and setting flash messages.

The code for /app/Http/Controllers/Admin/BrandsController.php is as follows

<?php

namespace Larashop\Http\Controllers\Admin;

use Illuminate\Http\Request;
use Larashop\Http\Controllers\Controller;

class BrandsController extends Controller
{
      /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('admin.brands.brands_list');
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('admin.brands.brands_create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        return redirect()->route('brands.index')->with('success', "The brand <strong>Brand</strong> has successfully been created.");
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        return view('admin.brands.brands_delete');
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        return view('admin.brands.brands_edit');
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        return redirect()->route('brands.index')->with('success', "The brand <strong>Brand</strong> has successfully been updated.");
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        return redirect()->route('brands.index')->with('success', "The brand <strong>Brand</strong> has successfully been archived.");
    }
}

HERE,

  • The above code simply displays relevant views, redirects and sets flash messages. We will talk more about the above code as we proceed in the tutorial series.

Complete Laradmin blade templates

Due to the large size of the HTML, I will not include all of the views here. You can download the complete from either the attached tutorial files or run the following code to download from the GitHub repository

git clone -b 03_views https://github.com/KodeBlog/Laradmin.git laradmin

Run the following command to browser to the root of the project

cd laradmin

We will now use composer to install dependencies.

composer install

When the installation is completed, run the following artisan command

php artisan serve

Summary

In this tutorial, we have managed to convert our template into fully functional blade template views. We also updated the controllers code to respond appropriately.

What’s next?

In the next tutorial, we will look at the database structure for our admin panel. We will add the necessary code that will be able to Create, Read, Update and Delete data from our database.

Kode Blog Tutorials is dedicated to bring you update to date, high quality free tutorials. You can support us by using the social media buttons to like and share the tutorial and subscribing to our newsletter. Please use the comments section below to give us feedback.

You can sign up for a free account on our site and you will be able to keep track of your progress as you go through the tutorial series and get notifications when we publish new content.


...