Laravel Blade Composor/Creator override - laravel

I am intending to provide a default set of variables to various blade views with the ability to override them later. For example
a.blade.php
<p>a.blade</p>
<p>{{ $foo }}</p>
#include('b')
#include('b', ['bar' => 'bar as param'])
b.blade.php
<p>b blade</p>
<p>{{ $bar }}</p>
When I use View::creator, it allows me to use ->with() at runtime to recompose my views and override the ones bound in the creator. If I use View::composer, this is not the case.
So given the below creator
View::creator('a', function ($view) {
$view->with(['foo' => 'foo as CREATED']);
});
I am able to then use (in a route Closure for example)
return view('a')->with('foo', 'foo from composition');
// Expected a.blade foo from composition (excluding inclusion of b)
// Actual a.blade foo from composition (excluding inclusion of b)
But I am not able to use
return view('a', ['foo' => 'foo from composition']);
// Expected a.blade foo from composition (excluding inclusion of b)
// Actual a.blade foo as CREATED (excluding inclusion of b)
This isn't so much of an issue here as I can use ->where() but my problem lies in the fact that I can no longer use blade directives #include or #component within my templates.
So given the above example, add a creator for a
View::creator('b', function ($view) {
$view->with(['bar' => 'bar AS CREATED']);
});
Then in a.blade.php as above
#include('b')
#include('b', ['bar' => 'bar as param'])
// Expected
// b.blade bar AS CREATED
// b.blade bar as param
// Actual
// b.blade bar AS CREATED
// b.blade bar AS CREATED
So I'm looking for a way I can achieve the ability to provide defaults for variables to views and then override them with these syntax
view('a', ['foo' => 'bar']);
#include('a', ['foo' => 'bar'])
#component('a', ['foo' => 'bar'])

Related

Mutating data in Alpine JS

I am trying to achieve something that seems trivial.
<main x-data='x'>
<p x-text='foo'>
</main>
The foo needs to be changed by some external event (callback from a library etc.)
This
window.x = {
foo: 'bar',
setFoo: foo => this.foo = foo
}
// late, after `alpine:init`
window.x.foo = 'boo' // doesn't work
window.x.setFoo('boo') // doesn't work
The same goes for the $store.
I can try and declare Alpine.data('x'), but then there is no (documented) way to call a setter.
In your example x is now an Alpine.js component, so you have to use the Alpine.js way to mutate the reactive data. First, instead of p-text, you have to use x-text:
<main x-data='x'>
<p x-text='foo'>
</main>
And to mutate data, you can access the reactive properties in $data object:
x.$data.foo = '42'
For the store you can use the global Alpine.store() method:
// Create number1 property in $store:
document.addEventListener('alpine:init', () => {
Alpine.store('number1', '0')
})
// Set number1 to 42 externally:
Alpine.store('number1', 42)

Passing data to both extended and sub view in Laravel

At first, I had just one view file that contained all codes for showing a page. but now I decided to split code sections.
So, as I learned, I would make a child view, write my section codes to that file and now return the child view in Laravel Controller. So now passed data goes to child view and in parent view, I have no access to them until I call yield function. But in parent view I need some of that data before calling yield. So How can I pass data which would be available both in parent view and sub view?
I've already tried passing data in extends() as a second parameter but this way
data will be available just when I call yield.
Controller :
class walletsController extends Controller
{
function name(){
return view("subview", ["somedata" => $somedata])
}
}
subview blade file :
#extends('parentview',["somedata" => $somedata] )
#section('wallet')
// some codes here
#endsection
parentview blade file :
// some codes
#yield('wallet')
when I try to use data that being passed in extends() before calling yield it gives me a garbage value.
In this case I would recommend using Laravel's View Composers.
View Composers allow you to pass variables to any view the you want (id doesn't matter if it's a parent or child view).
In your case, you will pass a variable that will be used only on parentview, right?
The code in the AppServiceProvider (boot() method) would be like this:
view()->composer(['parentview', 'folder.another-view-that-you-want'], function ($view) {
$someVar = 'some var value';
$view->with(['someVar' => $someVar]);
});
You can also pass a variable to every single view, using *:
view()->composer('*', function ($view) {
$someVar = 'some var value';
$view->with(['someVar' => $someVar]);
});
Of course, you can read further in the docs: https://laravel.com/docs/5.8/views#view-composers

How to pass javascript variable from laravel controller to vuejs component

