What does these directives do ?
Blade @push and @stack - are they here to stay?
The @push and @stack commands have been in Laravel for a year now, but have not made it to any documentation yet. I only discovered them by accident.
So, are they here to stay? Or should I avoid using them? For their use-case - being able to define blocks of markup in lower-level views that need to be aggregated in higher level views to support their functionality, is spot-on.
In a detail view you may want to throw a bit of JavaScript up into the head of the page to support something that view does. So you could do this to define the script in the detail view:
@push('script-head')
<script>
...do some stuff here that this view needs...
</script>
@endpush
You could have multiple views pushing their own stuff onto script-head, or maybe script-body or css-file-just-for-this-page or whatever stacks you want to use.
In the outer layout template, these fragments can be pulled out like this:
<head>
...other stuff...
@stack('script-head')
</head>
<body>
...
These are just fragments of markup - any low-level view can throw these fragments to any higher-level view to say, "here, show this over at your place for me". It is simple, works, and is something that I have been doing on other frameworks for the last 15 years, so it is nice to see it pop up in Laravel. I'm running 5.1 at the moment.
Wow, I've been using sections for this, this looks useful.
I ended up having a content section, a custom-style section and a scripts section. I could just use stacks.. Brilliant, even though it is practically the same, but partials can add code if only it is required without complex if-else directives in the main page, with poorly placed code in the middle of the markup.
Great ! Thanks for pointing this out.
It's even nicer. I just found that it can be used multiple times inside a view, and anywhere inside that view.
So if you put it at the bottom of the view, it has access to all the data passed into the view. That's straight forward.
However, if you @push() from inside, say, a form using model binding, then it has access to that context. In my use-case I needed to call a function in the page head with the initial value of a form item in a model-bound form. The only way to find out what value has been given to those form items (whether from the bound model, or POSTed to a form that has failed validation checks) is to use Form::getValueAttribute('field_name'). Outside of Form::model() and Form::close() pair, that method will return null, but inside the form it returns the form value when the page is loaded.
Remember: when you bind your model to a form, the values presented to the user in that form are only the same as the values in that model as a fall-back, if the user has not just posted that form. The model contains what is in the database, not the transient entered values as the form is completed.
So I have this in my page:
{!! Form::model($my_model) !!}
Enter the timezone:
{!! Form::text('timezone', null) !!}
@push('scripts-footer')
<script type="text/javascript">
ko.applyBindings(new MyViewModel(
{!! json_encode(Form::getValueAttribute('timezone')) !!}
));
</script>
@endpush
{!! Form::close() !!}
I've left out stuff not relevant here. It means in the footer of my page I now have a call to my ko viewmodel, with a parameter passed in of the initial value of the timezone form item, as presented to the user, regardless of whether this form is being presented to them for the first tine, or represented to them on a validation failure of an entered timezone.
There may be better ways to do this, but I've not found a quick and easy way for knockout to bind to a form item as an observer, without knockout being forced to set the initial value of that form item. This does it nicely in MyViewModel.
just thought I would share that!
@pmall well, no, that was the point. $model contains the values of the model in the database. If the user has just submitted the form and it fails a validation check, then the form is re-presented for the user to make corrections. Laravel will automatically override the model values for the form items that were POSTed, so they are NOT necessarily going to be the same as the model. Doing it the way you describe means the whole form gets reset every time the user makes a single mistake resulting in a validation failure. Good point though - I did try that first.
What I would ideally like to do, is for knockout to be able to bind to a form field as an observer, without it taking over the initial value of that form item. But it seems you have to give it that initial value, unless you want to get into complex custom bindings, which I'm steering clear of at the moment.
Obviously beyond what I have posted here, is a much more complex form, with all sorts of relationships between various items and groups of items, that knockout deals with. I'm kind of skirting around that in this post to stick to the Laravel-specific stuff.
Yes, good one - that works. I had no idea this old helper function existed. That gives the presented value of the form item outside of the form section of the blade template. I think I'll switch to that instead of nesting the @push block into other content blocks, just in case that nesting is relying on assumptions that don't hold true in later versions.
Thanks :-)
(Note: an extra "{!!...!!}" pair have crept into your example, inside the json_encode. Just mentioning that for future readers.)
So what is the difference with:
@section('scripts-footer')
This will be appended to the section without overwriting parent content...
@append
Please or to participate in this conversation.