laravel-htmx
laravel-htmx copied to clipboard
Retarget and Reswaping with views
I am trying to do some re-targeted swapping and looking at the documents I see I can use the retarget and reswap methods and came up with this:
return with(new HtmxResponse())->view('components.recipe.ingredient-add-form',[
'errors' => $validator->errors(),
'allIngredients' => auth()->user()->ingredients,
])->retarget('#ingredientAddForm')->reswap('outerHTML');
However it throws a Method Mauricius\LaravelHtmx\Http\HtmxResponse::view does not exist. error. I am still getting my feet wet with Laravel and such so im sure its a me problem and not fully understanding it. Am I doing it right of have I got the wrong end of the stick.
Thanks
The HtmxResponse class doesn't have a view method because it's supposed to render only fragments of views, instead of a full view. However I guess you can still return the full view by adding a rendered view to the fragments list, more or less like this (I'm writing by memory)
$view = view()->make('components.recipe.ingredient-add-form', [
'errors' => $validator->errors(),
'allIngredients' => auth()->user()->ingredients,
]);
return with(new HtmxResponse())
->addRenderedFragment($view)
->retarget('#ingredientAddForm')
->reswap('outerHTML');
Thanks that makes total sense. I knew it was looking at it all wrong!
Sorry to bother on this, but it is a bit annoying that there is no such easy feature. I am currently adding a dummy @fragment to all my views, like
<x-layouts.superuser>
@fragment('customers.index')
<div>Some search input form and button goes here</div>
<div id="customers-table">
@fragment('customers.table')
<table class="table-auto w-full">
<thead>
<tr>
<th>{{ __('id') }}</th>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach($customers as $c)
<tr>
<td>{{ $c->id }}</td>
<td>{{ $c->name }}</td>
</tr>
@endforeach
</tbody>
</table>
<div class="mt-4" hx-boost="true" hx-target="#customers-table">
{!! $customers->withQueryString()->links() !!}
</div>
@endfragment
</div>
@endfragment
</x-layouts.superuser>
just to be able to render the full fragment on needing to load the table with search and pagination, and to only render the table upon pagination itself.
if ($request->isHtmxRequest()) {
if ($request->getTarget() === 'customers-table') {
// Only the table fragment
return HtmxResponse::addFragment('customers.index', 'customers.table', compact('customers'));
}
// Full page with table fragment
return HtmxResponse::addFragment('customers.index', 'customers.index', compact('customers'));
}
It would be easier to just go HtmxResponse::view('customers.index', compact($customers)) and this would just render only the view file.
Afaik the View::make() solution also renders the entire layout around it.
Yeah that's a good point, I have been victim of this myself. I think the correct way to handle this would be to just treat HtmxResponse as a regular response instead of delegating also the task to render the view. Your example would become like this
<?php
return new HtmxResponse(View::make('customers.index', compact($customers)));
But I guess at this point it would just be easier and more understandable to just return View::make('customers.index', compact($customers)), unless of course you need htmx-specific methods.