laravel-htmx icon indicating copy to clipboard operation
laravel-htmx copied to clipboard

Retarget and Reswaping with views

Open CallumBee opened this issue 1 year ago • 4 comments

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

CallumBee avatar Sep 24 '24 22:09 CallumBee

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');

mauricius avatar Sep 25 '24 16:09 mauricius

Thanks that makes total sense. I knew it was looking at it all wrong!

CallumBee avatar Sep 26 '24 18:09 CallumBee

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.

Tom-CDA avatar Sep 09 '25 15:09 Tom-CDA

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.

mauricius avatar Sep 18 '25 17:09 mauricius