10-Introducción a Blade en Laravel con un Ejemplo Práctico

  Introducción a Blade en Laravel con un Ejemplo Práctico

Blade es el motor de plantillas de Laravel que permite crear vistas de manera elegante y eficiente. A continuación te mostraré un ejemplo completo de cómo usar Blade para crear una aplicación simple de gestión de tareas.

Estructura del Proyecto

Vamos a crear:

  1. Una plantilla base (layout)

  2. Una página de índice para ver todas las tareas

  3. Una página para agregar nueva tarea

  4. Una página para ver los detalles de una tarea

  5. Un menú de navegación

  6. Funcionalidad para salir (logout)

1. Plantilla Base (resources/views/layouts/app.blade.php)

html
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title') - Gestor de Tareas</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="#">Gestor de Tareas</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('tasks.index') }}">Inicio</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('tasks.create') }}">Nueva Tarea</a>
                    </li>
                </ul>
                <ul class="navbar-nav ms-auto">
                    <li class="nav-item">
                        <form action="{{ route('logout') }}" method="POST">
                            @csrf
                            <button type="submit" class="btn btn-link nav-link">Salir</button>
                        </form>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <div class="container mt-4">
        @if(session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        @yield('content')
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

2. Página de Índice (resources/views/tasks/index.blade.php)

html
@extends('layouts.app')

@section('title', 'Lista de Tareas')

@section('content')
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1>Lista de Tareas</h1>
        <a href="{{ route('tasks.create') }}" class="btn btn-primary">Nueva Tarea</a>
    </div>

    @if($tasks->isEmpty())
        <div class="alert alert-info">No hay tareas registradas.</div>
    @else
        <div class="table-responsive">
            <table class="table table-striped">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Título</th>
                        <th>Estado</th>
                        <th>Fecha</th>
                        <th>Acciones</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach($tasks as $task)
                        <tr>
                            <td>{{ $task->id }}</td>
                            <td>{{ $task->title }}</td>
                            <td>
                                <span class="badge {{ $task->completed ? 'bg-success' : 'bg-warning' }}">
                                    {{ $task->completed ? 'Completada' : 'Pendiente' }}
                                </span>
                            </td>
                            <td>{{ $task->created_at->format('d/m/Y') }}</td>
                            <td>
                                <a href="{{ route('tasks.show', $task->id) }}" class="btn btn-sm btn-info">Ver</a>
                                <a href="{{ route('tasks.edit', $task->id) }}" class="btn btn-sm btn-warning">Editar</a>
                            </td>
                        </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
    @endif
@endsection

3. Página para Crear Tarea (resources/views/tasks/create.blade.php)

html
@extends('layouts.app')

@section('title', 'Crear Nueva Tarea')

@section('content')
    <div class="card">
        <div class="card-header">
            <h2>Nueva Tarea</h2>
        </div>
        <div class="card-body">
            <form action="{{ route('tasks.store') }}" method="POST">
                @csrf
                <div class="mb-3">
                    <label for="title" class="form-label">Título</label>
                    <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" value="{{ old('title') }}">
                    @error('title')
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="description" class="form-label">Descripción</label>
                    <textarea class="form-control @error('description') is-invalid @enderror" id="description" name="description" rows="3">{{ old('description') }}</textarea>
                    @error('description')
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3 form-check">
                    <input type="checkbox" class="form-check-input" id="completed" name="completed">
                    <label class="form-check-label" for="completed">Completada</label>
                </div>
                <button type="submit" class="btn btn-primary">Guardar</button>
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">Cancelar</a>
            </form>
        </div>
    </div>
@endsection

4. Página para Ver Tarea (resources/views/tasks/show.blade.php)

html
@extends('layouts.app')

@section('title', 'Detalles de la Tarea')

@section('content')
    <div class="card">
        <div class="card-header">
            <h2>Detalles de la Tarea</h2>
        </div>
        <div class="card-body">
            <div class="mb-3">
                <h5 class="card-title">{{ $task->title }}</h5>
                <span class="badge {{ $task->completed ? 'bg-success' : 'bg-warning' }}">
                    {{ $task->completed ? 'Completada' : 'Pendiente' }}
                </span>
            </div>
            <p class="card-text">{{ $task->description }}</p>
            <div class="mt-4">
                <p><strong>Creada:</strong> {{ $task->created_at->format('d/m/Y H:i') }}</p>
                <p><strong>Actualizada:</strong> {{ $task->updated_at->format('d/m/Y H:i') }}</p>
            </div>
            <div class="mt-4">
                <a href="{{ route('tasks.edit', $task->id) }}" class="btn btn-warning">Editar</a>
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">Volver</a>
            </div>
        </div>
    </div>
@endsection

5. Rutas (routes/web.php)

php
<?php

use App\Http\Controllers\TaskController;
use Illuminate\Support\Facades\Route;

// Página de inicio (lista de tareas)
Route::get('/', [TaskController::class, 'index'])->name('tasks.index');

// Mostrar formulario para crear nueva tarea
Route::get('/tasks/create', [TaskController::class, 'create'])->name('tasks.create');

// Guardar nueva tarea
Route::post('/tasks', [TaskController::class, 'store'])->name('tasks.store');

// Mostrar detalles de una tarea
Route::get('/tasks/{task}', [TaskController::class, 'show'])->name('tasks.show');

// Mostrar formulario para editar tarea
Route::get('/tasks/{task}/edit', [TaskController::class, 'edit'])->name('tasks.edit');

// Actualizar tarea
Route::put('/tasks/{task}', [TaskController::class, 'update'])->name('tasks.update');

// Eliminar tarea
Route::delete('/tasks/{task}', [TaskController::class, 'destroy'])->name('tasks.destroy');

// Cerrar sesión
Route::post('/logout', function () {
    auth()->logout();
    return redirect('/');
})->name('logout');

6. Controlador (app/Http/Controllers/TaskController.php)

php
<?php

namespace App\Http\Controllers;

use App\Models\Task;
use Illuminate\Http\Request;

class TaskController extends Controller
{
    public function index()
    {
        $tasks = Task::latest()->get();
        return view('tasks.index', compact('tasks'));
    }

    public function create()
    {
        return view('tasks.create');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable',
            'completed' => 'boolean'
        ]);

        Task::create($validated);

        return redirect()->route('tasks.index')
                         ->with('success', 'Tarea creada correctamente');
    }

    public function show(Task $task)
    {
        return view('tasks.show', compact('task'));
    }

    public function edit(Task $task)
    {
        return view('tasks.edit', compact('task'));
    }

    public function update(Request $request, Task $task)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable',
            'completed' => 'boolean'
        ]);

        $task->update($validated);

        return redirect()->route('tasks.show', $task)
                         ->with('success', 'Tarea actualizada correctamente');
    }

    public function destroy(Task $task)
    {
        $task->delete();

        return redirect()->route('tasks.index')
                         ->with('success', 'Tarea eliminada correctamente');
    }
}

Características de Blade demostradas en este ejemplo:

  1. Herencia de plantillas: Uso de @extends y @section

  2. Inclusión de contenido@yield en el layout y @section en las vistas

  3. Estructuras de control@if@else@foreach

  4. Directivas de Blade@csrf@error@method

  5. Mostrar datos{{ $variable }} con escape automático

  6. Condicionales en clasesclass="{{ $condition ? 'class1' : 'class2' }}"

  7. Formateo de fechas: Uso de métodos de Carbon (format())

  8. Sistema de rutasroute() para generar URLs

Este ejemplo proporciona una base sólida para entender cómo funciona Blade en Laravel y cómo estructurar una aplicación básica con las páginas que mencionaste.

Comentarios

Entradas más populares de este blog

0-Sistema de Tareas

13-CRUD en Laravel para Web y API con Rutas Normales (No Resource)