htmx icon indicating copy to clipboard operation
htmx copied to clipboard

hx-on is not working for custom events

Open warcayac opened this issue 1 year ago • 6 comments

Taking this video as reference I've tried to fire a custom event with hx-on attribute but is not working.

Client-side code:

export default function Home({people}: TProps) {
  return (
    <Layout>
      <div>
        <h2>Phonebook</h2>
        <form 
          hx-post="/api/contacts"
          hx-swap="innerHTML"
          hx-target="#listing-box"
          hx-on--after-request="this.reset()"
          hx-on--customevent="console.log('chesu!!')"
          >
          <div>
            <label for="name">Name: </label>
            <input type="text" name="name" id="name"/>
          </div>
          <div>
            <button type="submit">add</button>
          </div>
        </form>
        <h2>Numbers</h2>
        <div id="listing-box">
          <PeopleListingBox {...{people}}/>
        </div>
      </div>
    </Layout>
  )
}

Layout component code:

export default function Layout({ children, title = 'My App' } : TProps) {
  return (
    <>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />

          <link rel="icon" href="/public/img/elysia.png"></link>
          <link rel="stylesheet" href="/public/styles/main.css"></link>

          <script src="https://unpkg.com/[email protected]" integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2" crossorigin="anonymous"></script>
          <script src="https://unpkg.com/[email protected]"></script>

          <title>{title}</title>
        </head>

        <body>
          {children}
        </body>
      </html>
    </>
  );
}

Server side code for contacts Api (I'm using Bun with ElysiaJs):

export const contactsRoutes = new Elysia()
  .use(html())
  .post(
    '/',
    ({html, body: {name}, set}) => {
      const value = name.toLowerCase();
      if (people.some(person => person.name.toLowerCase() === value)) {
        set.headers['hx-trigger'] = 'customevent';
      } else {
        const newPerson: TContact = {
          id: 0,
          name,
          number: "?",
        }
        people.push(newPerson);
      }
      // set['status'] = 201;
      return html(<PeopleListingBox {...{people}} />);
    },
    {
      body: t.Object({
        name: t.String({minLength: 3, maxLength: 100})
      })
    }
  )
;

after sending a Post request with a duplicate name, server returns this for Response Headers section:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf8
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Vary: *
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Expose-Headers: *
Access-Control-Exposed-Headers: *
hx-trigger: customevent
Date: Thu, 09 May 2024 17:13:11 GMT
Content-Length: 120

However custom event is not fired as expected and console shows no output. I've tried with:

hx-on="customevent: console.log('chesu!!')"

same result, no output.

warcayac avatar May 09 '24 17:05 warcayac

Most likely you had Typo error, seems like htmx is case sensitive went it comes to headers, so instead of hx-trigger, you use HX-Trigger it will work fine.

Eg:

`import { Elysia } from "elysia"; import { html } from '@elysiajs/html'

const app = new Elysia() app .use(html()) .get('/', () => { return '

Test init

target here
' }) .get('/binding', ({ set }) => { set.headers['HX-Trigger'] = 'custom-event'
return '<span>Msg from server</span>'

}) .listen(3000);

console.log( 🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port} ); `

DioLps avatar May 15 '24 03:05 DioLps

I don't think so because I previously tried (like as the reference video ) with "Hx-Trigger" and it didn't work. Instead of using hx-on I've tried hyperscript and it is working as expected.

warcayac avatar May 15 '24 04:05 warcayac

Well I'm glad that you find another solution. But the example above it's working as well, maybe you use the "Hx-Trigger" with 'x' in lower case and it caused the issue? Not sure to be fair.

:)

DioLps avatar May 15 '24 05:05 DioLps

I think the problem with hx-on is that it's listening on the element it is placed on. You'd need something like hx-on-from-body. :)

andryyy avatar May 15 '24 05:05 andryyy

I've tested my code again with some variants and here my observations:

  • the formats hx-on--customevent= or hx-on-customevent= are definitely not working
  • the format hx-on="customevent: is working,
  • the key "hx-trigger" passed as header is insensitive-case

The strange here is when I posted this issue, the format hx-on="customevent: was not working but it is now @ _ @ however that format will be deprecated as documentation, so it is not really a solution. Moreover it seems hx-on is very limited regarding the number of operations I can do, hyperscript is more flexible in this aspect.

warcayac avatar May 15 '24 05:05 warcayac

Nice, good job!

DioLps avatar May 15 '24 06:05 DioLps

yes, hx-on is designed to only be used for simple things, for anything beyond that i highly recommend hyperscript, alpine.js or https://github.com/gnat/surreal

1cg avatar Jun 18 '24 17:06 1cg

I think the problem with hx-on is that it's listening on the element it is placed on. You'd need something like hx-on-from-body. :)

Yes this was my issue thank you... I think this should really be documented as a gotcha. If the element with the hx-on is replaced, the hx-on is no longer executed.

chrissound avatar Mar 08 '25 23:03 chrissound