Laravel Blade: @ lengthen (already extended) baby blade?
Does anyone know if it is possible to extend the child blade?
My app has one generic layout template and then every page @ expands from that. Each page can contain a number of @includes for other HTML snippets as needed (like modals).
@extends('common.layout')
@section('content')
... Some other content ...
@include('modals.modal-1')
@include('modals.modal-2')
@endsection
All modals have a lot of common template code (Bootstrap), so what I would like to do is define the template for the main model, have all @extend modals from that, and then @ include those in my pages as required. So / modals / modal -1.blade.php would look something like this:
@extends('common.modals')
@section('modal-id', 'modal-1')
@section('modal-title','Modal title')
@section('modal-body')
... Some HTML / Blade here ...
@endsection
Every time I try, the generated HTML is corrupted. In the above case, modal-1 will be shown twice because it appeared first and modal-2 was missing at all. Reverse the order and modal-2 will appear twice.
I guess I can just put my modal body in a variable and use it in the @include statement @include('modal.blade', ['body' => '<div>...</div>'])
, but using @extends seems to be more correct.
Any ideas?
You can fully extend the Blade view from an already expanded view. However, you are mixing template inheritance with view inclusion, and this leads to your weird results.
When inheriting templates with a directive, @extend
you should always return the lowest child in the chain you want. Let's say you have 3 generations of templates:
//grandparent.blade.php
<html>
<head>
<title>My App</title>
</head>
<body>
@yield('parent-content')
</body>
</html>
//parent.blade.php
@extends('grandparent')
@section('parent-content')
<div class="container">
@yield('child-content')
</div>
@endsection
//child.blade.php
@extends('parent')
@section('child-content')
<div class="page">
//stuff
</div>
@endsection
In this case, you must return a child view, and it will also contain two generations of templates above it. But you can never return parent.blade.php
and expect it to return this child view as well. There might be 100 child views that extend the parent, so there would be no way to know which one.
Think of a directive @include
as an easy way to break the HTML in your view into smaller bits. Often, you will use it for multiple pieces of code that you want to reference across multiple views. However, this is not the same as template inheritance. Also remember that the included view will receive all the same data as its parent view (and you can even pass more of it).
In your case, you must decide what constitutes the main root of the page. Is the core of the page modal-1
? If so, you need to return modal-1
from your controller as your child view and chain it out. In this case, leave the file the same as you have in your post. Its parent view ( common.modals
) should be changed like this:
@extends('common.layout')
@section('content')
... Some other content ...
@yield('modal-id')
@yield('modals-title')
@yield('modal-body')
@include('modals.modal-2')
@endsection
Obviously, you would place each of these output statements where it makes sense on the page.
However, if modal-1
it is not the core of the page, but just something extra that you want to include (like a widget), then you should include
like you do in the parent view. In this case, you will need to remove the directive @extends
and not bother with wrapping the main HTML in any section. It will simply be transferred to the view as is. If you include sections in an included template, those sections must be assigned to the view that includes it. So your template modal-1
will look like this:
<div>
<p>HTML goes here. No need to extend anything or wrap in a section.
You can still include {{$data}} though.
</p>
</div>
@section('script')
Including this section means that the view that is including this template
already contains a @yield('script') directive.
By including the @parent directive, this section will append that one.
@parent
@endsection
I believe the correct way to include templates, which already extends some of the other templates, is to use @overwrite
instead @endsection
in your included template:
@extends('common.modals')
@section('modal-id', 'modal-1')
@overwrite
@section('modal-title','Modal title')
@overwrite
@section('modal-body')
... Some HTML / Blade here ...
@overwrite