Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

afterRequest, afterSettle events never trigger #79

Closed
warpr opened this issue Jun 3, 2020 · 13 comments
Closed

afterRequest, afterSettle events never trigger #79

warpr opened this issue Jun 3, 2020 · 13 comments

Comments

@warpr
Copy link

warpr commented Jun 3, 2020

Hello! I'm trying to use htmx to navigate an app while only a small part of the page doesn't reload (because it contains an <audio> element playing music).

Some events don't seem to be working, here is a small test file to reproduce the issue:

<?php declare(strict_types=1);

$link = $_SERVER['SCRIPT_NAME'] . '?t=' . time();

?>
<html>
    <head>
        <title>htmx test</title>
        <script src="https://unpkg.com/[email protected]"></script>
        <meta name="htmx-config" content='{"defaultSwapStyle":"outerHTML"}'>
        <script>
         htmx.on('beforeOnLoad.htmx', () => console.log('beforeOnLoad'));
         htmx.on('beforeRequest.htmx', () => console.log('beforeRequest'));
         htmx.on('afterRequest.htmx', () => console.log('afterRequest'));
         htmx.on('afterSettle.htmx', () => console.log('afterSettle'));
        </script>
    </head>
    <body>
        <audio src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" controls></audio>
        <div id="content">
            <h1>HTMX event test <?= time() ?></h1>
            <a href="<?= $link ?>"
               hx-boost="true"
               hx-target="#content"
               hx-select="#content">Click this link!</a>
        </div>
    </body>
</html>

When I click the link, the #content div reloads correctly (leaving the audio element playing), however only the beforeRequest and beforeOnLoad events get triggered.

I saw this mentioned in #75 , but it didn't seem to have it's own GitHub issue.

@1cg
Copy link
Contributor

1cg commented Jun 3, 2020

Can you enable logging w/

  htmx.logAll()

and see if the events are firing? It might be a bug in htmx.on rather than the logging system. :/

@warpr
Copy link
Author

warpr commented Jun 3, 2020

Yes, they do show up in htmx.logAll():

