diff --git a/src/htmx.js b/src/htmx.js index 41ae9b382..3ea6eec89 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1313,14 +1313,20 @@ var htmx = (function() { * @returns {(Node|Window)[]} */ function findAttributeTargets(elt, attrName) { - const attrTarget = getClosestAttributeValue(elt, attrName) + let attrTarget = getClosestAttributeValue(elt, attrName) if (attrTarget) { if (attrTarget === 'this') { return [findThisElement(elt, attrName)] } else { + const optional = attrTarget.slice(-1) === '?' + if (optional) { + attrTarget = attrTarget.slice(0, -1) + } const result = querySelectorAllExt(elt, attrTarget) if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + if (!optional) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + } return [DUMMY_ELT] } else { return result diff --git a/test/attributes/hx-include.js b/test/attributes/hx-include.js index 299810ad0..2133bbda6 100644 --- a/test/attributes/hx-include.js +++ b/test/attributes/hx-include.js @@ -224,4 +224,28 @@ describe('hx-include attribute', function() { this.server.respond() btn.innerHTML.should.equal('Clicked!') }) + + it('logs error when selector returns no matches', function() { + this.server.respondWith('POST', '/include', 'Clicked!') + var div = make('
') + const spy = sinon.spy(console, 'error') + div.click() + this.server.respond() + spy.calledOnce.should.equal(true) + spy.calledWith('The selector "input" on hx-include returned no matches!').should.equal(true) + div.innerHTML.should.equal('Clicked!') + spy.restore() + }) + + it('no error when optional selector returns no matches', function() { + this.server.respondWith('POST', '/include', 'Clicked!') + var div = make('') + const spy = sinon.spy(console, 'error') + div.click() + this.server.respond() + spy.calledOnce.should.equal(false) + spy.calledWith('The selector "input" on hx-include returned no matches!').should.equal(false) + div.innerHTML.should.equal('Clicked!') + spy.restore() + }) }) diff --git a/www/content/attributes/hx-disabled-elt.md b/www/content/attributes/hx-disabled-elt.md index fae9860dd..00a9b5c0b 100644 --- a/www/content/attributes/hx-disabled-elt.md +++ b/www/content/attributes/hx-disabled-elt.md @@ -41,5 +41,6 @@ The `hx-disabled-elt` attribute also supports specifying multiple CSS selectors ## Notes * `hx-disabled-elt` is inherited and can be placed on a parent element +* If the supplied selector doesn't match any element, it will log an error to the console which can be avoided by adding a `?` to the end to make it optional e.g. `hx-disabled-elt="find button?"` [hx-trigger]: https://htmx.org/attributes/hx-trigger/ diff --git a/www/content/attributes/hx-include.md b/www/content/attributes/hx-include.md index 5001b8ea8..9406c4c94 100644 --- a/www/content/attributes/hx-include.md +++ b/www/content/attributes/hx-include.md @@ -46,7 +46,7 @@ Note that if you include a non-input element, all input elements enclosed in tha ``` In the above example, when clicking on the button, the `find input` selector is resolved from the button itself, which - does not return any element here, since the button doesn't have any `input` child, thus in this case, raises an error. + does not return any element here, since the button doesn't have any `input` child, thus in this case, raises an error. This can be avoided by adding a `?` to the end to make it optional e.g. `hx-include="find input?"` * A standard CSS selector resolves to [document.querySelectorAll](https://developer.mozilla.org/docs/Web/API/Document/querySelectorAll) and will include multiple elements, while the extended selectors such as `find` or `next` only return a single element at most to diff --git a/www/content/attributes/hx-indicator.md b/www/content/attributes/hx-indicator.md index 9f80813eb..319365535 100644 --- a/www/content/attributes/hx-indicator.md +++ b/www/content/attributes/hx-indicator.md @@ -79,6 +79,7 @@ This simulates what a spinner might look like in that situation: ## Notes * `hx-indicator` is inherited and can be placed on a parent element +* If the supplied selector doesn't match any element, it will log an error to the console which can be avoided by adding a `?` to the end to make it optional e.g. `hx-indicator="find img?"` * In the absence of an explicit indicator, the `htmx-request` class will be added to the element triggering the request * If you want to use your own CSS but still use `htmx-indicator` as class name, then you need to disable `includeIndicatorStyles`. See [Configuring htmx](@/docs.md#config). The easiest way is to add this to the `` of your HTML: