Laravel 24 septiembre, 2018 0

Blade: motor de plantillas – parte 3

Como ya vimos con anterioridad en los artículos  motor de plantilla  parte 1 y parte 2, blade es una potente herramienta integrada con el framework Laravel.

En esta ultima parte de blade veremos y daremos solución a un tipo problema al que nos enfrentamos a la hora de  desarrollar aplicaciones web y para ello haremos el uso de layouts y partials.

Tema de administración

Lo primero que haremos será descargar SB Admin, un tema gratuito con el cual estaremos trabajando a partir de este articulo.

 

Estructura del proyecto

Al abrir el proyecto en algún editor y abrir alguna de las  paginas principales (index.html, charts.html, tables.html, etc) notaremos que tienen una misma estructura HTML Y es que todas la paginas comparten la cabecera, el menú lateral y el pie de pagina.

Si seguimos trabajando y creando más páginas a partir de este tema deberíamos respetar la estructura, lo que nos llevara en algún momento al problema de duplicación de código. Y es que si en alguno momento se modifica la estructura del menú lateral, deberemos realizar esta misma actualización en todas las páginas creadas.

Templates y Partials

Para dar solución al problema planteado anteriormente deberemos crear una solo vez los archivos compartidos y hacer el llamado a estas en todos las paginas necesarias, así si es necesaria una actualización en el menú lateral, esta se hará de manera mucho mas fácil y eficiente.

Templates

Son platillas que nos ahorraran mucho código o lenguaje HTML.

Creación de themplate

Abrimos el archivo “blank.html” que se encuentra en el tema SB Admin descargado anteriormente, y copiaremos el código en una nueva vista llamada “theme.blade.php“. Antes de guardar buscaremos las siguientes lineas.

<!-- Page Content -->
<h1>Blank Page</h1>
<hr>
<p>This is a great starting point for new custom pages.</p>

Las cuales sustituiremos por @yield(“content”). Esta sintaxis sera la encargada de sustituir el código de cada página creada en nuestra aplicación.

Creación de página de inicio

Abramos la vista “welcome.blade.php” y la editaremos colocando el siguiente código.

@extends("themplate")

@section('content')
    <!-- Page Content -->
    <h1>Blank Page</h1>
    <hr>
    <p>This is a great starting point for new custom pages.</p>
@endsection

Como podemos notar entre las sentencias utilizadas encontramos @extends() la cual recibe como parámetro el nombre de la plantilla de la cual deseamos heredar todo el código HTML.

La otra sentencia utilizada es @section y @endsection, y entre ellas deberemos colocar el contenido de cada página creada en nuestra aplicación, en este caso deberá ser el código que sustituimos de la vista “themplate.blade.php“. También notaremos que esta sentencia recibe un parámetro, este deberá ser el mismo que se definió en el template creada y el que se utilizo en la sentencia @yield(), en este caso fue la palabra “content“.

Resultados

Como ultimo paso deberemos implementar los assets que vienen dentro del tema descargado. En este caso copiamos las carpetas css, js y vendor, para pegarlas en nuestra aplicación dentro de la carpeta /public/.

Por último deberemos editar la vista “themplate.blade.html” para se carguen los archivos CSS y JS. Para ello utilizaremos el método assets() la cual recibe como parámetro la ubicación del asset a cargar.

<!DOCTYPE html>
<html lang="en">

  <head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>SB Admin - Blank Page</title>

    <!-- Bootstrap core CSS-->
    <link href="{{ asset('vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">

    <!-- Custom fonts for this template-->
    <link href="{{ asset('vendor/fontawesome-free/css/all.min.css') }}" rel="stylesheet" type="text/css">

    <!-- Page level plugin CSS-->
    <link href="{{ asset('vendor/datatables/dataTables.bootstrap4.css') }}" rel="stylesheet">

    <!-- Custom styles for this template-->
    <link href="{{ asset('css/sb-admin.css') }}" rel="stylesheet">

  </head>

  <body id="page-top">

    <nav class="navbar navbar-expand navbar-dark bg-dark static-top">

      <a class="navbar-brand mr-1" href="assets('index.html">Start Bootstrap</a>

      <button class="btn btn-link btn-sm text-white order-1 order-sm-0" id="sidebarToggle" href="assets('#">
        <i class="fas fa-bars"></i>
      </button>

      <!-- Navbar Search -->
      <form class="d-none d-md-inline-block form-inline ml-auto mr-0 mr-md-3 my-2 my-md-0">
        <div class="input-group">
          <input type="text" class="form-control" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2">
          <div class="input-group-append">
            <button class="btn btn-primary" type="button">
              <i class="fas fa-search"></i>
            </button>
          </div>
        </div>
      </form>

      <!-- Navbar -->
      <ul class="navbar-nav ml-auto ml-md-0">
        <li class="nav-item dropdown no-arrow mx-1">
          <a class="nav-link dropdown-toggle" href="assets('#" id="alertsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <i class="fas fa-bell fa-fw"></i>
            <span class="badge badge-danger">9+</span>
          </a>
          <div class="dropdown-menu dropdown-menu-right" aria-labelledby="alertsDropdown">
            <a class="dropdown-item" href="assets('#">Action</a>
            <a class="dropdown-item" href="assets('#">Another action</a>
            <div class="dropdown-divider"></div>
            <a class="dropdown-item" href="assets('#">Something else here</a>
          </div>
        </li>
        <li class="nav-item dropdown no-arrow mx-1">
          <a class="nav-link dropdown-toggle" href="assets('#" id="messagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <i class="fas fa-envelope fa-fw"></i>
            <span class="badge badge-danger">7</span>
          </a>
          <div class="dropdown-menu dropdown-menu-right" aria-labelledby="messagesDropdown">
            <a class="dropdown-item" href="assets('#">Action</a>
            <a class="dropdown-item" href="assets('#">Another action</a>
            <div class="dropdown-divider"></div>
            <a class="dropdown-item" href="assets('#">Something else here</a>
          </div>
        </li>
        <li class="nav-item dropdown no-arrow">
          <a class="nav-link dropdown-toggle" href="assets('#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <i class="fas fa-user-circle fa-fw"></i>
          </a>
          <div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown">
            <a class="dropdown-item" href="assets('#">Settings</a>
            <a class="dropdown-item" href="assets('#">Activity Log</a>
            <div class="dropdown-divider"></div>
            <a class="dropdown-item" href="assets('#" data-toggle="modal" data-target="#logoutModal">Logout</a>
          </div>
        </li>
      </ul>

    </nav>

    <div id="wrapper">

      <!-- Sidebar -->
      <ul class="sidebar navbar-nav">
        <li class="nav-item">
          <a class="nav-link" href="assets('index.html">
            <i class="fas fa-fw fa-tachometer-alt"></i>
            <span>Dashboard</span>
          </a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="assets('#" id="pagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <i class="fas fa-fw fa-folder"></i>
            <span>Pages</span>
          </a>
          <div class="dropdown-menu" aria-labelledby="pagesDropdown">
            <h6 class="dropdown-header">Login Screens:</h6>
            <a class="dropdown-item" href="assets('login.html">Login</a>
            <a class="dropdown-item" href="assets('register.html">Register</a>
            <a class="dropdown-item" href="assets('forgot-password.html">Forgot Password</a>
            <div class="dropdown-divider"></div>
            <h6 class="dropdown-header">Other Pages:</h6>
            <a class="dropdown-item" href="assets('404.html">404 Page</a>
            <a class="dropdown-item active" href="assets('blank.html">Blank Page</a>
          </div>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="assets('charts.html">
            <i class="fas fa-fw fa-chart-area"></i>
            <span>Charts</span></a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="assets('tables.html">
            <i class="fas fa-fw fa-table"></i>
            <span>Tables</span></a>
        </li>
      </ul>

      <div id="content-wrapper">

        <div class="container-fluid">

          <!-- Breadcrumbs-->
          <ol class="breadcrumb">
            <li class="breadcrumb-item">
              <a href="assets('index.html">Dashboard</a>
            </li>
            <li class="breadcrumb-item active">Blank Page</li>
          </ol>

          @yield('content')

        </div>
        <!-- /.container-fluid -->

        <!-- Sticky Footer -->
        <footer class="sticky-footer">
          <div class="container my-auto">
            <div class="copyright text-center my-auto">
              <span>Copyright © Your Website 2018</span>
            </div>
          </div>
        </footer>

      </div>
      <!-- /.content-wrapper -->

    </div>
    <!-- /#wrapper -->

    <!-- Scroll to Top Button-->
    <a class="scroll-to-top rounded" href="assets('#page-top">
      <i class="fas fa-angle-up"></i>
    </a>

    <!-- Logout Modal-->
    <div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5>
            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">×</span>
            </button>
          </div>
          <div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
          <div class="modal-footer">
            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
            <a class="btn btn-primary" href="assets('login.html">Logout</a>
          </div>
        </div>
      </div>
    </div>

    <!-- Bootstrap core JavaScript-->
    <script src="{{ asset('vendor/jquery/jquery.min.js') }}"></script>
    <script src="{{ asset('vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>

    <!-- Core plugin JavaScript-->
    <script src="{{ asset('vendor/jquery-easing/jquery.easing.min.js') }}"></script>

    <!-- Custom scripts for all pages-->
    <script src="{{ asset('js/sb-admin.min.js') }}"></script>

  </body>

</html>

Partials

Básicamente es lo mismo que hemos visto anteriormente, una vista.

Para tener esto mas claro tomaremos como muestra el archivo “themplate.blade.php” y lo que haremos es separar en componentes la estructura HTML de la cabecera, menú lateral y pie de página.

Cabecera

Creamos una vista llamada “header.blade.php”, buscaremos la estructura HTML del “navbar” que esta en el tema y lo copiamos en la vista.

<nav class="navbar navbar-expand navbar-dark bg-dark static-top">

  <a class="navbar-brand mr-1" href="assets('index.html">Start Bootstrap</a>

  <button class="btn btn-link btn-sm text-white order-1 order-sm-0" id="sidebarToggle" href="assets('#">
    <i class="fas fa-bars"></i>
  </button>

  <!-- Navbar Search -->
  <form class="d-none d-md-inline-block form-inline ml-auto mr-0 mr-md-3 my-2 my-md-0">
    <div class="input-group">
      <input type="text" class="form-control" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2">
      <div class="input-group-append">
        <button class="btn btn-primary" type="button">
          <i class="fas fa-search"></i>
        </button>
      </div>
    </div>
  </form>

  <!-- Navbar -->
  <ul class="navbar-nav ml-auto ml-md-0">
    <li class="nav-item dropdown no-arrow mx-1">
      <a class="nav-link dropdown-toggle" href="assets('#" id="alertsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        <i class="fas fa-bell fa-fw"></i>
        <span class="badge badge-danger">9+</span>
      </a>
      <div class="dropdown-menu dropdown-menu-right" aria-labelledby="alertsDropdown">
        <a class="dropdown-item" href="assets('#">Action</a>
        <a class="dropdown-item" href="assets('#">Another action</a>
        <div class="dropdown-divider"></div>
        <a class="dropdown-item" href="assets('#">Something else here</a>
      </div>
    </li>
    <li class="nav-item dropdown no-arrow mx-1">
      <a class="nav-link dropdown-toggle" href="assets('#" id="messagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        <i class="fas fa-envelope fa-fw"></i>
        <span class="badge badge-danger">7</span>
      </a>
      <div class="dropdown-menu dropdown-menu-right" aria-labelledby="messagesDropdown">
        <a class="dropdown-item" href="assets('#">Action</a>
        <a class="dropdown-item" href="assets('#">Another action</a>
        <div class="dropdown-divider"></div>
        <a class="dropdown-item" href="assets('#">Something else here</a>
      </div>
    </li>
    <li class="nav-item dropdown no-arrow">
      <a class="nav-link dropdown-toggle" href="assets('#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        <i class="fas fa-user-circle fa-fw"></i>
      </a>
      <div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown">
        <a class="dropdown-item" href="assets('#">Settings</a>
        <a class="dropdown-item" href="assets('#">Activity Log</a>
        <div class="dropdown-divider"></div>
        <a class="dropdown-item" href="assets('#" data-toggle="modal" data-target="#logoutModal">Logout</a>
      </div>
    </li>
  </ul>

</nav>

Menú lateral

Creamos una vista llamada “sidebar.blade.php”, buscaremos la estructura HTML del “sidebar” que esta en el tema y lo copiamos a la vista.

<!-- Sidebar -->
<ul class="sidebar navbar-nav">
  <li class="nav-item">
    <a class="nav-link" href="assets('index.html">
      <i class="fas fa-fw fa-tachometer-alt"></i>
      <span>Dashboard</span>
    </a>
  </li>
  <li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="assets('#" id="pagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
      <i class="fas fa-fw fa-folder"></i>
      <span>Pages</span>
    </a>
    <div class="dropdown-menu" aria-labelledby="pagesDropdown">
      <h6 class="dropdown-header">Login Screens:</h6>
      <a class="dropdown-item" href="assets('login.html">Login</a>
      <a class="dropdown-item" href="assets('register.html">Register</a>
      <a class="dropdown-item" href="assets('forgot-password.html">Forgot Password</a>
      <div class="dropdown-divider"></div>
      <h6 class="dropdown-header">Other Pages:</h6>
      <a class="dropdown-item" href="assets('404.html">404 Page</a>
      <a class="dropdown-item active" href="assets('blank.html">Blank Page</a>
    </div>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="assets('charts.html">
      <i class="fas fa-fw fa-chart-area"></i>
      <span>Charts</span></a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="assets('tables.html">
      <i class="fas fa-fw fa-table"></i>
      <span>Tables</span></a>
  </li>
</ul>

Pie de página

Creamos una vista llamada “footer.blade.php”, buscaremos la estructura HTML del “sidebar” que esta en el tema y lo copiamos en la vista.

<!-- Sticky Footer -->
<footer class="sticky-footer">
  <div class="container my-auto">
    <div class="copyright text-center my-auto">
      <span>Copyright © Your Website 2018</span>
    </div>
  </div>
</footer>

Resultados

Por ultimo deberemos llamar estas vistas o partials dentro del template creado, para ello implementaremos la sentencia @include(), la cual recibe como parámetro el nombre del partial. Entonces tendremos al final un template con la siguiente estrucurura.

<!DOCTYPE html>
<html lang="en">

  <head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>SB Admin - Blank Page</title>

    <!-- Bootstrap core CSS-->
    <link href="{{ asset('vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">

    <!-- Custom fonts for this template-->
    <link href="{{ asset('vendor/fontawesome-free/css/all.min.css') }}" rel="stylesheet" type="text/css">

    <!-- Page level plugin CSS-->
    <link href="{{ asset('vendor/datatables/dataTables.bootstrap4.css') }}" rel="stylesheet">

    <!-- Custom styles for this template-->
    <link href="{{ asset('css/sb-admin.css') }}" rel="stylesheet">

  </head>

  <body id="page-top">

    @include('header')

    <div id="wrapper">

      @include('sidebar')

      <div id="content-wrapper">

        <div class="container-fluid">

          <!-- Breadcrumbs-->
          <ol class="breadcrumb">
            <li class="breadcrumb-item">
              <a href="assets('index.html">Dashboard</a>
            </li>
            <li class="breadcrumb-item active">Blank Page</li>
          </ol>

          @yield('content')

        </div>
        <!-- /.container-fluid -->

        @include('footer')

      </div>
      <!-- /.content-wrapper -->

    </div>
    <!-- /#wrapper -->

    <!-- Scroll to Top Button-->
    <a class="scroll-to-top rounded" href="assets('#page-top">
      <i class="fas fa-angle-up"></i>
    </a>

    <!-- Logout Modal-->
    <div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5>
            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">×</span>
            </button>
          </div>
          <div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
          <div class="modal-footer">
            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
            <a class="btn btn-primary" href="assets('login.html">Logout</a>
          </div>
        </div>
      </div>
    </div>

    <!-- Bootstrap core JavaScript-->
    <script src="{{ asset('vendor/jquery/jquery.min.js') }}"></script>
    <script src="{{ asset('vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>

    <!-- Core plugin JavaScript-->
    <script src="{{ asset('vendor/jquery-easing/jquery.easing.min.js') }}"></script>

    <!-- Custom scripts for all pages-->
    <script src="{{ asset('js/sb-admin.min.js') }}"></script>

  </body>

</html>

Esta estructura no generara cambios visuales para el usuario, pero si hará nuestro código mucho más simple y legible.

Visitamos en nuestro navegador la ruta “/” de nuestra aplicación para ver los resultados.