Índice de contenido
Para hacer el uso de los mensajes flash en Laravel Inertia, aunque desde el controlador, podemos usar las operaciones típicas para establecer los mensajes de sesión tipo flash.
Vamos a implementar un mensaje de confirmación que se muestre luego de ejecutar una operación (crear, actualizar o eliminar).
Esto funciona distinto a Laravel tradicional, porque Inertia no expone automáticamente los mensajes flash en el cliente. Pero lo podemos configurar fácilmente.
$request->session()->flash('message', 'Message');O mediante la redirección:
with('message','Message');Pero, al usar componentes en Vue y no vistas de blade, tenemos que hacer un paso extra para pasar estos datos vía sesión flash.
Anteriormente, este proceso era bastante manual y algo fastidioso. Teníamos que ir al middleware HandleInertiaRequests (el intermediario entre la petición y el componente Vue) y compartir manualmente los datos en el método share.
Ahora, con las versiones más recientes, el enfoque se ha optimizado. Podemos usar directamente Inertia::flash en el controlador y leerlo de forma sencilla en la vista utilizando el composable usePage.
Inertia Share
Con las versiones más recientes, el enfoque se ha optimizado. Podemos usar directamente Inertia::flash en el controlador y leerlo de forma sencilla en la vista utilizando el composable usePage.
app/Http/Controllers/dashboard/PostController.php
namespace App\Http\Controllers\Dashboard;
use App\Http\Controllers\Controller;
use App\Http\Requests\PostRequest;
use App\Models\Category;
use App\Models\Post;
use Inertia\Inertia;
class PostController extends Controller
{
public function index()
{
$posts = Post::with('category')->paginate(10);
return inertia('dashboard/post/Index', compact('posts'));
}
public function create()
{
$post = new Post;
$categories = Category::orderBy('title')->get(['id', 'title']);
return inertia('dashboard/post/Save', compact('post', 'categories'));
}
public function store(PostRequest $request)
{
Post::create($request->validated());
Inertia::flash('message', 'Post created successfully.');
return to_route('post.index');
}
public function edit(Post $post)
{
$categories = Category::orderBy('title')->get(['id', 'title']);
return inertia('dashboard/post/Save', compact('post', 'categories'));
}
public function update(PostRequest $request, Post $post)
{
$post->update($request->validated());
Inertia::flash('message', 'Post updated successfully.');
return redirect()->route('post.index');
}
public function destroy(Post $post)
{
$post->delete();
Inertia::flash('message', 'Post deleted successfully.');
return to_route('post.index');
}
}Te dejo la implementación actual aunque en el siguiente apartado te muestro la implementación actual:
Compartir el mensaje flash con Inertia (HandleInertiaRequests)
En Inertia, tenemos un middleware que se encarga de interceptar las peticiones del usuario; desde este middleware, podemos establecer datos globales a los componentes en Vue; por lo tanto, si quieres pasar datos globales a los componentes desde la base de datos, archivos, configuraciones, sesión, etc:
return array_merge(parent::share($request), [
'appName' => config('app.name'),
'auth.user' => fn () => $request->user()
? $request->user()->only('id', 'name', 'email')
: null,
]);Debes de usar este middleware; para el caso de los mensajes flash; puedes usar un esquema como el siguiente:
app/Http/Middleware/HandleInertiaRequests.php
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'flash' => [
'message' => $request->session()->get('message')
]
]);
}En el ejemplo anterior, estamos suponiendo que vamos a usar una sola clasificación de mensajes flash, pero, puedes usar cuantos necesites; por ejemplo:
app/Http/Middleware/HandleInertiaRequests.php
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'flash' => [
'message' => $request->session()->get('message'),
'status' => $request->session()->get('status')
***
'other' => $request->session()->get('other')
]
]);
}En el ejemplo anterior, usamos un array de array para organizar los mensajes flash al considerar que es un esquema escalable y organizado para poder definir otros esquemas que quieras pasar de manera global.
Objeto $page
El objeto $page es una variable que se puede acceder de manera global en todos los componentes en Vue, tiene datos variados como:
{
"component": "Dashboard/Post/Index",
"props": {
"jetstream": {
"canCreateTeams": true,
"canManageTwoFactorAuthentication": true,
"canUpdatePassword": true,
"canUpdateProfileInformation": true,
"hasEmailVerification": false,
"flash": [
],
"hasAccountDeletionFeatures": true,
"hasApiFeatures": true,
"hasTeamFeatures": true,
"hasTermsAndPrivacyPolicyFeature": true,
"managesProfilePhotos": true
},
"user": {
"id": 1,
"name": "andres",
"email": "admin@gmail.com",
"email_verified_at": null,
"two_factor_confirmed_at": null,
"current_team_id": 1,
"profile_photo_path": null,
"created_at": "2022-05-31T15:10:22.000000Z",
"updated_at": "2022-05-31T15:28:19.000000Z",
"profile_photo_url": "https://ui-avatars.com/api/?name=a&color=7F9CF5&background=EBF4FF",
"current_team": {
"id": 1,
"user_id": 1,
"name": "andres's Team",
"personal_team": true,
"created_at": "2022-05-31T15:10:22.000000Z",
"updated_at": "2022-05-31T15:10:22.000000Z"
},
"all_teams": [
{
"id": 1,
"user_id": 1,
"name": "andres's Team",
"personal_team": true,
"created_at": "2022-05-31T15:10:22.000000Z",
"updated_at": "2022-05-31T15:10:22.000000Z"
}
],
"two_factor_enabled": false
},
"errorBags": [
],
"errors": {
},
"data": ...
"url": "/post",
"version": "207fd484b7c2ceeff7800b8c8a11b3b6"
}- props → Los datos que envía Laravel
- url → Ruta actual
- component → Nombre del componente Vue actual
- flash → Nuestros mensajes flash (si los configuramos)
- auth → Info del usuario autenticado
- etc.
Y por supuesto, los datos que establezcamos en el middleware de HandleInertiaRequests se encuentran aquí también.
Mostrar el mensaje flash en el layout
Vamos a establecer los mensajes flash de confirmación en cada una de las redirecciones definidas anteriormente:
app/Http/Controllers/Dashboard/CategoryController.php
class CategoryController extends Controller
{
public function store(Store $request)
{
Category::create($request->validated());
return to_route('category.index')->with('message',"Created category successfully");
}
public function update(Put $request, Category $category)
{
$category->update($request->validated());
return redirect()->route('category.index')->with('message',"Updated category successfully");
}
public function destroy(Category $category)
{
$category->delete();
return to_route('category.index')->with('message',"Deleted category successfully");
}
}Para usarlos desde los componentes en Vue, en vez definirlos manualmente en cada uno de los componentes que queramos que tengan el mensaje de confirmación, lo podemos colocar en un componente global como el de AppLayout:
resources/js/Layouts/AppLayout.vue
***
<main>
{{ $page.props.flash.message }}
<slot />
main>
***Y al realizar cualquier operación de eliminación, creación o actualización en este caso, tendremos:
Updated category successfully
Estilo para el contenedor del mensaje flash
Vamos a dar un estilo para el mensaje de confirmación anterior; para eso:
resources/js/Layouts/AppLayout.vue
if="$page.props.flash.message"
class="
container my-2 bg-purple-300 text-purple-800 px-4 py-3 rounded shadow-sm"
>
{{ $page.props.flash.message }}
</div>
>¿Por qué desaparece después del primer request?
Porque estamos usando un mensaje flash:
- ✔ dura 1 request
- ✔ en el siguiente ya no existe
- ✔ por eso $page.props.flash.message se vuelve null automáticamente
Esto es exactamente igual que en Laravel tradicional.
Funcionamiento real: Vue + servidor + Inertia
- Aunque la app luce como un SPA, cada acción que ejecutas (crear, actualizar, eliminar, etc.) provoca una petición al servidor, y el servidor:
- recibe el request
- crea o no el mensaje flash
- responde con otro request de Inertia
- Vue actualiza la vista con $page.props.flash
No hay magia:
- ✔ son peticiones reales
- ✔ los mensajes flash duran una sola petición
- ✔ Inertia solo ayuda a transportarlos hacia el cliente
Crea tu primer componente, un componente de paginación con Laravel Inertia.
Aprenderemos a generar mensajes Flash en Laravel Inertia, que son mensajes que solamente duran una petición o request lo cuales son ideales para mostrar confirmación de una acción realizada como la de eliminar.
Acepto recibir anuncios de interes sobre este Blog.
<script>
window.addEventListener('scroll', function() {
if (window.scriptsLoaded) return;
loadThirdPartyScripts();
}, {
once: true
});
window.addEventListener('mousemove', function() {
if (window.scriptsLoaded) return;
loadThirdPartyScripts();
}, {
once: true
});
window.addEventListener('touchstart', function() {
if (window.scriptsLoaded) return;
loadThirdPartyScripts();
}, {
once: true
});
// Fallback if no interaction
window.addEventListener('load', function() {
setTimeout(function() {
if (!window.scriptsLoaded) loadThirdPartyScripts();
}, 8000);
});
function loadThirdPartyScripts() {
if (window.scriptsLoaded) return;
window.scriptsLoaded = true;
console.log('Loading third party scripts...');
// Google Analytics
var gtagScript = document.createElement('script');
gtagScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-F22688T9RL';
gtagScript.async = true;
document.head.appendChild(gtagScript);
gtagScript.onload = function() {
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-F22688T9RL');
};
// Google ADS
const adScript = document.createElement('script');
adScript.src = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
adScript.setAttribute('data-ad-client', 'ca-pub-5280469223132298');
adScript.async = true;
document.head.appendChild(adScript);
// Facebook Pixel
(function(f, b, e, v, n, t, s) {
if (f.fbq) return;
n = f.fbq = function() {
n.callMethod ?
n.callMethod.apply(n, arguments) : n.queue.push(arguments)
};
if (!f._fbq) f._fbq = n;
n.push = n;
n.loaded = !0;
n.version = '2.0';
n.queue = [];
t = b.createElement(e);
t.async = !0;
t.src = v;
s = b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t, s);
})(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '1643487712945352');
fbq('track', 'PageView');
}
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=1643487712945352&ev=PageView&noscript=1" />
</noscript>