handle errors with HTMX

Viewed 1654
<form  
 class="" id="form" hx-post="/add/" hx-swap="afterbegin" hx-target="#big_list" hx-trigger="submit">
    <input type="text" name="langue1" >
    <input type="text" name="langue2">
    <div id="errors"></div>
    <button type="submit">GO</button>
</form> 
<div id="big_list"> 
.....
</div>

I have a big list in #big_list, and I want my #form appends only one row when submitted.

How with htmx, can I handle errors and show message in #errors ?

3 Answers

I created this solution so you can use hx-target-error = to define which HTML will be displayed after a failed request

document.body.addEventListener('htmx:afterRequest', function (evt) {
  const targetError = evt.target.attributes.getNamedItem('hx-target-error')
  if (evt.detail.failed && targetError) {
    document.getElementById(targetError.value).style.display = "inline";
  }
});
document.body.addEventListener('htmx:beforeRequest', function (evt) {
  const targetError = evt.target.attributes.getNamedItem('hx-target-error')
  if (targetError) {
    document.getElementById(targetError.value).style.display = "none";
  }
});

Although it doesn't follow REST principles, you might consider using an swap-oob to report your error back to your user. For example, your request might return a (slightly misleading) status 200, but include content like this:

<div id="errors" hx-swap-oob="true">
  There was an error processing your request...
</div>

If it's important to follow REST more precisely, then you'll want to listen to the htmx:responseError event, as mentioned by @guettli in his previous answer.

If your code raises the errors (validation?), you can change target and swap behavior with response headers.

Response.Headers.Add("HX-Retarget", "#errors"); 
Response.Headers.Add("HX-Reswap", "innerHTML");

If you want to return a status other than 200, you have to tell htmx to accept it. 4xx would normally not do a swap in htmx. In case of validation errors you could use 422.

document.body.addEventListener('htmx:beforeOnLoad', function (evt) {
    if (evt.detail.xhr.status === 422) {
        evt.detail.shouldSwap = true;
        evt.detail.isError = false;
    }
});

It works in htmx 1.8.

If you want to remove the error message on then next sucessfull request, you could use hx-swap-oob. Out of band elements must be in the top level of the response. So the response could look like this:

<div>
    your new row data...
</div>
<div id="errors" hx-swap-oob="true"></div>
Related