I’ve a list of uploaded files that I plan to render in a view. For each file, I want to call an API endpoint e.g. /api/v1/fileinfo
to fetch some information and display it.
My blade template is following. A sample HTML page generated from it is shown above.
@extends('layouts.app')
@section('content')
<div class="container">
<h3>Files</h3>
@foreach ($files as $file)
<div class="card m-1 px-2 py-1">
<div class="card-content">
{{ $file['display_name'] }}
</div>
<div>
<button class="btn btn-secondary">Show Information</button>
</div>
</div>
@endforeach
</div>
@endsection
Being old school, I don’t want to enable livewire/inertia just for this. I thought of of using AJAX which all the cool kids were using a decade ago.
Recently I read about HTMX. It is a good opportunity to play with it. The HTMX documentation (</> htmx ~ Documentation) is superb. The API looks great. AJAX can wait.
In code sample shown below, htmx-post
define the endpoint that will be called with data defined in hx-vals
when hx-trigger
event occurs. The inner img
with class htmx-indicator
will get triggered and we’ll see a indicator spinning for a short while. The value received from server will be put into hx-target
which has id $id
. $id
is generated randomly by PHP to create one-to-one mapping between hx-target
and target div
.
@foreach ($files as $file)
<div class="card m-1 px-2 py-1">
<!-- Generate a unique id to insert content received from POST
request -->
@php($id=uniqid("div_"))
<div class="card-content">
{{ $file['display_name'] }}
</div>
<div>
<button class="btn btn-link"
hx-post="/api/v1/fileinfo"
hx-vals='{"path" : "{{ $file["path"] }}" }'
hx-target='#{{ $id }}'
hx-trigger="mouseenter"
>
File Information
<img class="bg-primary htmx-indicator" src="{{ asset('svg/90-ring.svg') }}" />
</button>
<div id="{{ $id }}">
</div>
</div>
</div>
@endforeach
Let’s see this in action. We barely see the spinner since the request doesn’t take much time.
Importantly, note that we render raw JSON😢. HTMX expects HTML from servers and doesn’t support JSON → HTML conversion natively. Well, this sucks for obvious reasons. Who returns HTML from APIs?!
So we have to turn JSON into HTML by ourselves. Thankfully there are community maintained plugins such as client-side-templates. See https://github.com/bigskysoftware/htmx-extensions/blob/main/src/client-side-templates/README.md. The plugin documentation is pretty clear. I am going to show the final solution.
div
has hx-ext
set that enables the extension.hx-target
is replaced by mustache-template
.<template>
is added. If you are using blade then you have to prefix mustache template with @
so that blade doesn’t touch them. The template create HTML out of JSON.Let’s try again! Great, I got most basic functionalities working.
Apparently HTMX is quite powerful. You can search HN for resources https://hn.algolia.com/?q=htmx