How to have one-time push in laravel blade
One solution is to extend Blade by creating a pushonce
directive as follows:
Blade::directive('pushonce', function ($expression) {
$isDisplayed = '$__pushonce_'.trim(substr($expression, 2, -2));
return "<?php if(!isset({$isDisplayed})): {$isDisplayed} = true; \$__env->startPush{$expression}; ?>";
});
Blade::directive('endpushonce', function ($expression) {
return '<?php $__env->stopPush(); endif; ?>';
});
It must be added to AppServiceProvider
boot
method.
Usage:
@pushonce('scripts')
<script src="{{ asset('js/foo.js') }}"></script>
<script>
...
</script>
@endpushonce
@pushonce('styles')
<script src="{{ asset('js/foo.js') }}"></script>
<script>
...
</script>
@endpushonce
Please test it and let me know if that's help.
This Works for me.
@once
@push('page_scripts')
<script type="text/javascript">
</script>
@endpush
@endonce
As of Laravel 7.25, Blade now includes a new @once component that will only render the items within the tags one time. https://laravel.com/docs/8.x/blade#the-once-directive
In the following answer I assumed you are familiar with Blade extension. This method has been tested on Laravel 5.2 and 5.3 (See note below).
After testing Ismail RBOUH's Answer (so please read it), It seems there are two problems with the solution:
1- The $isDisplayed variable is not in a same scope with the other included widgets so each @include push its scripts to stack. As a result I change it to:
Blade::directive('pushonce', function ($expression) {
$isDisplayed = '__pushonce_'.trim(substr($expression, 2, -2));
return "<?php if(!isset(\$__env->{$isDisplayed})): \$__env->{$isDisplayed} = true; \$__env->startPush{$expression}; ?>";
});
Blade::directive('endpushonce', function ($expression) {
return '<?php $__env->stopPush(); endif; ?>';
});
2- The solution limit the use of @pushonce to one widget. i.e. in the case of 2 or more widgets (widget1.blade.php, widget2.blade.php, ...) it prevent to push other widgets scripts. So, I add domain to @pushonce with the following code:
Blade::directive('pushonce', function ($expression) {
$domain = explode(':', trim(substr($expression, 2, -2)));
$push_name = $domain[0];
$push_sub = $domain[1];
$isDisplayed = '__pushonce_'.$push_name.'_'.$push_sub;
return "<?php if(!isset(\$__env->{$isDisplayed})): \$__env->{$isDisplayed} = true; \$__env->startPush('{$push_name}'); ?>";
});
Blade::directive('endpushonce', function ($expression) {
return '<?php $__env->stopPush(); endif; ?>';
});
Usage:
widget1.blade.php
@pushonce('scripts:widget1')
<script src="{{ asset('js/foo.js') }}"></script>
<script>
...
</script>
@endpushonce
widget2.blade.php
@pushonce('scripts:widget2')
<script src="{{ asset('js/bar.js') }}"></script>
<script>
...
</script>
@endpushonce
NOTE FOR L 5.3: change the following line:
$domain = explode(':', trim(substr($expression, 2, -2)));
to
$domain = explode(':', trim(substr($expression, 1, -1)));