htmx.min.js:1 configRequest.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class=​"htmx-request">​Click this link!​</a>​ {parameters: {…}, unfilteredParameters: {…}, headers: {…}, target: div#content, verb: "get", …}
htmx.min.js:1 beforeRequest.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content, elt: a}
htmx.php:9 beforeRequest
htmx.min.js:1 beforeOnLoad.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content, elt: a.htmx-request}
htmx.php:8 beforeOnLoad
htmx.min.js:1 beforeSwap.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content, elt: a.htmx-request}
htmx.min.js:1 beforeHistorySave.htmx <body>​…​</body>​ {path: "/tmp/htmx.php", historyElt: body, elt: body}
htmx.min.js:1 afterSwap.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content.htmx-settling, elt: a.htmx-request}
htmx.min.js:1 afterRequest.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content.htmx-settling, elt: a}
htmx.min.js:1 afterOnLoad.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content.htmx-settling, elt: a}
htmx.min.js:1 load.htmx <div id=​"content">​…​</div>​ {elt: div#content}
htmx.min.js:1 afterSettle.htmx <a href=​"/​tmp/​htmx.php?t=1591196570" hx-boost=​"true" hx-target=​"#content" hx-select=​"#content" class>​Click this link!​</a>​ {xhr: XMLHttpRequest, target: div#content, elt: a}

@1cg
Copy link
Contributor

1cg commented Jun 3, 2020

OK, that looks like a bug in the htmx.on method then.

Can you add an event listener directly to the element? I'm planning on removing the "on" method in the next release.

@warpr
Copy link
Author

warpr commented Jun 3, 2020

Which element can I attach these listeners to to make sure I get the same events logAll() sees?

@1cg
Copy link
Contributor

1cg commented Jun 3, 2020

If you look in the log messages in Chrome or Firefox, you should see the element that the event was triggered on and you can usually right click on it and have it revealed in the DOM.

@warpr
Copy link
Author

warpr commented Jun 4, 2020

I've changed my test to add listeners to the <a href> element, which works once. If I click the link a second time the events no longer trigger -- which is expected, because the element is destroyed when htmx swaps it out for the new one provided by the server. it doesn't seem very useful, at least not for my usecase :)

This is my code now (full file here):

        function listen(node) {
             console.log('set up listeners for', node);
             node.addEventListener('beforeOnLoad.htmx', () => console.log('beforeOnLoad'));
             node.addEventListener('beforeRequest.htmx', () => console.log('beforeRequest'));
             node.addEventListener('afterRequest.htmx', () => console.log('afterRequest'));
             node.addEventListener('afterSettle.htmx', () => console.log('afterSettle'));
         }

         document.querySelectorAll('a').forEach(listen);

Trying some different approaches, I also looked into using the extension mechanism, so I used htmx.defineExtension and adding hx-ext on the body:

        <script>
             htmx.defineExtension('kuno-ext', {
                 onEvent: (name, event) => console.log('kuno-ext', name, event)
             });
        </script>
    </head>
    <body hx-ext='kuno-ext'>

The extension also doesn't get the afterRequest or afterSettle events, here is the full log after clicking the link:

kuno-ext configRequest.htmx CustomEvent {isTrusted: false, detail: {…}, type: "configRequest.htmx", target: a, currentTarget: null, …}
kuno-ext beforeRequest.htmx CustomEvent {isTrusted: false, detail: {…}, type: "beforeRequest.htmx", target: a, currentTarget: null, …}
kuno-ext beforeOnLoad.htmx CustomEvent {isTrusted: false, detail: {…}, type: "beforeOnLoad.htmx", target: a.htmx-request, currentTarget: null, …}
kuno-ext beforeSwap.htmx CustomEvent {isTrusted: false, detail: {…}, type: "beforeSwap.htmx", target: a.htmx-request, currentTarget: null, …}
kuno-ext beforeHistorySave.htmx CustomEvent {isTrusted: false, detail: {…}, type: "beforeHistorySave.htmx", target: body, currentTarget: null, …}
kuno-ext processedNode.htmx CustomEvent {isTrusted: false, detail: {…}, type: "processedNode.htmx", target: div#content, currentTarget: null, …}
kuno-ext processedNode.htmx CustomEvent {isTrusted: false, detail: {…}, type: "processedNode.htmx", target: h1, currentTarget: null, …}
kuno-ext processedNode.htmx CustomEvent {isTrusted: false, detail: {…}, type: "processedNode.htmx", target: a, currentTarget: null, …}
kuno-ext load.htmx CustomEvent {isTrusted: false, detail: {…}, type: "load.htmx", target: div#content, currentTarget: null, …}

@1cg
Copy link
Contributor

1cg commented Jun 4, 2020

OK, in the first part I think I see the problem: the anchors are getting swapped out and so the listener isn't working any more.

In the second case, that seems like a bug: the afterRequest and afterSettle events should bubble up to the body even if they are on new elements and cause the extension to fire. I'll have to dig into it.

Sorry for the issue, I'm currently on vacation but will look at it on Tuesday when I'm back.

@warpr
Copy link
Author

warpr commented Jun 4, 2020

@chg20 thanks for looking into it, there's no hurry :)

@bencroker
Copy link
Collaborator

I can confirm the above, and that afterSwap is also never triggered when replacing an element.

@tomberek
Copy link

tomberek commented Jun 5, 2020

My expectation was that the elt and target of the event would be identical for beforeRequest.htmx and afterRequest.htmx. Specifically the elt moved. Not sure if this is by design.

@1cg
Copy link
Contributor

1cg commented Jun 10, 2020

OK, so I think the problem here is that we are replacing the outerHTML, which causes elt to be removed from the DOM, which prevents the event from bubbling up.

Hmmm. What's the right thing here?

Probably to trigger the event on the replacement element. That's kinda ugly in the code though.

@1cg
Copy link
Contributor

1cg commented Jun 10, 2020

OK, looking at the code, I think we should trigger the events on the replacement content, rather than on the elt, since the elt might have been replaced. Does this sound reasonable?

1cg pushed a commit that referenced this issue Jun 10, 2020
…triggering element may have been replaced

fixes #79
@1cg
Copy link
Contributor

1cg commented Jun 10, 2020

Fixed and tested w/ 6f14cba

@1cg 1cg closed this as completed Jun 10, 2020
strangeRabbit777 added a commit to strangeRabbit777/high-power-tool that referenced this issue Aug 23, 2022
strangeRabbit777 added a commit to strangeRabbit777/high-power-tool that referenced this issue Aug 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants