How to pass data from #extends to #yield? - laravel

I have some common data getting from helper. Now I wanted to use that data in all over view. So, I am trying to declare that data in app.blade.php and trying to pass it's sections.
Here is my app.blade.php -
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>ABC| #yield('title')</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<link href="{{ asset('/assets/plugins/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ asset('/assets/abc/css/style.css') }}" rel="stylesheet">
<?php
//get theme
$theme = AppHelper::instance()->getTheme();
//get theme folder
$themeFolder = $theme[0]->websiteAdmin;
//set include files section path
$includePath = 'frontend.'.$theme[0]->themeName.'.sections.';
?>
</head>
#yield('content')
</html>
Here I want to pass variables $theme, $themefolder, $includePath to #yield('content').
I tried below code -
#yield('content', array('theme'=> $theme, 'themeFolder'=> $themeFolder, 'includePath'=> $includePath))
But getting error that those variables are undefined.
Undefined variable: theme
Can you please help me how to pass data from #extend to #yield?
Thank you in advance.

You should use View composers to accomplish this. They allow you to pass the same data across multiple views by only calling it in one place.
In your providers/AppServiceProvider.php you can add the following to your boot method:
use Illuminate\Support\Facades\View; //import view facade
public function boot()
{
View::composer(['view-name', 'another-view-name'], function($view){
$theme = AppHelper::instance()->getTheme();
$themeFolder = $theme[0]->websiteAdmin;
$includePath = 'frontend.'.$theme[0]->themeName.'.sections.';
$view->with(compact('themeFolder', 'includePath', 'theme'));
});
}
View::composers first argument takes an array of views, put all the views you want to pass the data to here ['view-name', 'another-view-name'], it can also take a single string.
The data will now be available to your specified views through $themeFolder $includePath and $theme variables
If you want this data to pass to ALL views, you can do '*' as the first argument.
NOTE, this will pass the data to EVERY view you create, only do '*' if you want every view to contain the data! Otherwise, specifiy the views individually.
If you want all the views within a certain folder to get passed the data you can do 'folder-name.*'.
Alternatively, the only other way to pass data to your #yield is to return the view app.blade.php with the variables in your controller.

Related

CSS loading slow and causing temporary weird formatting on Laravel app with Blade and Vue

I have a Laravel app that uses a tiny bit of Vue code in the blade templates. There's a problem navigating from view to view, almost every time there's a brief delay before the CSS is loaded where the raw text of the page shows without any formatting. It shows for about 1/2 a second and then the CSS kicks in and it looks correct. I can't find any reason for this, I tried changing the mix('css/app.css') etc so that it's not having to reload every time, but I can't figure out how to fix it.
I'm not sure if Vue is somehow delaying the css from loading? Any ideas what it could be? I'll paste the top section of the blade template below. I just upgraded to Laravel 8 but the same was happening with Laravel 7.
Thanks for your help!
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="title" content="Pono Admin">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Admin</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght#300;400;700&display=swap" rel="stylesheet">
<!-- Styles -->
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
<link href="{{ mix('css/admin.css') }}" rel="stylesheet">
#hasSection('style')
#yield('style')
#endif
<!-- Scripts -->
#hasSection('script')
#yield('script')
#else
<script>
var vmMixinsAdmin = '';
</script>
#endif
<script src="{{ mix('/js/app.js') }}" defer></script>
<script>
var vmMixinsApp = '';
let vroundedBtn = false;
let vunreadNotificationCount = {{ auth()->user()->unreadNotifications()->count() }};
</script>
</head>
<body>
<div id="vm">
<main id="app-main" class="container-fluid px-0">
etc
Someone had something similar and decided to show an overlay on foreground and hide it after the page has loaded. I'm not sure that it's the best solution but it could help:
Force browsers to load CSS before showing the page

Laravel - Vue component rendering twice because of app.js

