If you look to laravel official documentation http://laravel.com/docs/4.2/templates
It says that giving this layout:
<!-- Stored in app/views/layouts/master.blade.php -->
<html>
<body>
#section('sidebar')
This is the master sidebar.
#show
<div class="container">
#yield('content')
</div>
</body>
</html>
Extended by this view
#extends('layouts.master')
#section('sidebar')
<p>This is appended to the master sidebar.</p>
#stop
#section('content')
<p>This is my body content.</p>
#stop
Will append to the section sidebar. But actually if you try is it doesn't append, it just override the content from the extended template.
I heard about others blade function like #append, #prepend, #parent... no one seems to work.
Beside, this example in the official doc which doesn't work, I find that the blade documentation is very poor. There's nothing about blade function like #parent for instance.
The example in the documentation from Laravel website does indeed seem to be flawed, but I think it's a markdown parsing problem on the website, the same docs on github show the correct code:
In any case #parent does indeed work. The example in the docs should look like this:
#extends('layouts.master')
#section('sidebar')
#parent
<p>This is appended to the master sidebar.</p>
#stop
#section('content')
<p>This is my body content.</p>
#stop
A quick look in the Illuminate/View/Factory.php confirms what #parent does:
/**
* Append content to a given section.
*
* #param string $section
* #param string $content
* #return void
*/
protected function extendSection($section, $content)
{
if (isset($this->sections[$section]))
{
$content = str_replace('#parent', $content, $this->sections[$section]);
}
$this->sections[$section] = $content;
}
You can simply use #append...
#extends('layouts.master')
#section('sidebar')
<p>This is appended to the master sidebar.</p>
#append
#section('content')
<p>This is my body content.</p>
#stop
See here.
To understand how this works...
The compileStatements() method in the BladeCompiler calls the method compileAppend(), as you can see here:
/**
* Compile Blade Statements that start with "#"
*
* #param string $value
* #return mixed
*/
protected function compileStatements($value)
{
$callback = function($match)
{
if (method_exists($this, $method = 'compile'.ucfirst($match[1])))
{
$match[0] = $this->$method(array_get($match, 3));
}
return isset($match[3]) ? $match[0] : $match[0].$match[2];
};
return preg_replace_callback('/\B#(\w+)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', $callback, $value);
}
In turn, that inserts a call to appendSection() which looks like this:
/**
* Stop injecting content into a section and append it.
*
* #return string
*/
public function appendSection()
{
$last = array_pop($this->sectionStack);
if (isset($this->sections[$last]))
{
$this->sections[$last] .= ob_get_clean();
}
else
{
$this->sections[$last] = ob_get_clean();
}
return $last;
}
as mentioned before, I used #parent and it works fine for me. May be an example for extended title will helps:
master.blade.php
#section('title')
My Blog
#stop
<!doctype html>
<html>
<head>
#include('includes.head')
</head>
<body>
<div class="container-fluid">
<div id="main" class="row">
#yield('content')
</div>
</div>
</body>
</html>
includes/head.blade.php
<meta charset="utf-8">
<title>#yield('title')</title>
post.blade.php
#extends('master')
#section('title')
#parent
| {{$post->title }}
#stop
#section('content')
// Post Body here ..
#stop
Therefore, The Title will be rendered to be like this:
My Blog | My Post Title
Actually, this will render something like:
<title>
My Blog
| My Post Title
</title>
so you can use the section second parameter to set the values:
includes/head.blade.php
...
#section('title', 'My Blog')
...
post.blade.php
...
#section('title', '#parent | ' . $post->ar_name )
...
And this will render:
<title>My Blog | My Post Title</title>
So you will get rid of the lines inside the title,
Hope that's helps.
Note:
This is used for Laravel 5.2, Not quite sure but as I remember, it works for Laravel 4 too.
Related
I want to show same content for different URL. For example:
website.com/controllername/country/state1/dist1/
website.com/controllername/country/state2/dist2/
I want these two URL to show same content.Even though the some content will vary based on URL (like name of state and district). I don't want to create separate content/page for every URL. I want to know if its possible to do so in Codeigniter? and is it possible to show a URL like the above in Codeigniter?
Yes it is possible with Codeigniter routing,
In your application/config/routes.php paste the below code and change the controller and function name you used,
$route['([a-zA-Z0-9---_%])+/([a-zA-Z0-9---_%])+/([a-zA-Z0-9---_%])'] = 'your_controller_name/your_function_name/$1/$1/$1';
Unlike other frameworks CodeIgniter does not have a global template system. Each Controller controls it's own output independent of the system and views are FIFO unless otherwise specified.
For instance if we have a global header:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" >
<html>
<head>
<title><?=$title?></title>
<!-- Javascript -->
<?=$javascript ?>
<!-- Stylesheets -->
<?=$css ?>
</head>
<body>
<div id="header">
<!-- Logos, menus, etc... -->
</div>
<div id="content">
and a global footer:
</div>
<div id="footer">
<!-- Copyright, sitemap, links, etc... -->
</div>
</body>
</html>
then our controller would have to look like
class Welcome extends Controller {
function index() {
$data['title'] = 'My title';
// Javascript, CSS, etc...
$this->load->view('header', $data);
$data = array();
// Content view data
$this->load->view('my_content_view', $data);
$data = array();
// Copyright, sitemap, links, etc...
$this->load->view('footer', $data);
}
}
Yes you can set same page with different url setting on routing.
Refer below link for more info:
https://www.codeigniter.com/userguide3/general/routing.html
$route['controllername/country/state1/dist1/'] = 'catalog/product_lookup';
$route['controllername/country/state1/dist2/'] = 'catalog/product_lookup';
Improving the krishnaraj answer...
you need
website.com/controllername/method1/st/dist/
website.com/controllername/method2/st/dist/
//i´ve changed some variables for better understanding, and the "country" would
//be the main change
so at your controller you just
public function method1($st1,$st2){
$this->load->view('header');
$this->load->model('data_processing');
$data['data'] = $this->data_processing->any_model_function($st1,$st2);
$this->load->view('page_you_want',$data);
//here you choose the same view for both methods
$this->load->view('footer');
}
public function method2($st1,$st2){
$this->load->view('header');
$this->load->model('data_processing');
$data['data'] = $this->data_processing->any_model_function($st1,$st2);
$this->load->view('page_you_want',$data);
//here you choose the same view
$this->load->view('footer');
}
In the case of route configuration explained by Kavin Smk, noticed just a mistake, instead of
'your_controller_name/your_function_name/$1/$1/$1';
it shoud be
'your_controller_name/your_function_name/$1/$2/$3';
Well, there is always a lot of ways to do the same, choose yours...
Good luck!
Is it possible to check into a blade view if #yield have content or not?
I am trying to assign the page titles in the views:
#section("title", "hi world")
So I would like to check in the main layout view... something like:
<title> Sitename.com {{ #yield('title') ? ' - '.#yield('title') : '' }} </title>
For those looking on it now (2018+), you can use :
#hasSection('name')
#yield('name')
#endif
See : https://laravel.com/docs/5.6/blade#control-structures
In Laravel 5 we now have a hasSection method we can call on a View facade.
You can use View::hasSection to check if #yeild is empty or not:
<title>
#if(View::hasSection('title'))
#yield('title')
#else
Static Website Title Here
#endif
</title>
This conditional is checking if a section with the name of title was set in our view.
Tip: I see a lot of new artisans set up their title sections like this:
#section('title')
Your Title Here
#stop
but you can simplify this by just passing in a default value as the second argument:
#section('title', 'Your Title Here')
The hasSectionmethod was added April 15, 2015.
There is probably a prettier way to do this. But this does the trick.
#if (trim($__env->yieldContent('title')))
<h1>#yield('title')</h1>
#endif
Given from the docs:
#yield('section', 'Default Content');
Type in your main layout e.g. "app.blade.php", "main.blade.php", or "master.blade.php"
<title>{{ config('app.name') }} - #yield('title', 'Otherwise, DEFAULT here')</title>
And in the specific view page (blade file) type as follows:
#section('title')
My custom title for a specific page
#endsection
#hasSection('content')
#yield('content')
#else
\\Something else
#endif
see "Section Directives" in If Statements - Laravel docs
You can simply check if the section exists:
if (isset($__env->getSections()['title'])) {
#yield('title');
}
And you can even go a step further and pack this little piece of code into a Blade extension: http://laravel.com/docs/templates#extending-blade
Complete simple answer
<title> Sitename.com #hasSection('title') - #yield('title') #endif </title>
I have a similar problem with the solution:
#section('bar', '')
#hasSection('bar')
<div>#yield('bar')</div>
#endif
//Output
<div></div>
The result will be the empty <div></div>
Now, my suggestion, to fix this, is
#if (View::hasSection('bar') && !empty(View::yieldContent('bar')))
<div>#yield('bar')</div>
#endif
New in Laravel 7.x -- sectionMissing():
#hasSection('name')
#yield('name')
#else
#yield('alternative')
#endif
Check if section is missing:
#sectionMissing('name')
#yield('alternative')
#endif
#if (View::hasSection('my_section'))
<!--Do something-->
#endif
Use View::hasSection to check if a section is defined and View::getSection to get the section contents without using the #yield Blade directive.
<title>{{ View::hasSection('title') ? View::getSection('title') . ' - App Name' : 'App Name' }}</title>
I don't think you can, but you have options, like using a view composer to always provide a $title to your views:
View::composer('*', function($view)
{
$title = Config::get('app.title');
$view->with('title', $title ? " - $title" : '');
});
why not pass the title as a variable View::make('home')->with('title', 'Your Title') this will make your title available in $title
Can you not do:
layout.blade.php
<title> Sitename.com #section("title") Default #show </title>
And in subtemplate.blade.php:
#extends("layout")
#section("title") My new title #stop
The way to check is to not use the shortcut '#' but to use the long form: Section.
<?php
$title = Section::yield('title');
if(empty($title))
{
$title = 'EMPTY';
}
echo '<h1>' . $title . '</h1>';
?>
Building on Collin Jame's answer, if it is not obvious, I would recommend something like this:
<title>
{{ Config::get('site.title') }}
#if (trim($__env->yieldContent('title')))
- #yield('title')
#endif
</title>
Sometimes you have an enclosing code, which you only want to have included in that section is not empty. For this problem I just found this solution:
#if (filled(View::yieldContent('sub-title')))
<h2>#yield('sub-title')</h2>
#endif
The title H2 gets only displayed it the section really contains any value. Otherwise it won't be printed...
How can I remove just the footer from a specific view in ZF2. I have tried
$View->setTerminal(true);
return $view;
but it makes the links in the top nav bar inactive. Thanks
You could change your base layout for that particular action.
for example, your main layout may be like this example:
layout.phtml
<?php echo $this->doctype(); ?>
<html lang="en">
<head>
<?php echo $this->headTitle($this->translate('TITLE'))->setSeparator(' - ')->setAutoEscape(false) ?>
</head>
<body>
....
<?php echo $this->partial('footer') ?>
</body>
</html>
You can simple make a duplicate layout, but without the footer partial included (or how ever you are including the footer partial/view etc)
you would then tell your action to use a different base layout:
Controller.php
public function testAction()
{
/**
* Now we use the base with no footer
*/
$this->layout('layout/no-footer-layout');
// identical to below, a shortcut
//$this->layout()->setTemplate('layout/no-footer-layout');
return new ViewModel(array(/** etc **/));
}
I have a template handlebar with php comment. I don't want the html result to include these comment php, and I can't use handlebar comment like {{! }}.
$template:
<?php
/**
* Template to show the Section on the front end.
*
* #uses array $options A collection
* #uses string $options['section_additional_classes'] A list of additional
*
* #uses array $dropzones A collection of widget dropzones.
* #uses string $dropzones['A'] A first dropzone.
*
* #package admin-panel
*/
?>
<script data-widget-template="frontend-section" type="text/x-handlebars-template">
<div class="row-fluid {{ options.section_additional_classes }}">
<div class="span12">
{{& dropzones.A }}
</div>
</div>
</script>
My code render with handlebar is (for example):
$hdlbars = new Handlebars_Engine();
$array_content_to_replace = array( 'dropzones' => array('A' => '<strong> Hello World!!</strong>'), 'options' => ('section_additional_classes') => 'class-example');
echo $hdlbars->render($template, array_content_to_replace );
the example before return html with php comment.
Why you can't use Handlebars template comments like {{! }}?
That indeed will solve your issue, just replace the <?php ?> tags from the comments and that code will stripped from the final template.
I have an application without controllers and read about controller layouts in laravel 4 documentation and this other article too, but I don't know where to start for implement it within routes (version 4), how can I do that?
Error received: InvalidArgumentException, View [master] not found.
app/routes.php
<?php
View::name('layouts.master', 'layout');
$layout = View::of('layout');
Route::get('users/create', array('as' => 'users.create', function() use($layout) {
//#TODO: load view using 'layouts.master',
// desirable: append 'users.create' and 'users.menu' views to sidebar and content sections.
//return View::make('users.create');
return $layout->nest('content', 'master');
}));
?>
app/views/layouts/master.blade.php
<html>
<body>
#section('sidebar')
This is the master sidebar.
#show
<div class="container">
#yield('content')
</div>
</body>
</html>
app/views/users/create.blade.php
{{ Form::open() }}
{{ Form::text('name') }}
{{ Form::submit('submit') }}
{{ Form::close() }}
app/views/users/menu.blade.php
<!-- This is appended to the master sidebar -->
<p>Create user</p>
Update: I modified example code to clarify what I want to do. Check app/routes.php and its comments
The code in your routes file is trying to nest the master layout within itself, which isn't really what you want. You're getting the error because 'master' would look for app/views/master.blade.php. That's easily fixed by changing it to 'layouts.master', but I wouldn't like to think what might happen...
The root cause of the issue you're having is the difference between "yielding" views from a Blade template, and nesting them from a route. When you nest a route, you need to echo it rather than using the #yield tag.
// File: app/routes.php
View::name('layouts.master', 'layout');
$layout = View::of('layout');
Route::get('users/create', array('as' => 'users.create', function() use ($layout)
{
return $layout
->nest('content', 'users.create')
->nest('sidebar', 'users.menu');
}));
/*
|--------------------------------------------------------------------------
| View Composer
|--------------------------------------------------------------------------
|
| Code in this method will be applied to all views that use the master
| layout. We use that to our advantage by injecting an "empty" sidebar
| when none is set when returning the view. It will error otherwise.
|
*/
View::composer('layouts.master', function($view)
{
if (!array_key_exists('sidebar', $view->getData()))
{
$view->with('sidebar', '');
}
});
// File: app/views/layouts/master.blade.php
<html>
<body>
#section('sidebar')
This is the master sidebar
{{ $sidebar }}
#show
<div class="container">
{{ $content }}
</div>
</body>
</html>
Laravel's View composers are a powerful tool. If you have any data (eg logged-in user info) used by all views that share the same template(s), you can use the composers to save injecting the data every time you load the view.
You could also use the #parent tag to append content, assuming you;re using blade for templating. E.g. (in the view)
#section('sidebar')
#parent
<p>This is appended to the master sidebar.</p>
#stop
You don't need to use nesting views if you're using blade.
app/views/users/create.blade.php
You need to extend the master.blade
#extends('layouts.master')
#section('content')
// form stuff here
#stop
Now, all you need to do is call create.blade
return View::make('users.create')
Just throwing this out there as a possible solution using controller routing (whereas you can set the template from within the controller).
app/routes.php
Route::controller('something', 'SomethingController');
app/controllers/SomethingController.php
class SomethingController extends BaseController {
protected $layout = "templates.main"; // denotes views/templates/main.blade.php
public function getIndex() { // the "landing" page for "/something" or "/something/index"
$this->layout->content = View::make('something.index')->with("myVar", "Hello, world!"); // load in views/something/index.blade.php INTO main.blade.php
}
public function getTest() { // for "/something/test"
$this->layout->content = View::make('something.index')->nest("widget", "something.widget", array("myVar" => "Hello, World!"));
}
}
app/views/templates/main.blade.php
#include('templates.partials.header')
#yield('something')
#yield('content')
#include('templates.partials.footer')
app/views/something/widget.blade.php
I'm a widget. {{ $myVar }}
app/views/something/index.blade.php
#section('something')
I will go in the 'something' yield in main.blade.php
#stop
#section('content')
I will go in the 'content' yield in main.blade.php.
{{ $myVar }}
{{ $widget }}
#stop
?>
Now you can test http://myserver/something and http://myserver/something/test to see the differences. Note: not tested but as a rough example.