Laravel's Blade template #yield and #section how does it work? - php

I'm new to Laravel and want to learn how to use the Blade template system properly, but i cant wrap my head around the difference between #section and #yield.
I've been reading the docs : https://laravel.com/docs/5.7/blade.
But it's not explaining the differences and how to use them properly.
I've been reading posts in other forums too like this one :
https://laravel.io/forum/09-02-2014-using-section-and-yield
But still i'm a bit confused.
For example right now i'm creating an app that have multiple pages with commun pieces between them, so for now i get that i have to create a common layout for this pages, but when to use #section and when do i have to use #yield ?
for example if i have a page like so :
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<title>{{ config('app.name', 'Name') }}</title>
//Common CSS between pages
<link href="{{ asset('css/style1.css') }}" rel="stylesheet">
//Changing CSS between pages
<link href="{{ asset('css/style2.css') }}" rel="stylesheet">
</head>
<body>
//the content stay the same !
<div id="app">
<span id="some_style">hello world !</span>
</div>
<script>
//common JS
<script src="{{ asset('script1.js') }}">
//Changing JS between pages
<script src="{{ asset('script2.js') }}">
</script>
</body>
</html>
How can i organise it using the blade templating?

Assuming you 2 templates. Lets call one Base.blade.php and the other one Posts.blade.php.
We'll #extends('base') in Posts.
Using #section in Posts and #yield in Base.
Something like this:
Base
#yield('posts') {# the section called "posts" #}
Posts
#extends('base')
#section('posts')
Here be posts
#endsection
Whatever is written in posts will be yielded in the base blade.
Think of it as inheritance.
You can imagine it as classes if you will. Where the child class calls a method in the base class.
class Base {
protected function printSomething($something) {
echo $something;
}
}
class Posts extends Base {
public function BaseWillPrint() {
$this->printSomething('POSTS');
}
}
Basically I haven't told you anything that doesn't already exist in the documentation.

Yes, assuming if you have a template you can make the base of template in layouts/app.blade/php and you can make the #yield('anything') and then in your views/main.blade.php you must give #extends('layouts.app') and
#section('anything')
*for dynamic page
#endsection

Related

Interpolate #yield() value within {{}} or the asset() helper in Laravel

I want to interpolate a #yield('page-name') value in the asset() helper method:
I think that blade directives cannot be used with php (I mean within {{}})
This is what I'm trying to do:
//guest.blade.php file
<html>
<head>
<title>{{ config('app.name', 'Laravel') }} - #yield('title')</title>
// this throws an error
// ParseError: syntax error, unexpected token "<"
<link rel="stylesheet" href="{{ asset('css/'. #yield('view-asset') .'.css') }}">
</head>
<body>
#yield('content')
</body>
</html>
//login.blade.php file
#extends('layouts.guest')
#section('title', 'Login-page')
#section('view-asset')
#section('content')
...
#endsection
How can do a similar implementation, to what I'm trying to do here?
You can use view() helper function.
Illuminate\View\View namespace holds Illuminate\View\Factory in it which contains data like files, paths, hints, views, section, etc.
To get yield data (retrieved from section directive of child view), In your parent view:
view('your.view')->getFactory()->getSection('page-name');
You can also pass a default value for the section.
view('your.view')->getFactory()->getSection('page-name' , 'default value');
Which in your case it would be like this:
<link rel="stylesheet" href="{{ asset('css/'.view("directory.guest")->getFactory()->getSection("page-name" , "default_value").'.css') }}">

Resource routing

so I'm relatively new to laravel and am trying to understand it. So far it has been good but I've been stuck at an error for a while now so any help would be appreciated.
I'm trying to follow along with a youtube tutorial (not sure if links are allowed) and this is what I'm trying to do,
I've a controller called, CarsController Inside my controllers file and a model named Car
I've generated the CarsController page by using the --resource flag, so inside my index function I've this code.
public function index()
{
return view('index'); //Error here, replace with return view (cars.index);
}
inside my web.php page for routing I've the following command
use App\Http\Controllers\CarsController; //added by me
use Illuminate\Support\Facades\Route; //present by default
Route::resource('/cars', CarsController::class);
As far as I understood from the documentation, using resource routing is better as I don't have to write the routes for every function that exists in my controller.
Also, the page I'm trying to view has a directory hierarchy of something like
resources > views > cars > index.blade.php
That is the file I'm trying to access. Sorry if this is a noob question by I've tried looking at the documentation and googling and don't understand what I'm doing wrong exactly.
Lastly, the error I'm receiving is a basic 404 one when accessing http://127.0.0.1:8000/.
if I try accessing http://127.0.0.1:8000/cars I just get index is not a file are you the blade.php view exists. Also if it matters I've deleted the default welcome page file that laravel includes inside the views folder.
This is my route list through the PHP artisan command,
Edit: This is the documentation I'm, referring https://laravel.com/docs/8.x/controllers#resource-controllers
Edit2: My code for cars/index.blade.php
#extends('layouts.app')
#section() //error here too, replace with #section('content')
<div class="m-auto w-4/5 py-24">
<div class="text-center">
<h1 class = "text-5xl uppercase bold">
Cars
</h1>
</div>
</div>
#endsection
Im using tailwind CSS if it matters.
layouts/app.blade.php
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{ assset('css/app.css') }}">
<title>Document</title>
</head>
<body class="bg-gradient-to-r from gray-100 to-gray-200">
#yield('content')
</body>
</html>
Your blade located at resources > views > cars > index.blade.php,
so your view() method will be view('cars.index') :
public function index()
{
return view('cars.index');
}
Inside your method you can return the view as return view('cars.index'); where the index is the index.blade.php file inside the cars folder.

Blade template - #extends & #section not working

I'm learning the laravel framework and trying to get to grips with using the blade template engine. However i cant for life of me get the #extends and #section functionality to work within my project.
I have already tried reinstalling the whole project multiple times, using different browsers and restarting my machine but i cant figure out why it doesn't display the #section content
Laravel Version: 5.7.28 |
IDE: PhpStorm
routes/web.php
Route::get('/', function () {
return view('layouts/index');
});
views/layouts/index.blade.php
<body>
<div class="container-fluid">
<h1>Site Index</h1>
#yield('header')
</div>
</body>
views/header.blade.php
#extends('layouts.index')
#section('header')
<p>Header</p>
#endsection
At the moment all that is being displayed is the tag in the views/layouts/index.blade.php file.
Thank you very much for any and all input on this.
That's not how the templating works. You have to reference the child template in your return statement. Because the #extends is in this child template, Laravel knows to use the mentioned master layout. So your return statement would be like so:
return view('header');
If you just want the header to be displayed on every page, you don't need to extend the master layout in your header, you should just include the header part in your master layout.
<body>
<div class="container-fluid">
<h1>Site Index</h1>
#include('header')
</div>
</body>
i have tested the view and layout they seems working. check your controller return statement. try return view('header');
Route::get('/', function () {
return view('header');
});
thanks all for your responses, now i understand how the blade template engine works a little better and how i was doing this wrong. Just for clarification for others that get confused like me and come across this thread:
When you are redirecting to a view through the web routes then it has to be a child that is extending from a layouts master.
routes/web.php
Route::get('/', function () {
return view('index');
});
The html from the master file will then be displayed by default and its the content that we are "viewing"
views/layouts/master.blade.php
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>#yield('title', 'default title if unspecified')</title>
</head>
<body>
<h1>Master Header</h1>
#yield('content')
</body>
</html>
To work with the content of the page then its the index view that is worked with using the #section('content') method.
views/index.blade.php
#extends('layouts.master')
#section('title', 'Changing the default title')
#section('content')
<p>content displayed</p>
#endsection
I hope this helps for anyone else.
If you want to show content of section('header') then you must return header view like
Route::get('/', function () {
return view('header');
});
this is because contents are in header view and you have been extending layout.index
so if you return layout.index view you will not see content of section('header')

Passing variables through blade includes in Laravel

I'm a beginner in Laravel and I'm getting practices converting a previous (simple) website to Laravel.
Basically, I created a template having HTML structure and I change the main content using #includes and #yield
The interesting parts in html template.blade.php are like
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<!-- Title -->
<title>#yield('title')</title>
....
....
<!-- CSS Customization -->
<link rel="stylesheet" href="/assets/css/custom.css">
#yield('css')
....
....
#include('include._header')
#include('include._test_script')
#include('include._footer')
....
....
<!-- JS Customization -->
<script src="/assets/js/custom.js"></script>
#yield('js')
The router calls the test.blade.php which include the template. This blade file has some custom php code having the $extra_script variable
<?php $extra_script = " alert(0); console.log(0);";?>
#extends('layouts.template')
#section('css')
....
#endsection
#section('js')
...
<script>
{!! $extra_script !!}
</script>
#endsection
Loading this page the script works fine and I see the alert message having the 0 content.
Now I'm trying to update the $extra_string into the /include/test_script.blade.php file but it doesn't work.
This include blade file is like:
#php
$extra_script = " alert(1); console.log(1);";
#endphp
or
<?php $extra_script = " alert(1); console.log(1);"; ?>
The result is no errors and still alert(0) shown.
I understand is not elegant to have PHP code in the blade template but in the controller but this is a quick and fast porting to have the website online in a few time.
How to fix it in view?
I would say the order is incorrect, first test.blade.php is extending from template.blade.php. It is template.blade.php the one setting the alert to 1 by #include('include._extra_script') but then as test.blade.php is extending from that template, it is overwriting $extra_script to the one that alerts a 0.

organizing script files for different pages in laravel

Let us say i have two pages based on laravel and I have different script files for both the pages.Now I am loading all the scripts in index.blade.php.As per the present implementation all the scripts are loaded in both cases.How to load different script files for different pages and also load scripts after the html.
I am not familiar with require.js which was stated as an alternative by #jsxqf in the comments.
I personally have yields in my master-layout (one for js, one for css) which i am adressing using blade. In your views, you could do the same.
File layout/master.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>title</title>
<link rel="stylesheet" href="style.css">
#yield('css-scripts')
</head>
<body>
#yield('content')
</body>
<script src="script.js"></script>
#yield('js-scripts')
</html>
Your views would then extend this layout and put the scripts independently in the corresponding sections like so:
File myview.blade.php
#extends('layout.master')
#section('content')
// your content...
#stop
#section('js-scripts')
// here, you have control over additionally loaded scripts...
<script src="otherscript.js"></script>
#stop
But it looks like require.js might be a good alternative to this approach, which i wasn't aware of until now.
The best approach you can do is creating a section to put optional scripts using stack on your main layout
<html>
<head>
<!-- At the end of head -->
#stack('styles')
</head>
<body>
<!-- At the end of body -->
#stack('scripts')
</body>
</html>
In a normal view which would be your page,
#extends('layouts.app')
#push('styles')
<link rel="stylesheet" href="{{ asset('css/page1.css')}}">
#endpush
#section('content')
// page content
#endsection
#push('scripts')
<script src="{{ asset('js/page1.js')}}"></script>
#endpush
This allows you to add additional optional scripts and styles to your main layout from other views, making it completely safe to organize styles / scripts in your views

Categories