Skip to content

Commit b98e4f2

Browse files
fix htmx.ajax defaulting to swap body when target not found (#2878)
* ajax helper handle no target * allow source only targeting * Add tests * Handle source set but invalid target set * Improve source logic * missed # * improve readiblity and add inline comment
1 parent df92b29 commit b98e4f2

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

src/htmx.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3901,16 +3901,22 @@ var htmx = (function() {
39013901
if (context) {
39023902
if (context instanceof Element || typeof context === 'string') {
39033903
return issueAjaxRequest(verb, path, null, null, {
3904-
targetOverride: resolveTarget(context),
3904+
targetOverride: resolveTarget(context) || DUMMY_ELT,
39053905
returnPromise: true
39063906
})
39073907
} else {
3908+
let resolvedTarget = resolveTarget(context.target)
3909+
// If target is supplied but can't resolve OR both target and source can't be resolved
3910+
// then use DUMMY_ELT to abort the request with htmx:targetError to avoid it replacing body by mistake
3911+
if ((context.target && !resolvedTarget) || (!resolvedTarget && !resolveTarget(context.source))) {
3912+
resolvedTarget = DUMMY_ELT
3913+
}
39083914
return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event,
39093915
{
39103916
handler: context.handler,
39113917
headers: context.headers,
39123918
values: context.values,
3913-
targetOverride: resolveTarget(context.target),
3919+
targetOverride: resolvedTarget,
39143920
swapOverride: context.swap,
39153921
select: context.select,
39163922
returnPromise: true

test/core/api.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,71 @@ describe('Core htmx API test', function() {
213213
div.innerHTML.should.equal('foo!')
214214
})
215215

216+
it('ajax api does not fall back to body when target invalid', function() {
217+
this.server.respondWith('GET', '/test', 'foo!')
218+
var div = make("<div id='d1'></div>")
219+
htmx.ajax('GET', '/test', '#d2')
220+
this.server.respond()
221+
document.body.innerHTML.should.not.equal('foo!')
222+
})
223+
224+
it('ajax api fails when target invalid', function(done) {
225+
this.server.respondWith('GET', '/test', 'foo!')
226+
var div = make("<div id='d1'></div>")
227+
htmx.ajax('GET', '/test', '#d2').then(
228+
(value) => {
229+
},
230+
(reason) => {
231+
done()
232+
}
233+
)
234+
this.server.respond()
235+
div.innerHTML.should.equal('')
236+
})
237+
238+
it('ajax api fails when target invalid even if source set', function(done) {
239+
this.server.respondWith('GET', '/test', 'foo!')
240+
var div = make("<div id='d1'></div>")
241+
htmx.ajax('GET', '/test', {
242+
source: div,
243+
target: '#d2'
244+
}).then(
245+
(value) => {
246+
},
247+
(reason) => {
248+
done()
249+
}
250+
)
251+
this.server.respond()
252+
div.innerHTML.should.equal('')
253+
})
254+
255+
it('ajax api fails when source invalid and no target set', function(done) {
256+
this.server.respondWith('GET', '/test', 'foo!')
257+
var div = make("<div id='d1'></div>")
258+
htmx.ajax('GET', '/test', {
259+
source: '#d2'
260+
}).then(
261+
(value) => {
262+
},
263+
(reason) => {
264+
done()
265+
}
266+
)
267+
this.server.respond()
268+
div.innerHTML.should.equal('')
269+
})
270+
271+
it('ajax api falls back to targeting source if target not set', function() {
272+
this.server.respondWith('GET', '/test', 'foo!')
273+
var div = make("<div id='d1'></div>")
274+
htmx.ajax('GET', '/test', {
275+
source: div
276+
})
277+
this.server.respond()
278+
div.innerHTML.should.equal('foo!')
279+
})
280+
216281
it('ajax api works with swapSpec', function() {
217282
this.server.respondWith('GET', '/test', "<p class='test'>foo!</p>")
218283
var div = make("<div><div id='target'></div></div>")

0 commit comments

Comments
 (0)