2
votes

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.

3

3 Answers

2
votes

Found a solution, for what it is worth.

  1. I create 2 new /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 create 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 create 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...

0
votes

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'));
-1
votes

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.