Use Laravel View Composer to share data in partial views

Ever been in a situation where you have to share some data with multiple views? I have. If you are passing it in every controller pretty soon it will get very messy since you end up duplicating same code in multiple controllers which is against the DRY principle. Let’s learn about view composer provider by Laravel which eliminate this issue and gives you a single place to attach your logic for view data.

What is View Composer?

You can think View composer as a callback which will run when an attached view is rendered, here you can run some code and pass data when a view is requested.

For example, If you have a nav view in sidebar view which needs a list of menu items from the database, you bind a callback to partials.nav which fetch the data from DB and show it. So no matter in how many places you need this view partial you can just include without worrying about passing any data item through a controller, this view will be composed of with data by View Composer.

Passing data into View

You can pass data into Laravel views using one of following options.

Pass Data using with method on view.

public function index()
{
    $nav = Nav::active()->get();
    return view('partials.nav')->with('nav', $nav);
}

Pass data as the second argument in the view() helper.

public function index()
{
    $nav = Nav::active()->get();
    return view('partials.nav', ['nav' => $nav]);
}

Pass data as with compact method which turns variable into a key-value array.

public function index()
{
    $nav = Nav::active()->get();
    return view('partials.nav', compact('nav'));
}

It’s all good, but things get tricky when we find yourself doing this in every controller method which needs the menu, to solve this kind of situation we can use View Composer.

Setup View Composer

Let’s see an example, where you want to show some navigation menu items in the sidebar, it will be a partial view which you can use in many places throughout the app.

By default laravel don’t have a directory for View Composer it’s up to you. Laravel recommends to create an app/Http/ViewComposers folder to store your view composers.

Create NavComposer

This composer will simply attach the menu items to view from database.

namespace App\Http\ViewComposers;

use App\Nav;

class NavComposer
{
    public function compose($view)
    {
        $view->with('menu', Nav::all());
    }
}

Now run the php artisan make:provider ComposerServiceProvider to create the our view composer provider in app/Providers folder.

Register Service Provider

Like any other provider add the ComposerServiceProvider class to config/app.php array for providers so that laravel is able to resolve it.

'providers' => [
    ...
    App\Providers\ComposerServiceProvider::class,
]

In order to make composer work, we will need to register it in ComposerServiceProvider@boot method.

namespace App\Providers;

use App\Nav;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        // You can use a class for composer
        // you will need NavComposer@compose method
        // which will be called everythime partials.nav is requested
        View::composer(
            'partials.nav', 'App\Http\ViewComposers\NavComposer'
        );

        // You can use Closure based composers
        // which will be used to resolve any data
        // in this case we will pass menu items from database
        View::composer('partials.nav', function ($view) {
            $view->with('menu', Nav::all());
        });
    }
}

You will need to use one of above option to compose the view, first is to use a dedicated class NavComposer with compose method, or you can use a Closure which is most ideal in most of case since you should already have a repository to get the data from database.

Make sure to provide full path of your view in View::composer('partials.nav', handler) to resolve it, in this case I have nav.blade.php inside resoources/views/partialsfolder.

Attach a Composer to multiple views

If same data is needed in multiple views you can pass views as array View::composer(['partials.nav', 'partials.top-nav'], handler)this will bind it to both views.

And you can also pass * wildcard to make this data available in all views.

View::composer('*', function ($view) {
      $view->with('menu', Nav::all());
});

View Creators

View creators are similar to composer with slight difference, they are executed immediately after the view is instantiated instead of waiting until the view is about to render. You can use theme exactly the same way as view composer but you will need to call creator method instead of composer.

View::creator('partials.nav', function ($view) {
    $view->with('menu', Nav::all());
});

Conclusion

View composer can make your views more independent since data needed by a view can be bind directly without need of passing it from controller. This will make your code cleaner and maintainable in long run. I hope it helps and let me know if you need any help.