I have a Laravel 7 project and installed bootstrap as well as the ui vue auth package. I'm trying to modify the home (home.blade.php) which extends app.blade.php but I've found that somehow the <div id="app"> in app.blade.php is rendering twice. I put a script tag with a console.log() at the bottom of app.blade.php just before the div tag closes and it outputs twice. However, when I put the script tag outside this div it behaves as it should and it only outputs once.
I found out that this is due to a script tag in the head of app.blade.php:
<script src="{{ asset('js/app.js') }}" defer></script>
When I commented that line, everything worked fine! So, my questions are:
Why is this script tag here? Why does it make everything run twice? Do I really need it? Will I encounter problems in the future by not having it?
webpack.mix.js:
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
resources/js/app.js:
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
const app = new Vue({
el: '#app',
});
app.blade.php:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<!-- Icons -->
<script src="https://kit.fontawesome.com/36a988e261.js" crossorigin="anonymous"></script>
</head>
<body>
<div id="app">
<script type="application/javascript">console.log('app')</script>
</div>
</body>
</html>
Edit: Since it's been a few hours and no answers I decided to set up a repo in case anyone wants to see first-hand what the problem is.
I faced same problem, in my case it was due to some iframes in the page targetting # src url. I realized it was written several times that message in the console :
[Vue devtools message in console][1]
So, I created a new special route
Route::get('/frame', [PagesController::class, 'frame'])->name('frame');
which return an empty string like
/**
* Used for iframes to override dowloadinf twice page content
*/
public function frame() {
return "";
}
And it solved my problem. Maybe it can be the same for all ressources fetched at "#"
.
[1]: https://i.stack.imgur.com/Z55BX.png
I found out this is because of having script tags outside of a Vue component. I deleted the script tag in app.blade.php and put the ExampleComponent that comes when installing vue with laravel which has a console.log inside the mounted() method and it only gets called once.
Still, I have no idea as to why this happens. If someone could shed light into this matter that would be awesome. Maybe I'll post another question with this new insight.

laravel does not load styles while passing value with urls

im using a laravel 5.4 and i have a problem with urls, when i send value with urls like http://localhost:8000/Music/{id} , laravel does not load styles but if use url without value to get that view it loads styles properly, it also does not load styles if an slash get added to end of url like http://localhost:8000/videos/ but without that slash http://localhost:8000/videos works without problem ..sorry i cant speak english good.
here is my code :
Route::get('Music/{id}','homeController#Music');
public function Music(music $item)
{
return view('music',['item'=>$item]);
}
this works by route model binding properly and does what i want but when it returns music blade file it does not load styles that i linked but if use this instead :
Route::get('Music','homeController#Music');
a
public function Music()
{
$item = music::find(1); //for example
return view('music',['item'=>$item]);
}
that works perfect.
i checked this many ways its because of {vlaues} in urls
it also does not loads styles or js files if an slash get added to end of urls
what is the problem?
Use the asset() function...
<html>
<head>
<link href="{{ asset('css/test.css') }}" rel="stylesheet">
</head>
<body>
<div class="square"></div>
<!-- Same for Javascript... -->
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
i tested it on this too
<html>
<head>
<link rel="stylesheet" href="css/test.css" type="text/css">
</head>
<body>
<div class="square"></div>
</body>
</html>

DHTMLXGantt and Laravel - Data doesn't display in extended templates

