How to extend a layout without overwriting the scripts in the layout section (Laravel 5.8) - laravel

Ths should be simple enough, but...
I have a layout view dashboard-layout.blade.php with:
#section('headscripts')
<script src="{{ mix('/js/app.js') }}" defer></script>
#show
And a billing.blade.php view that extends the layout file:
#extends('layouts.dashboard-layout')
#section('headscripts')
#parent
<script src="https://js.braintreegateway.com/web/dropin/1.17.2/js/dropin.min.js"></script>
#endsection
The problem is, this only outputs the first script...what am I doing wrong?

You can simply use #stack('name here') instead of #yield('name here')
and use
#push('name here')
// Add Your Script Here
#endpush
instead of
#section('name here')
// Scripts
#endsection
to solve your problem.

Related

How to use Alpine.data() in #push within Laravel Blade components?

With Alpine.js 2 it was possible to develop Blade components with the following structure:
...
<div x-data="myApp()">
...
#once
#push('child-scripts')
<script>
function myApp() {
return {
...
}
}
</script>
#endpush
#endonce
This was great in that it allowed all the code for the component to be defined together.
In Alpine.js 3 this approach of defining functions is deprecated (https://alpinejs.dev/upgrade-guide#alpine-data-instead-of-global-functions). Instead, they should be defined like this:
...
<div x-data="myApp">
...
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('myApp', () => ({
...
}))
})
</script>
However, it states "you need to define Alpine.data() extensions BEFORE you call Alpine.start()". This suggests that with the new approach it is impossible (or at best unreliable) to use #push to add data functions for use in Blade components and, therefore, impossible to keep all the code for a Blade component together.
My code all works fine with Alipne 3, if I use the deprecated approach. If I try to include the new syntax data function via #push, I get "myApp is not defined" JS error from my Blade component.
I am using Alpine.js 3.9 installed as an NPM module. I have also tried using Alpine.js 3 via <script src="https://unpkg.com/alpinejs#3.x.x/dist/cdn.min.js" defer></script>. The result is the same in both cases.
Is there a way to keep all the code together in the Blade component?
UPDATE 25.02.2022
It seems I need to provide more details of what I am doing so here they are.
The relevant bits of my app.blade.php are:
<head>
...
<script src="{{ asset('js/app.js') }}" defer></script>
#livewireStyles
...
</head>
<body>
// HTML/Blade stuff here
#livewireScripts
#stack('child-scripts')
</body>
My app.js is like:
import Alpine from 'alpinejs'
require('./bootstrap');
window.Alpine = Alpine
Alpine.start();
I have also tried:
require('./bootstrap');
import Alpine from 'alpinejs'
window.Alpine = Alpine
Alpine.start();
My Blade component is like this:
...
<div x-data="myApp">
...
#once
#push('child-scripts')
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('myApp', () => ({
...
}))
})
</script>
#endpush
#endonce
When I access a page that uses the Blade component, I get "Uncaught ReferenceError: myApp is not defined".
If I revert my Blade component to the old syntax (as follows) it works with no errors:
...
<div x-data="myApp()">
...
#once
#push('child-scripts')
<script>
function myApp() {
return {
...
}
}
</script>
#endpush
#endonce
The only difference between the working and failing versions is the way in which myApp is defined. The deprecated method works but, with the new method, it doesn't.
Not sure why you would think that using #push is unreliable.
Since the #push directive (like any other blade directive) is evaluated by the blade engine on the server-side, by the time the page loads, anything you push is already there on the page.
One thing to note is that it is important to defer the execution of the javascript assets so that it is executed after the document has been parsed. You can do that by adding a defer attribute like so:
<!DOCTYPE html>
<html>
<head>
...
<script src="{{ mix('js/app.js') }}" defer></script> {{-- or CDN here --}}
</head>
<body>
...
#stack('scripts')
</body>
</html>
// resources/js/app.js
import Alpine from 'alpinejs'
window.Alpine = Alpine
Alpine.start()
I'm already using Alpine v3 this way without any issues.

Prevent script loading for specific route [Laravel]

In my head section of my form.layout.blade.php I have the following:
<head>
<script src="/js/main.js"></script>
<head>
This is layout file is loaded before all pages are loaded. Is there a way to not load main.js for a specific route?
you can use if statement like this. main.js will not load on this page
#if(!Request::is('subpage/url'))
<script src="/js/main.js"></script>
#endif
The workaround I used for not loading scripts on all sites, is that I put script paths in variables in controllers, something like this:
public function show($id){
$scripts[] = '/js/main.js';
view()->share('scripts', $scripts);
return view('view', $someData);
}
This allows me to use this script only on a page I really need it, like this:
#if(isset($scripts))
#foreach($scripts as $key => $value)
<script src="{{mix($value)}}"></script>
#endforeach
#endif
Hope that this can lead you in right direction.
You can use if statements
#if(!in_array(Route::currentRouteName(), ['route.name', ...]))
<script src="/js/main.js"></script>
#endif

