×

back Mastering view mixins

In this tutorial we will look at how to register areas for view mixins, enabling other packages to extend your views. We then look at some advanced use cases of view mixins.

You have used view mixins before to extend existing views with a new package (if you haven't, start there and come back later). But how can you enable others to extend the views of your package? Let's have a look at how registering new areas for mixins works.

Implementing a new area for view mixins

Implementing a new area for view mixins is not a great deal. Everything happens in the view so no controllers need to be changed if new mixins are added (especially handy for mixins in the global navbar)!

Handling the mixins in the view

View mixins are basically no more than a dynamic usage of the @include control structure of the Blade templating engine. With @include you can take a view and insert it into another view making view modularization and separation of concerns possible. Adding a view mixin to a view is nothing else than @include-ing it, except the name of the view to load is dynamically fetched from the Biigle\Services\Modules service.

But first we need to inject the Modules service into the view like this:

@inject('modules', 'Biigle\Services\Modules')

Now the service can be used to fetch the names of all views that should be included as a mixin. Let's take a look at how the dashboard view handles including the mixins:

@foreach ($modules->getMixins('dashboardMain') as $module => $nestedMixins)
   @include($module.'::dashboard', ['mixins' => $nestedMixins])
@endforeach

First, it makes use of the @forelse Blade control structure to display a message if there are no view mixins. Otherwise it loops over all the content of the array returned by the modules service. Each item is a key-value pair called $module as the key and $nestedMixins as the value. We'll set aside the nested mixins for the next section.

The $module variable for each item contains the view namespace of the package that registered the mixin. If your package were called quotes and you wanted to load the dashboard view from it, you'd access it with quotes::dashboard. The part before the :: is the view namespace of the package (the namaspace is defined by the loadViewsFrom method, really, not by the package name but you should always use the same identifiers).

Following the convention over configuration paradigm, if a package wants to add a mixin to the dashboard view, the mixin should be called dashboard, too (resulting in views/dashboard.blade.php in the package). If a view has multiple areas reserved for mixins, these identifiers can differ. We'll cover that in a later section.

Now you know how view mixins essentially work. Using the code snippets from above as an example, you are able to allow view mixins to be added to a view of your own package. Let's now have a look at some advanced use cases for view mixins.

Nested mixins

Let's stay in the dashboard example. If you fiddle with the providers array of BIIGLE' config/app.php and disable the volumes module, you'll notice on the dashboard that the volume thumbnail images inside of the project boxes disappear. If you then disable the projects module as well, the project boxes will disappear, too. So the volume thumbnails and project boxes both must be view mixins. But the thumbnails are inside of the project boxes so there must be a mechanism for nesting view mixins.

Displaying nested mixins

We have already seen the $nestedMixins variable in the code snippet above. Let's take a closer look at it:

@foreach ($modules->getMixins('dashboardMain') as $module => $nestedMixins)
   @include($module.'::dashboardMain', ['mixins' => $nestedMixins])

Previously we only talked about keys of the mixins array ($module). The values of the array ($nestedMixins) contain an array of nested view mixins that should be inserted into the current mixin. Let's take the volumes thumbnails and project boxes as an example.

The project boxes are the first level of mixins that are added to the dashboard; this works just as described in the previous section. Now the volume thumbnails should be added to each project box. These are the second level of mixins, supplied to the project box mixin as an additional argument of @include. The structure can be visualized in a tree like this:

$modules->getMixins('dashboardMain')
├─ projects (the project boxes)
│  └─ volumes (the volume thumbnails for each box)
│     └─ empty
└─ quotes (the inspiring quotes box)
   └─ empty

Like this, the mixins could theoretically be nested infinitely deep. But how do we register one of those nested mixins in a package?

Registering nested mixins

If your Laravel application has lots of views you should order them in different directories. Views ordered like that can be accessed using the dot notation, e.g. the view public/views/admin/profile.php can be accessed with view('admin.profile'). Nested mixins make use of this method of accessing views; let's see how.

The view mixin for the project boxes of the dashboard is registered as usual:

$modules->addMixin('projects', 'dashboardMain');

The view mixin registration of the volume thumbnails looks a bit different, though:

$modules->addMixin('volumes', 'dashboardMain.projects');

Here, a mixin of the volumes namespace is registered for the projects mixin on the dashboardMain view.

While the project box mixin simply is the file views/dashboardMain.blade.php, the volume thumbnail mixin has to be the file views/dashboardMain/projects.blade.php. So here, again following convention over configuration, the dashboardMain.projects identifier is used both to determine the area, the mixin should be inserted into, and the source file.

Registration and serving of nested mixins is handled by the Modules service so nested mixins work out of the box. For a "live" example take a look at the projects and volumes modules mentioned in this tutorial.

Asset mixins and multiple mixins per view

Until now we have only talked about registering one area for view mixins per page. There are use cases, though, where you'd want or are even required to have multiple of those areas on one page. Let's take a look at one of the situations where multiple areas for view mixins are necessary.

Having the example of the project box mixins containing volume thumbnail mixins still in mind, think about what whould happen if we tried to add a custom style to the volume thumbnails. "Of course", you'd say, "there is the styles stack we can append our CSS to." But the downside of this approach is: the custom style tag is appended each time the mixin is included. While this is fine for the project box mixin that is included only once, it becomes a problem with nested mixins like the volume thumbnails that are included multiple times. So for each project box on the dashboard, one custom style tag woul be appended to the page. There is a better way to do this.

In fact there is nothing preventing us to implement a separate "style" mixin and add it to the dashboard. That's exactly what is already provided by the dashboard, looking like this:

@push('styles')
   @foreach ($modules->getMixins('dashboardStyles') as $module => $nestedMixins)
      @include($module.'::dashboardStyles')
   @endforeach
@endpush

Any mixin registered for dashboardStyles will be appended once to the styles section of the dashboard. Since nested mixins don't make any sense in this case, they are not passed on to the first level mixin.

Now, if we wanted to add a custom style to the volumes thumbnails we would create a mixin called views/dashboardStyles.blade.php looking like this:

<link href="{{ asset('vendor/volumes/styles/main.css') }}" rel="stylesheet">

And - in the service provider - register it to the dashboard styles section:

$modules->addMixin('volumes', 'dashboardStyles');

Now the custom style for the volume thumbnails is included only once in the dashboard but available to all the multiple instances of the thumbnail mixin. The same holds for custom scripts (there is a dashboardScripts mixin area). Aside from styles and scripts of nested mixins, you can use this technique to specify multiple arbitrary areas for view mixins on one page, e.g. one for a sidebar, title bar or the content each.

Conclusion

Now we have de-mystified the mechanisms behind view mixins and you know how to register areas for view mixins, use nested mixins and in which situations asset mixins are required. You can now consider yourself a fully qualified BIIGLE package developer!