Background
Following this tutorial from Jan 2016, ( https://dhtmlx.com/blog/using-dhtmlxgantt-with-laravel/ ) I began experimenting with DHTMLXGantt (v4.1) and Laravel (v5.4) and ran into some troubles getting the sample data from a mysql/mariadb database to display in the gantt chart. The initial troubles had to do with the DHTMLX connector not staying current with some Laravel changes. For the sake of others who may read this and are struggling with the same issues, the two basic problems I already solved were:
(1) I was referred to this [updated] connector which was compatible with Laravel's recent versions ( https://github.com/mperednya/connector-php/tree/modern ). And,
(2) I specified a date range that matched the dates of the sample data (from 2013), such as...
gantt.config.start_date = new Date(2013, 04, 01);
gantt.config.end_date = new Date(2013, 04, 30);
At this point I was able to successfully use Laravel as a backend server for the DHTMLXGantt chart (including read-write with the sample data).
Problem
The problem I am having now is trying to move from the simplistic sample, to something slightly more complex. Specifically, when I employ Laravel's extended templating I get the gantt chart painted on screen, but no project/task data displays in the chart.
To explain this a little more specifically, a simple Laravel view with the whole page contained within it works as expected. For example, this blade file (gantt.blade.php) works.
<!DOCTYPE html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<script src="codebase/dhtmlxgantt.js"></script>
<link rel="stylesheet" href="codebase/dhtmlxgantt.css">
<link rel="stylesheet" href="codebase/skins/dhtmlxgantt_skyblue.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<div class="container">
<h1>Placeholder Header</h1>
<div id="gantt_here" style='width:100%; height:500px;'></div>
<script type="text/javascript">
gantt.config.xml_date = "%Y-%m-%d %H:%i:%s";
gantt.config.step = 1;
gantt.config.scale_unit= "week";
gantt.config.autosize = "xy";
gantt.config.fit_tasks = true;
gantt.config.columns = [
{name:"text", label:"Task name", width:"*", tree:true },
{name:"start_date", label:"Start time", align: "center" },
{name:"duration", label:"Duration", align: "center" },
{name:"add", label:"", width:44 }
];
gantt.init("gantt_here");
gantt.load("./gantt_data", "xml");
var dp = new gantt.dataProcessor("./gantt_data");
dp.init(gantt);
</script>
<h1>Placeholder Footer</h1>
</div>
</body>
But if I try using an extended app layout with the intention of building out a standard look & feel across all pages, the Gantt chart appears and is formated as I expect, but no data appears within the gantt chart. Here is top-level layout file (app.blade.php)
<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<link rel="stylesheet" href="codebase/dhtmlxgantt.css">
<link rel="stylesheet" href="codebase/skins/dhtmlxgantt_skyblue.css" type="text/css" media="screen" title="no title" charset="utf-8">
<!-- Scripts -->
<script>
window.Laravel = {!! json_encode([
'csrfToken' => csrf_token(),
]) !!};
</script>
<script src="codebase/dhtmlxgantt.js"></script>
</head>
<body>
<div id="app">
<!-- menus and other bootstrap styling removed for brevity -->
#yield('content')
</div>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
And here's the "content" view (index.blade.php)...
#extends('layouts.app')
#section('content')
<div id="gantt_here" style='width:100%; height:500px;'></div>
<script type="text/javascript">
gantt.config.xml_date = "%Y-%m-%d %H:%i:%s";
gantt.config.step = 1;
gantt.config.scale_unit= "week";
gantt.config.autosize = "xy";
gantt.config.fit_tasks = true;
gantt.config.columns = [
{name:"text", label:"Task name", width:"*", tree:true },
{name:"start_date", label:"Start time", align: "center" },
{name:"duration", label:"Duration", align: "center" },
{name:"add", label:"", width:44 }
];
gantt.init("gantt_here");
gantt.load("./gantt_data", "xml");
var dp = new gantt.dataProcessor("./gantt_data");
dp.init(gantt);
</script>
</div>
#endsection
Other things I've tried:
Using Chrome developer tools, I can see that the xml data was properly delivered to the browser in both examples. This made me think maybe it is a timing problem of some sort. So I put a couple links on the page just to test clearing the chart and reloading it. But still no change.
<a onclick="gantt.clearAll()" href="javascript:void(0);">Clear</a>
<a onclick="gantt.load('./gantt_data', 'xml')" href="javascript:void(0);">Refresh</a>
I also tried moving the div block "gantt_here" to various other places above and below Laravel's template directives. It fails in all cases, except when this div block is outside (either above or below) the "app" div tag in "app.blade.php" which, of course, defeats the purpose I am trying to achieve.
My goal is to use this chart within Laravel's extended templating capabilities. But I can't figure out what's wrong. Any ideas?
After further troubleshooting, I discovered the problem. It turns out that in app.blade.php, I was loading the app.js at the bottom of the body tag. When I moved this up to the HTML header area, the data began to display properly.

Blade Template with comment on top not working

file: app/route.php
Route::get('/', function()
{
return View::make('home');
});
file: app/views/home.blade.php
{{-- Blade comment. --}}
#extends('layouts.base')
#section('head')
<link rel="stylesheet" href="second.css" />
#stop
#section('body')
<h1>Heading</h1>
<p>Hello Home!</p>
#stop
file: app/views/layouts/base.blade.php
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
#section('head')
<link rel="stylesheet" href="style.css" />
#show
</head>
<body>
#yield('body')
</body>
</html>
When I access to laravel.localhost/
It only output
#extends('layouts.base')
but however, if I remove the
{{-- Blade comment. --}}
then it works perfectly.
May I know what is the issue?
The first line in your extended blade view must be the #extends directive.
Yes it is a convention by the devs.
Look at BladeCompiler.php on line 119.
protected function compileExtends($value)
{
// By convention, Blade views using template inheritance must begin with the
// #extends expression, otherwise they will not be compiled with template
// inheritance. So, if they do not start with that we will just return.
if (strpos($value, '#extends') !== 0)
{
return $value;
}

Resources