As an admin I can create pages (don't think I have to paste my adminpagescontroller here, because you understand the logic). What I'm getting stuck on, is selecting, but especially using the layout that will be used for the page.
i.e. I have three layouts:
page with left sidebar
page with right sidebar
page with full-width (no sidebars)
And i.e. I want to create a salespage or so, which uses the layouts "page with full-width". How can I call this in my view?
Now all my views begin with #extends('layouts.path.file') <--- I need that to be filled in by the database, if you know what I mean.
One way of doing it is to use a view composer to define the current layout to be used. View composers set variables that can be used by all your views ('*') or just some ('users.profile', 'admin.profile'), so this is an example of using a user specific layout:
View::composer('*', function($view)
{
$view->with('userLayout', Auth::check() ? Auth::user()->layout : 'main');
});
And in your view you just have to:
#extends('layouts.'.$userLayout);
If you just need to select a page on your controller, you can pass a layout to it:
return View::make('myview')->with('layout', 'front.main');
And use it in your view:
#extends('layouts.'.$layout);
And if you have it on a table, you can just pass it on:
$layout = Pages::first()->layout;
return View::make('myview')->with('layout', $layout);
Or do the same in your composer
View::composer('*', function($view)
{
$layout = Pages::first()->layout;
$view->with('layout', $layout);
});
A lot of people like to set the layout in controller too, so you could in your controller do:
public function showProfile()
{
$this->layout = Pages::first()->layout;
$this->layout->content = View::make('user.profile');
}
And your views doesn't have to #extend a layout anymore, because you are already telling them which layout to use.
Related
I have a layout that is used when you are logged in. menu.blade.php.
Then I use it in blade files #extends('admin.layouts.menu')
I want to show some information in the layout, let's say the number of messages near the "message" link in the menu. I could easily do this by adding:
$message_count = Message::where("user_id", Auth::user()->id)->count();
and adding: <div>{{$message_count}}</div> to menu.blade.php
to every single controller and view where the layout is used, but this is clearly not a clean way to do it.
Is there a way to pass information to the view in a single step instead of having to do it in every single controller?
Use view composers.
View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location
Register the view composer within a service provider:
public function boot()
{
View::composer('menu', function ($view) {
$view->with('messagesCount', auth()->user()->messages->count())
});
}
Then each time when the menu view will be rendered, it will have $messagesCount variable with counted messages for an authenticated user.
I am working on Laravel for the first time
i have to make a Front End Menu Dynamic in Header and Footer [ list of categories will come from database ]. which controller I have to use for this.?
any common controller available in this framework to send data to header and footer.
When I receive the data in HomeController index Action its available for the home page only.
class HomeController {
public function index()
{
$categories = Category::get();
return view('home', compact('categories'));
}
}
Thanks.
This is a perfect case for View Composers:
View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location.
You may attach a view composer to multiple views at once by passing an array of views as the first argument to the composer method:
View::composer(['partials.header', 'partials.footer'], function ($view) {
$view->with('categories', [1, 2, 3]); // bind data to view
});
Now you could simply retrieve $categories within your view (blade template).
Tip: Common practice is to create a new service provider called ComposerServiceProvider and place the abovementioned composer logic in the boot() method.
I assume you are using the Header and Footer in a master layout file. In this case you need to send all header/footer info every request. Which would be silly so instead use View Composers:
Define them in your appServiceProvider in the boot() method
view()->composer('home', function($view) {
$view->with('categories', App\Category::all());
});
In my example i made 'home' the name of the view, since it is in your example. But i would make a master file called layout and include a header and footer partial. If you want categories inside your header you could make a view()->composer('layout.header') with only header data.
which controller I have to use for this.?
Any
any common controller available in this framework to send data to header and footer
No.
You control what is returned from the Controller to be the response. You can design layouts and break them up into sections and have views that extend them. If you setup a layout that has the header and footer and your views extend from it, you can use a View Composer to pass data to that layout when it is rendered so you don't have to do this every time you need to return a view yourself.
Laravel Docs 5.5 - Front End - Blade
Laravel Docs 5.5 - Views - View Composers
In case of this u can use components
https://laravel.com/docs/8.x/blade#components
php artisan make:component Header
View/Component.Header.php
public function render()
{
$category = [Waht you want];
return view('views.header', ['category'=>$category]);
}
Then include Header.php to your blade like this
views/front.blade.php
<html>
<body>
<x-header/> <!-- like this -->
#yield('content')
#include('footer')
<body>
I have a laravel page which can be extended from admin layout or user layout.
If the user logged as admin it should extend from admin, otherwise it should extend from user.
Can I make this control with a simple if inside of my view like:
//in my view
#if(Auth::check())
#extends('layouts.admin')
#else
#extends('layouts.outside')
If I do this control in my controller I need to make two view for user and admin and I dont want to duplicate my views like:
//in my controller
if(Auth::check())
return View::make('bot/bwin_admin');
else
return View::make('bot/bwin_user');//the view is duplicated :(
So how can I use different parent layout for a view without duplicating that view in laravel?
You can control the layout in your controller.
First add the default layout to your controller:
public $layout = 'layouts.outside';
Then do this in your action:
if(Auth::check()){
$this->layout = View::make('layouts.admin');
}
$this->layout->content = View::make('bot/bwin');
Also, you can then remove the #extends() from your view. It is not needed anymore since the controller defines the layout.
i am using laravel's blade template and i have a master template for all my pages. In the master template i have a top bar and a sidebar. I want to load something in the sidebar. But i don't know how do it in a simpler way. Now i am calling that method (which i want in to display in my sidebar) in every controller i have like this:
View::make()->with('data_to_load_in_sidebar',$data_to_load_in_sidebar)
How can i load this only once, not every time i generate a view?
This is what view composers are for, any view that is loaded will automatically have it's composer run alongside providing the view with any extra data it may require.
View::composer(array('partials.sidebar'), function($view)
{
$news = News::all();
$view->with('news', $news);
});
I typically put this in my routes.php file in both L3 and L4.
In the view views\partials\sidebar.blade.php you now always have access to the variable $news that will contain all models from the News collection.
I would share top bar & sidebar data in constructor (prefferably in some BaseController's contructor, that other controllers extends).
public function __construct()
{
// if needed, call parent's contructor method as well
parent::__construct()
$data_to_load_in_sidebar = loadDataForSidebar();
View::share('data_to_load_in_sidebar',$data_to_load_in_sidebar)
}
I'm starting a large codeigniter project and would like to try to create some reusable 'mini' views for snippets of content like loops of data which may be displayed on different pages/controllers.
Is it better to call the views from within the main controller's view? If so, how? Or should I call the 'mini view' from the controller and thus pass the view's code to the main view?
Views within other views are called Nested views.
There are two ways of including nested views in CodeIgniter:
1. Load a nested view inside the controller
Load the view in advance and pass to the other view. First put this in the controller:
<?php
// the "TRUE" argument tells it to return the content, rather than display it immediately
$data['menu'] = $this->load->view('menu', NULL, TRUE);
$this->load->view ('home', $data);
?>
Then put <?=$menu?> in your view at the point you want the menu to appear.
2. Load a view "from within" a view
First put this in the controller:
<?php
$this->load->view('home');
?>
Then put this in the /application/views/home.php view:
<?php $this->view('menu'); ?>
<p>Other home content...</p>
About best method, I prefer the 1st method over 2nd one, because by using 1st method I don't have to mix up code, it is not like include php. Although indirectly both are same, the 1st method is clearer & cleaner than 2nd one!
Honestly I prefer to do this by having template views then loading that with the necessary data from the controller, it means a lot less repeated code and follows the DRY concept better than loading views from views. Especially for things like headers, footers and menus.
So my template view would look something like this:
template.php
$this->load->view('header',$title);
$this->load->view('sidebar',$sidebar_content);
$this->load->view('main_content',$main_content);
$this->load->view('footer');
Then in my controller I pass the data required to the template like this:
$data['title'] = 'Home Page';
$data['sidebar_content']='pages/standard_sidebar';
$data['main_content'] ='pages/my_home_page';
$this->load->view('template',$data);
There are a number of benefits to doing it this way. First is I can have multiple templates, for example I have, in my case, two main ones, one for full page views without a sidebar and one for pages with a sidebar, I also call an if statement to decide which header to include, the regular one or the one with the admin menu in it.
Yes I could include the header, sidebar and footer in every main view page, but that ends up in a ton of duplicate code. And what happens if for example I want all my pages to have something new, some other small snippet? Using templates I add the snippet to the appropriate template and it's done. Going the other route I find every page and add the snippet view there, it's the equivalent to having CSS in the page in my opinion, wasteful and not ultimately maintainable.
METHOD 1
I use this method into my view to insert the include view where I want
$this->load->view('include/include_view');
METHOD 2
or in the controller you can load more than a view like this:
$this->load->view('header_view');
$this->load->view('list_view');
$this->load->view('footer_view');
No one method is better than the other, it depends if you have to pass some data (in this case use method2) or if you want to include a view in a specific part of your main view (in this case is better to use method1)
METHOD 3
Passing data to your include view by your main view
into your controller:
$data['title'] = "Title";
$this->load->view('main_view',$data);
in your view
$data2['title'] = $title;
$this->load->view('include/include_view',$data2);
If you want to pass entire data to your include view you can do in this way:
in your controller:
$data['nestedView']['title'] = 'title';
in your view
$this->load->view('includes/included_view', $nestedView);
This a simple way of including views within views.there is no need to load views in advance.just pass view path to other view.
In your controller use this:
$data['middle'] = 'includeFolder/include_template_view'; //the view you want to include
$this->load->view('main_template_view',$data); //load your main view
and in main_template_view you can include other views :
$this->load->view($middle);
In my opinion for solve in more efficient way this problem I have done so:
You create a new helper (in application/helpers) with name (es. common_helpers.php, the underscore is important). In this file, you put all the functions for example build pieces of html in common.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
function getHead(){
require_once(APPPATH."views/common/head.php");
}
function getScripts(){
require_once(APPPATH."views/common/scripts.php");
}
function getFooter(){
require_once(APPPATH."views/common/footer.php");
}
In your controller you call only one view in respect of MVC and call the functions from your custom helper.
class Hello extends CI_Controller {
public function index(){
$this->load->helper('common');
$this->load->view('index');
}
}
In the controller
controller
<?php
public function view($page = NULL)
{
if ( ! file_exists(APPPATH.'views/pages/'.$page.'.php'))
{
$data['title'] = ucfirst($page); // Capitalize the first letter
// Whoops, we don't have a page for that
show_404();
}
$data= array('');
$data['title'] = ucfirst($page); // Capitalize the first letter
$data['page_layout']='pages/'.$page;
$this->load->view('page_layout', $data);
}
?>
In the Views folder create a page called page_layout.php
page_layout.php
//This is where you set the layout to call any view through a variable called $page_layout declared in the controller//
<?php
$this->load->view('header');
$this->view($page_layout);
$this->load->view('footer');
?>