Laravel: Pass variable to Blade Sub Component - php

There are many questions here that are similar to mine, such as:
Pass variable to a component Laravel 9
Cannot access Blade Component variables inside the view
Passing variable from component into a slot
but I have not found a resolution to my problem in any of them. I've also scoured the doc at: https://laravel.com/docs/9.x/blade#components
I would have thought this would be a simple task.
I have the following structure, in Resources/views:
start.blade.php (uses)
components/layout.blade.php (uses)
components/head.blade.php
From my controller, I call:
$data =
[
'total' => $total,
'uses_form' => true
];
return view('start', $data);
Inside start.blade.php, I have:
<x-layout>
<x-slot name="uses_form">
{{ $uses_form }}
</x-slot>
<!-- additional html -->
</x-layout>
Inside layout.blade.php:
<!DOCTYPE html>
<html lang="en">
<x-head :uses_form:$uses_form />
<!-- also tried: #include('includes.header', ['uses_form' => $uses_form])-->
<body>
<div class="container-fluid">
{{ $slot }}
</div><!--container-fluid-->
</body>
</html>
Finally, in head.blade.php:
<head>
<link type='text/css' rel='stylesheet' href='/css/vendor/bootstrap.min.css' />
#if ($uses_form === true)
<link type='text/css' rel='stylesheet' href='/css/form.css' />
#endif
</head>
This results in an:
Undefined variable $uses_form
at:
head.blade.php: line 3
How can I get the variable to be recognized in head.blade.php?
I'm open to other approaches, such as generated the conditional style include, at a higher level, but I rather keep this check in head.blade.php for maintainability.
Using Laravel version 9.48.0
Edit (Additional Notes)
If I var_dump $uses_form from the top of layout.blade.php, I get the following:
object(Illuminate\View\ComponentSlot)#301 (2) {
["attributes"]=> object(Illuminate\View\ComponentAttributeBag)#299 (1) {
["attributes":protected]=> array(0) { }
}
["contents":protected]=> string(1) "1"
}
So, it's already changed form.

You can try to pass the variable $uses_form from the parent component layout.blade.php to the child component head.blade.php using following changes and I hope it will helpful to you.
layout.blade.php look like:
<!DOCTYPE html>
<html lang="en">
<x-head :uses-form="$uses_form"/>
<body>
<div class="container-fluid">
{{ $slot }}
</div><!--container-fluid-->
</body>
</html>
head.blade.php look like:
<head>
<link type='text/css' rel='stylesheet' href='/css/vendor/bootstrap.min.css' />
#if ($usesForm === true)
<link type='text/css' rel='stylesheet' href='/css/form.css' />
#endif
</head>

I got it working. There were a few things needing adjusting, but, mainly, I needed to modify the component classes to accept the parameter data.
Another change that was needed, was to pass the data to the layout component, at the top of start.blade.php, like so:
<x-layout :hasForm="$hasForm">
Also, as indicated in another answer and in comments, I needed to place the variable in quotes.
Finally, I'm not sure if this was part of problem, but I changed the uses_form variable from snake_case to camelCase.
The changes, from the question are such:
Controller:
$data =
[
'total' => $total,
'hasForm' => true
];
return view('start', $data);
start.blade.php
<x-layout :hasForm="$hasForm">
<!-- additional html -->
</x-layout>
app/View/Components/Layout.php
class Layout extends Component
{
public $hasForm;
public function __construct($hasForm)
{
$this->hasForm = $hasForm;
}
}
layout.blade.php
<!DOCTYPE html>
<html lang="en">
<x-head :hasForm:"$hasForm" />
<body>
<div class="container-fluid">
{{ $slot }}
</div><!--container-fluid-->
</body>
</html>
app/Views/Components/Head.php
class Head extends Component
{
public $hasForm;
public function __construct($hasForm)
{
$this->hasForm = $hasForm;
}
}
head.blade.php
<head>
<link type='text/css' rel='stylesheet' href='/css/vendor/bootstrap.min.css' />
#if ($hasForm === true)
<link type='text/css' rel='stylesheet' href='/css/form.css' />
#endif
</head>
Hope this may help someone else, down the line.

Related

How comment script tag content in blade.php?

I try build a React Laravel webpage.
The main.blade.php responsible the layout and that pass data and React components to other blade
I test my app and make few blade.php
So I try comment out several way this line:
/* const data = {{ Illuminate\Support\Js::from($data)}};*/
but not work. It still perceives it as if it were there
I have to pass data for every route for testing because I can't comment the above line
Route::get('/react', function () {
$data = User::find(1);
return view('reactpractice', compact("data"));
})->name('react');
main.blade.php
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/css/app.css"/>
<title>#yield('title')</title>
<title>{{env('APP_NAME')}}</title>
</head>
<body>
<header>
Motto
</header>
<nav>
Index
About
React
Users
Login
Register
</nav>
#yield('contenttop')
#if(Session::has('successmessage'))
<div class="alert alert-success my-3">
{{Session::get('successmessage')}}
</div>
#endif
#yield('example')
<script>
const data = {{ Illuminate\Support\Js::from($data)}};
const token = '{{#csrf_token()}}'
</script>
<h2> React</h2>
<script src="js/app.js"></script>
</body>
</html>
So how comment script tag content in blade.php?
Rather than comment the line in JavaScript, why not make it conditional?
#if (isset($data))
const data = {{ Illuminate\Support\Js::from($data)}};
#endif
This way, if $data is provided, the JavaScript variable will be created. If $data is missing, it will be ignored and won't break your code.
<!-- Try like this -->
// or /* */
I hope it was helpfull.