How To Add Title For Each Page In Laravel

In my laravel website all pages having same title meta but how to make different title for each page please tell me.
this is my code for dynamic showing in all the pages
<title>{{setting('site.title')}} | {{setting('site.description')}} #if(isset($data->title)) {{$data->title}} #endif</title>
file name is layouts/app.blade.php
Inside your app.blade.php, in the head section.
change:
<title>{{ config('app.name', 'Laravel') }}</title>
to:
<title>#yield('title')</title>
You can choose any name/title that seems fitting.
For other views.blade.php pages,(extending app.blade.php) you can add a title this way:
#section('title','My Title')
this comes after #extends('layouts.app')
You can specify different title for different views.
In you common header file make your title like this:
<title>#yield('page_title', 'Default Title')</title>
Then in your view file change the title to whatever you want it to be set in following way:
#section('page_title')
{{ "Your Title" }}
#endsection
Simply inside your app.blade.php
Put this: #yield('title')
In other pages just extend the layout and put the new title at the this section
#extends('layoutWhateverYouNamedIt')
#section('title')
Type your title here
#endsection
in your controller
public function aboutUs()
{
//page title
$title = 'Project | About Us';
return view('project.about_us', compact('title'));
}
for your view page
<title>{{ $title }}</title>
Inside your app.blade.php,
<head>
#yield('title')
... // other scripts
</head>
For other pages which user app.blade.php you can use it like after extending app.blade.php :
#section('title')
<title> Your Page Title Here </title>
#endsection`
Hope it helps. happy coding.

Parameter in Route::get caused style to disappear?

I'm still new to Laravel. Anyway, I'm making a small system of viewing and creating articles to be shown in the main site. I wanted to create a page that displays an article from the database, using a parameter from the URL, like this:
http://localhost:8000/read/1
The above, for example, will display the article with 'id' value of 1 in the database.
So it works just fine, but problem is, after I got it to work (which took me some time since I'm a newbie), the whole style just disappears from the page. I tried to rewrite everything but it still didn't work. New pages that I create include the style just fine.
This is my route line:
Route::get('read/{id}', array('as' => 'read', 'uses' => 'NewsController#readArticle'));
NewsController readArticle function:
public function readArticle($id) {
$article = NewsMessage::where('id', $id) -> first();
return View::make('news.read', array('article' => $article));
}
And the file read.blade.php (located in views/news/read.blade.php)
#extends('layouts.main')
#section('content')
{{ $article -> title }}
#stop
So the whole PHP code works fine and I manage to get the title. But for some reason, the whole style disappears and this is what I see:
http://puu.sh/ctO6J/db30fbe102.png
So any idea, what have I dont wrong that caused this? The other pages work just fine with the style included.
Thank you!
The issue is that the path to the image is incorrectly specified.
You can either use the built in asset methods or something like {{ URL::to('/')/imagepathhere/filename.jpg }}
Assuming you have your styles links wrote as:
#extends('layouts.main')
#section('styles')
<link href="css/custom.css" rel="stylesheet" />
<link href="css/styles.css" rel="stylesheet" />
#endsection
#section('content')
{{ $article -> title }}
#endsection
Correct Syntax:
#extends('layouts.main')
#section('styles')
<link href="{{ asset('css/custom.css') }}" rel="stylesheet" />
<link href="{{ asset('css/styles.css') }}" rel="stylesheet" />
#endsection
#section('content')
{{ $article -> title }}
#endsection
And make sure your css folder is located at public folder when calling with asset() helper.
This issues of disappearing the whole page styles is causing by accessing the image or css file or any other resources, and the solution is to use asset() helper function.
NOTE: YOUR ROUTES AND CONTROLLER HAS NO ISSUE, YOU DON'T NEED TO TOUCH EITHER.

blade template, #yield at extended view

I would like to define a section at the layout or at an include, such as:
/views/master.blade.php
#section('mysection')
content here
#stop
#yield('content')
And be able to yield it at the view inheriting the layout:
/views/home.blade.php
#extends('master')
#section('content')
#yield('mysection')
#stop
From what I've tested this doesn't work. Is there another way of doing this?
Some sections are not supposed to always render and also not in the same place as they are on the layout, so the yield method would do what I need.
You can try to modify the master.blade.php as:
/views/master.blade.php
#section('mysection')
content here
#show
#yield('content')

Resources