diff --git a/src/htmx.js b/src/htmx.js index 5955d236..5eaa6ce1 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -472,7 +472,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -481,7 +484,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -490,7 +496,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -1397,6 +1406,7 @@ return (function () { } else if (triggerSpec.delay) { elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { + triggerEvent(elt, 'htmx:trigger') handler(elt, evt); } } @@ -1689,6 +1699,13 @@ return (function () { }); } }); + if (!explicitAction && hasAttribute(elt, 'hx-trigger')) { + explicitAction = true + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { }) + }) + } return explicitAction; } @@ -1773,7 +1790,7 @@ return (function () { if (elt.querySelectorAll) { var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext]"); + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"); return results; } else { return []; @@ -3435,6 +3452,7 @@ return (function () { }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/test/attributes/hx-trigger.js b/test/attributes/hx-trigger.js index a181b979..72086a17 100644 --- a/test/attributes/hx-trigger.js +++ b/test/attributes/hx-trigger.js @@ -11,7 +11,6 @@ describe("hx-trigger attribute", function(){ it('non-default value works', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var form = make('
'); form.click(); form.innerHTML.should.equal("Click Me!"); @@ -756,5 +755,33 @@ describe("hx-trigger attribute", function(){ div.innerHTML.should.equal("test 1"); }); + it("fires the htmx:trigger event when an AJAX attribute is specified", function () { + var param = "foo" + var handler = htmx.on("htmx:trigger", function (evt) { + param = "bar" + }); + try { + this.server.respondWith("GET", "/test1", "test 1"); + var div = make(''); + div.click(); + should.equal(param, "bar"); + } finally { + htmx.off("htmx:trigger", handler); + } + }); + + it("fires the htmx:trigger event when no AJAX attribute is specified", function () { + var param = "foo" + var handler = htmx.on("htmx:trigger", function (evt) { + param = "bar" + }); + try { + var div = make(''); + div.click(); + should.equal(param, "bar"); + } finally { + htmx.off("htmx:trigger", handler); + } + }); }) diff --git a/www/attributes/hx-trigger.md b/www/attributes/hx-trigger.md index c50f3886..ce3dadc9 100644 --- a/www/attributes/hx-trigger.md +++ b/www/attributes/hx-trigger.md @@ -64,7 +64,7 @@ is seen again before the delay completes it is ignored, the element will trigger * `closestHX-Trigger
response header, you will likely want to
-use the `from:body` modifier. E.g. if you send a header like this HX-Trigger: my-custom-event
+If you're trying to fire an event from HX-Trigger
response header, you will likely want to
+use the `from:body` modifier. E.g. if you send a header like this HX-Trigger: my-custom-event
with a response, an element would likely need to look like this:
```html
@@ -108,7 +108,7 @@ with a response, an element would likely need to look like this:
```
in order to fire.
-
+
This is because the header will likely trigger the event in a different DOM hierarchy than the element that you
wish to be triggered. For a similar reason, you will often listen for hot keys from the body.
@@ -148,3 +148,4 @@ The AJAX request can be triggered via Javascript [`htmx.trigger()`](/api#trigger
### Notes
* `hx-trigger` is not inherited
+* `hx-trigger` can be used without an AJAX request, in which case it will only fire the `htmx:trigger` event
diff --git a/www/events.md b/www/events.md
index e027564a..2a4c3ae9 100644
--- a/www/events.md
+++ b/www/events.md
@@ -413,6 +413,16 @@ Timeout time can be set using `htmx.config.timeout` or per element using [`hx-re
* `detail.target` - the target of the request
* `detail.requestConfig` - the configuration of the AJAX request
+### Event - [`htmx:trigger`](#htmx:trigger)
+
+This event is triggered whenever an AJAX request would be, even if no AJAX request is specified. It
+is primarily intended to allow `hx-trigger` to execute client-side scripts; AJAX requests have more
+granular events available, like [`htmx:beforeRequest`](#htmx:beforeRequest) or [`htmx:afterSend`](#htmx:afterSend).
+
+##### Details
+
+* `detail.elt` - the element that triggered the request
+
### Event - [htmx:validation:validate](#htmx:validation:validate)
This event is triggered before an element is validated. It can be used with the `elt.setCustomValidity()` method
diff --git a/www/reference.md b/www/reference.md
index 9821353e..789ae995 100644
--- a/www/reference.md
+++ b/www/reference.md
@@ -163,6 +163,7 @@ The table below lists all other attributes available in htmx.
| [`htmx:swapError`](/events#htmx:swapError) | triggered when an error occurs during the swap phase
| [`htmx:targetError`](/events#htmx:targetError) | triggered when an invalid target is specified
| [`htmx:timeout`](/events#htmx:timeout) | triggered when a request timeout occurs
+| [`htmx:trigger`](/events#htmx:trigger) | triggered by the event specified in `hx-trigger`
| [`htmx:validation:validate`](/events#htmx:validation:validate) | triggered before an element is validated
| [`htmx:validation:failed`](/events#htmx:validation:failed) | triggered when an element fails validation
| [`htmx:validation:halted`](/events#htmx:validation:halted) | triggered when a request is halted due to validation errors