My variable does not seem to be available in blade view

My Route...
Route::get('/test', function () {
$word = ['Hello'];
return view('test', $word);
});
My Blade View...
<!DOCTYPE html>
<html lang="en">
<head>
<title>Laravel Quickstart - Basic</title>
<link href="{{ asset('/css/app.css') }}" rel="stylesheet"/>
<link href="{{ asset('/css/Test.css') }}" rel="stylesheet"/>
<!-- CSS And JavaScript -->
</head>
<body>
<div class="container">
<nav class="navbar navbar-default">
{{$word}}
</nav>
</div>
</body>
</html>
I get the following erro when accessing the app via a browser...
(2/2) ErrorException Undefined variable: word (View:
/home/vagrant/Code/Laravel/resources/views/test.blade.php)
When I remove $word form the blade view and replace with a static string "test" it displays correctly.
no idea why the blade view can't see the $word varible, any ideas anyone?
You need to return it to the view in one of two ways:
return view('test', compact('word'));
Or
return view('test', ['word' => $word]);
Either of these methods will then enable you to use the $word variable from within the blade file
You can see an example of this within the documentation here: https://laravel.com/docs/5.4/blade#displaying-data
Change this line
return view('test', $word);
To
return view('test', compact('word'));
The variable will be available in your blade.
To complete Karl's answer, you can see an example there : https://laravel.com/docs/5.4/views#creating-views

Laravel: Accessing PHP from upper view

First Laravel Project.
I made a DB::select statement in the upper "master" layer, but when I want to access it from the lower layer I get "variable not defined message.
Master layer:
<!DOCTYPE HTML>
<html class="html">
<head>
<?php $options=DB::select('select * from options'); ?>
<title>#yield('title')</title>
<link href="{{ asset('/css/style.css') }}" rel="stylesheet">
<link href="media/favicon.ico" rel="icon" type="image/x-icon" />
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
</head>
.
.
.
Other layer:
#extends('layouts.master')
#section('title', 'Inventory')
#section('main')
#parent
<?php
$thumbnails=$options[0]->thumbnails;
?>
.
.
.
Output:
ErrorException in a9ef8ce5f32a327198559f3667e4271b90435dc6.php line 5:
Undefined variable: options (View:
/var/www/html/project/laravel/leltar/resources/views/inventory.blade.php)
What did I wrong?
It looks like you wanted to access $options variable on any given view. You can achieve that by sharing it across all views.
Add the following code to your App\Providers\AppServiceProvider boot() function
View::share('options', DB::select('select * from options'));
Don't forget to import
use Illuminate\Support\Facades\DB;
on the top.

Passing array from view(Blade) to another view(Blade) in laravel

I have master layout of laravel blade template main.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>#yield('title','My Site')</title>
</head>
<body>
#yield('container','Content area')
{{ HTML::script('assets/js/jquery-1.9.0.js') }}
</body>
</html>
I extended it for another view index.blade.php
#extend('main')
I want to add javascript links to master layout(main.blade.php) if exists in child layout(index.blade.php)
added code in index.blade.php
$extraJs = array('plugins1.js','plugins2.js');
#section('extraJs')
{{ $extraJs }}
#stop
So, How can I add javascript to master layout if exists in child blade?
In php:
<?php
if(isset($extraJs)):
foreach($extraJs as $js):
?>
<script src="assets/js/<?php echo $js ?>" type="text/javascript" />
<?php endforeach; endif; ?>
You can just add a yield in your main.blade.php, like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>#yield('title','My Site')</title>
</head>
<body>
#yield('container','Content area')
{{ HTML::script('assets/js/jquery-1.9.0.js') }}
#yield('javascripts')
</body>
</html>
Then, in your child layout, you add a section for it, like you did. For example:
#section('javascripts')
#foreach($scripts as $script)
{{ HTML::script('ets/js/' . $script) }}
#endforeach
#stop
If you add another child view which doesn't need to use extra javascripts, Laravel won't complain because the section is optional.
I wouldn't really encourage this method but since you asked. It is definitely possible to pass something "up" in the view tree. You can just define a PHP variable in your view and it will be available anywhere in the layout.
index.blade.php
<?php $extraJs = array('plugins1.js','plugins2.js'); ?>
main.blade.php
#if(isset($extraJs))
#foreach($extraJs as $js)
<script src="{{ asset('assets/js/'.$js) }}" type="text/javascript" />
#endforeach
#endif
As you can see I also converted your code in the layout to blade and made use of the asset() function to generate absolute URLs
Note Instead of doing it this way there are other methods. For example View composers or defining the plugins in the controller.

Appending into #section

I'm using Laravel 4 and I'd like to extend what's already placed in my master.blade.php template.
<!DOCTYPE html>
<html>
<head>
#section('head')
#parent
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{$title}}</title>
<meta name="description" content="{{$description}}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ asset('assets/css/main.css') }}">
#show
</head>
<body>
...
For example, my home.blade.php template:
#section('head');
appending to head....
#show
#section('content')
<h2>Hello World</h2>
#show
So I was trying to append "appending to head..." into the template. But it just replaces what's already there. With some research I came to an conclusion that it's not possible, but I'm not sure how else would I do this.. Partials? Includes?
What can I do?
Use this code in the home.blade.php template that extends the master.blade.php:
this could be your home.blade.php
#extends('master')
#section('head')
#parent
{{{ $head_data }}}
#stop
{{-- Content --}}
#section('content')
Here comes you content...
#stop
You can call it from your controller
<?php
class HomeController extends Controller {
public function getIndex()
{
$head_data = 'appending to head....';
return View::make('home', compact('head_data'));
}
}

Categories