Using 2 different blade root template for Vue, with Laravel 8 and Inertia?
Asked Answered
M

3

7

So I am working on a Laravel 8 app, with Inertia and Vue.

The idea is that most of the pages are Laravel + Blade (good for SEO, fast loading etc...), but for selected pages that need a lot of user interactions, I insert a Vue component in the Blade Template where the interactions need to happen.

With Inertia, this is done by calling the Vue component with return Inertia::render('vueComponent') in the Controller that is called by the Laravel Route. Data can be passed to the Vue instance, and even to the Blade template, so this is good (see below).

namespace App\Http\Controllers;
use Inertia\Inertia;

class RangePageController extends Controller
{
    public function show(string $lang='fr')
    {
        // Strip the trailing slash from $lang
        $lang = Str::before($lang, '/');

        return Inertia::render('ProductsGallery', ['bar' => "Hello World"])->withViewData(['lang' => $lang]);
    }
}

And by default, the file "/resources/views/app.blade.php" is rendered with the Vue component replacing the @inertia directive (plus some Vue Data). Neat.

By default, the Blade layout file "app.blade.php" is used. The doc specifies that the default can be changed: Inertia\Inertia::setRootView('name');.

The Question: rather than changing the default, is there a way to choose different Blade layout files when calling different pages from the Controller (and inject the Vue component as above)? For instance I would like to use one Blade layout for my e-commerce basket, and a different one for my admin pages. Like choosing "app1.blade.php" for a page, and "app2.blade.php" for another.

Many thanks! E.

Marlie answered 17/3, 2021 at 19:12 Comment(0)
M
11

Found a solution, for what it is worth.

  1. I created 2 new App\Http\Middleware, extending the HandleInertiaRequest.php middleware.
  2. In each extended class, I set the protected $rootView to point to the custom Blade layout file in /resources/views.
    For instance protected $rootView = 'admin.app';, to point to /resources/views/admin/app.blade.php, and the same for the 'web' app.blade.php.
  3. Then I created a second "admin" middleware group in Kernel.php replicating the list in the "web" group, and I replace the default \App\Http\Middleware\HandleInertiaWebRequests::class lines with the extended classes (in the "web" and the "admin" groups).
  4. And I created an "admin" route file in the "routes" folder to host the routes that will use the "admin" layout. The routes in the default "web" route file will use the Blade layout that sits in resources/views/web/.

Probably some better solutions, but this one seems to work.

Note: I have seen a discussion on GitHub to do the same, but in addition to have 2 different Vue instances: one for "web", and one for "admin". Not sure what this brings, but I am still looking for a way to do it! If anybody has an idea...

Marlie answered 18/3, 2021 at 10:26 Comment(1)
Its actually a good Idea,, have inertiajs did talk about this?Stitt
O
4

Just a little bit update your HandleInertiaRequests

public function version(Request $request)
    {
        // Add the root view tho the version hash.
        // This forces inertia to make a hard reload when the template changes.
        return $this->rootView . parent::version($request);
    }

public function handle(Request $request, \Closure $next, $rootView = null)
    {
        if ($rootView) {
            $this->rootView = $rootView;
        }

        return parent::handle($request, $next);
    }

Also remove HandleInertiaRequests from global middleware and add it as named middleware

    protected $routeMiddleware = [
         ...
        'inertia' => \App\Http\Middleware\HandleInertiaRequests::class,
    ];

and now you can populate routes, routes groups as you need

Route::group(['middleware' => ['Admin:Client.Dashboard.app']], function () {
    Route::get('/admin/dashboard', [
        'as'   => 'admin.dashboard',
        'uses' => 'Admin\DashboardController@index',
    ]);
});
Route::middleware('inertia:app')
    ->group(base_path('routes/auth.php'));
Otolaryngology answered 25/7, 2021 at 14:56 Comment(0)
S
0

You can change the root template of interia in middleware(HandleInertiaRequest.php) using property and also with method

// Set root template via property
protected $rootView = 'app';

// OR
// Set root template via method
public function rootView(Request $request)
{
    return 'app';
}

Now filter the request in rootView() method and change the root template according to your need just using a simple if-else conditions.

Stets answered 30/4, 2021 at 17:35 Comment(1)
You can remove the OR here then do return $this->getGuardNameCustomFunctionYouCreated() . app; if you separate the pages by guard name.Charlsiecharlton

© 2022 - 2024 — McMap. All rights reserved.