Laravel 4 - Extending a section declared in a master template more than once

9.6k views Asked by At

I have a scenario where I have a master template which defines a header section. It looks like this...

<!DOCTYPE html>

<html>
<head>
@section('header')
    {{ HTML::style('css/planesaleing.css') }}
    {{ HTML::script('js/jquery-1.10.1.js') }}
    {{ HTML::script('js/search_Bar.js') }}
@show
</head>
<body>
    <div class="planesaleing_page">
        <header>
@yield('header_bar')
@yield('nav_bar')
@yield('search_bar')
        </header>
        <div class="main_page">
                // Some more code
        </div>
@yield('footer')
    </div>
</body>
</html>

As you can see, I have several child views (e.g. nav_bar and search_bar). Each of these child views has an accompanying .js file. So I would like to extend the 'header' section in nav_bar like this...

@section('header')
@parent
    {{ HTML::script('js/anotherjs.js') }}
@stop

and then again in search_bar like this:

@section('header')
@parent
    {{ HTML::script('js/yetanotherjs.js') }}
@stop

The intention is that the final outputted html file would look like this:

@section('header') {{ HTML::style('css/planesaleing.css') }} {{ HTML::script('js/jquery-1.10.1.js') }} {{ HTML::script('js/search_Bar.js') }} {{ HTML::script('js/anotherjs.js') }} {{ HTML::script('js/yetanotherjs.js') }} @show

However, only the first one actually extends the header, all others after this are seemingly ignored. Is there anyway to use multiple extensions?

Any advice - much appreciated.

1

There are 1 answers

1
Vivek V Dwivedi On BEST ANSWER

Firstly, when you extend a layout in a view, you start a section and then "stop". Like this:

@section('header')
@parent
    {{ HTML::script('js/anotherjs.js') }}
@stop

How are you extending the layouts? I am not sure if you have multiple layouts which extend each other and are then extended by views or you have multiple views, each extending this particular layout. Now in later case, one view is not going to have any effect on the other view.

If you are using former approach, some more example code would be helpful as I think you are over writing the values at some point of time.

Hope it helps.

EDIT

when you say:

<header>
   @yield('header_bar')
   @yield('nav_bar')
   @yield('search_bar')
</header>

You are making placeholders with three different names. So nav_bar, search_bar are not child views but they are placeholders which can be populated from your views.

Let me put it in another way. When your views extend a template, they will fill in the gaps declared in the template. So each of the 'header', 'search_bar' etc. are gaps to be filled ONCE. So if you have a view named index.blade.php, you can fill in these once. So you can have index.blade.php like this:

@section('header')
@parent
    {{ HTML::script('js/anotherjs.js') }}
@stop

@section('header_bar')
@parent
    {{ HTML::script('js/yetanotherjs.js') }}
@stop

@section('nav_bar')
@parent
    {{ HTML::script('js/foojs.js') }}
@stop
@section('search_bar')
@parent
    {{ HTML::script('js/foojs.js') }}
@stop

Now if we look at this, what it will result is:

<!DOCTYPE html>

<html>
<head>
@section('header')
    {{ HTML::style('css/planesaleing.css') }}
    {{ HTML::script('js/jquery-1.10.1.js') }}
    {{ HTML::script('js/search_Bar.js') }}//from parent till this point
    {{ HTML::script('js/anotherjs.js') }} //comes from view
@show
</head>
<body>
    <div class="planesaleing_page">
        <header>
{{ HTML::script('js/yetanotherjs.js') }} //comes in place of header_bar as nothing in parent

//@yield('header_bar')

{{ HTML::script('js/foojs.js') }}//comes in place of nav_bar as nothing in parent

//@yield('nav_bar')

{{ HTML::script('js/foojs.js') }}//comes in place for search_bar as nothing in parent

//@yield('search_bar')
        </header>
        <div class="main_page">
                // Some more code
        </div>
@yield('footer')
    </div>
</body>
</html>

This is why just the first one seems to be extending the master. I think you should once reconsider the way you are trying to extend the master.

What can work for you is

@include('view.name') // includes a subview

However I am not sure if the sections will be cascaded from each subview or not. You can try this out.

So you will have a view called index.blade.php which looks some what like:

@extends('master')

@include('search_bar')
@include('nav_bar')
@include('foo_bar')

and then you will have separate files like search_bar.blade.php and others which will extend master and fill in the placeholders like this:

@extends('master')
 @section('header')
 @parent
    {{ HTML::script('js/anotherjs.js') }}
 @stop

I believe (havn't tested) that this should do your work. It can then cascade the inputs from all subviews and put it together like you want. So all the subviews will be populating the header section and this should be cascaded together in the final output. Try it out and if it works, GREAT !! else try a different approach to injecting the scripts.