I'm trying to build a page on Laravel 5.4 which contains few data which needs to be manipulated and then sent across the views. My view contains components of the vuejs v2.0. I want those data to be implemented in the components. I tried using the laracasts PHP Vars to JS transformer but unable to get it. I followed the steps by placing "laracasts/utilities": "~2.0" in my composer.json then I added the serviceprovider as mentioned in the documentation, I published the vendor and added the following in config/javascript.php,
'bind_js_vars_to_this_view' => 'Nitseditor.show',
I'm having a dynamic views folder which is currently inside my Nitseditor\home\resources\views Now in my controller I'm having following codes:
public function show()
{
JavaScript::put([
'foo' => 'bar',
'age' => 29
]);
return view(Nitseditor.show);
}
Now first of all it was throwing an error as I see that it was including use MongoDB\BSON\Javascript; then I removed and tried using use JavaScript
Now in the app.js file which is present in my asset folder, I'm including each components and trying to do console.log(foo); but its throwing an error foo not defined.
There are a few ways to do this depending on what you are trying to achieve and how your project is set up. The simplest way is to make a request to your controller from inside your component that returns json. Laravel 5.4 comes with axios so you can use that:
methods: {
getData(){
axios.get('/controller/route')
.then(response => {
// set your variables from the response
this.myData = response.data;
})
.catch(error => {
console.log(error);
});
},
data(){
return {
myData: {}
}
}
If you need child components to access the data then you would need to put that in the parent and pass myData" using props.
You could also create a directive and pass your variable down directly from your blade template:
Vue.directive('init', {
bind: function(el, binding, vnode) {
vnode.context[binding.arg] = binding.value;
}
});
Then you would just need to do:
<div v-init:vars="{foo: 'foo', age: 29}"></div>
And pass vars as props to any component that needs them:
Here's the JSFiddle: https://jsfiddle.net/3e05qwLh/
If you have multiple descendants that rely on your variables you will probably want to look at using vuex.
Dunno if it helps but I use this method for passing variables to javascript:
// in master layout (head section)
<meta name="foo" content="{{ $foo }}">
// in javascript (included or in the template)
foo = $('meta[name=foo]').attr('content');
If you have javascript in the blade template you can use directly this method:
foo = "{{ $foo }}";

Laravel extends - only send parameter when condition

I want to check for $house->category.
Depending on the category i want to send parameters with the #extends() functions.
I can't get it to work. When I use something like:
#if($house->category == 1)
#extends('templates.main')
#else
#extends('templates.main', ['logo' => 'img/logo/logo_red_white_text.png', 'favicon' => 'img/favicon/favicon_red.ico'])
#endif
The template is injected twice.
use "#include" instead of extends, and if it's being injected two times you can prevent that by handling that logic on the controller, make a method "checkHouseCategory" or something like that, to check if $house->category == 1, then just send a boolean to the template.
The problem is that you cannot pass parameters in #extends function.
What you can do is to move the view partial to separated file and then #include it in i.e. main file with the above condition. So this will looks like:
Partial view with #extends I will name: example.blade.php
Then in the main view partial:
#if($house->category == 1)
#include('example')
#else
#extends('example', ['logo' => 'img/logo/logo_red_white_text.png', 'favicon' => 'img/favicon/favicon_red.ico'])
#endif

Laravel form actions leads to undefined route

Form actions always confused me as it seemed very simple just to specify the controller however, every time I use it I always get Route [Controller#method] not defined. So I always go and manually make the route then use a url for my forms.
I currently have a route set up as Route::controller('handle/events', 'EventsController') and I'm trying to call the method postAdd from a form like:
{{ Form::open(['action' => 'EventsController#postAdd']) }}
instead of using
['url' => 'handle/events/add'] which is perfectly acceptable given that this is a RESTful route.
When I use the action, Laravel throws Route [EventsController#postAdd] not defined.. The method postAdd in the EventsController also accepts a parameter which I would like to pass in the form.
In the controller, the method is
public function postAdd($staff = false) {
var_dump($staff); // Always false
}
and once again I thought it would be as simple as:
{{ Form::open(['url' => 'handle/events/add'], true) }} however it did not change the value of $staff.
Recap
I would like to change my forms to point to controller methods rather than urls.
I would like to pass a parameter with my forms.
First Problem can be solved by naming your routes.
For example: Route::post('handle/events/add',['as' => 'handle.event.add', 'uses' => 'EventsController#addMethod']);
Then in your form you can do something like this
{{ Form::open(array('route' => 'handle.event.add', 'method' =>'POST'))}}
Now your form will use EventsController#addMethod
Docs named routes
If you want to pass a parameter to the controller method you can define it in your route
Route::get('handle/{event}',['as' => 'handle.event.add', 'uses' => 'EventsController#addMethod'])
Now your addMethod expects a paramter.

Resources