Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/htmx.js
Original file line number Diff line number Diff line change
Expand Up @@ -1787,14 +1787,17 @@ var htmx = (() => {

__collectFormData(elt, form, submitter, validate, isGet) {
if (validate && form && !form.reportValidity()) return


// treat a named submit button that owns hx-post as its own submitter (#4073)
submitter ??= (form && elt.type === 'submit') ? elt : null;

let formData = form ? new FormData(form) : new FormData()
let included = form ? new Set(form.elements) : new Set()
if (!form) {
if (validate && elt.reportValidity && !elt.reportValidity()) return
this.__addInputValues(elt, included, formData, isGet);
}
if (submitter && submitter.name) {
if (submitter?.name) {
formData.append(submitter.name, submitter.value)
included.add(submitter);
}
Expand Down
57 changes: 57 additions & 0 deletions test/tests/unit/__collectFormData.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,61 @@ describe('__collectFormData unit tests', function() {
let formData = htmx.__collectFormData(elt, null, null, false, false);
assert.deepEqual(formData.getAll('fruit'), ['banana', 'apple']);
});

// ── submit button name/value regression ────────────────────────────────

it('button[hx-post] inside form sends its own name/value', function () {
let form = createProcessedHTML('<form><input name="txt" value="hello"><button type="submit" name="btn" value="B"></button></form>')
let btn = form.querySelector('button')
let formData = htmx.__collectFormData(btn, form, null)
assert.equal(formData.get('txt'), 'hello')
assert.equal(formData.get('btn'), 'B')
})

it('form[hx-post] sends clicked submit button name/value via evt.submitter', function () {
let form = createProcessedHTML('<form><input name="txt" value="hello"><button type="submit" name="btn" value="B"></button></form>')
let btn = form.querySelector('button')
let formData = htmx.__collectFormData(form, form, btn)
assert.equal(formData.get('txt'), 'hello')
assert.equal(formData.get('btn'), 'B')
})

it('standalone button[hx-post] with no form sends its own name/value', function () {
let btn = createProcessedHTML('<button type="submit" name="btn" value="C"></button>')
let formData = htmx.__collectFormData(btn, null, null)
assert.equal(formData.get('btn'), 'C')
})

it('only the clicked button value is sent when multiple submit buttons exist', function () {
let form = createProcessedHTML('<form><input name="txt" value="hello"><button type="submit" name="action" value="save"></button><button type="submit" name="action" value="delete"></button></form>')
let save = form.querySelectorAll('button')[0]
let del = form.querySelectorAll('button')[1]
let fd1 = htmx.__collectFormData(save, form, null)
assert.equal(fd1.get('action'), 'save')
let fd2 = htmx.__collectFormData(del, form, null)
assert.equal(fd2.get('action'), 'delete')
})

it('input[type=submit][hx-post] inside form sends its own name/value', function () {
let form = createProcessedHTML('<form><input name="txt" value="hello"><input type="submit" name="btn" value="go"></form>')
let submit = form.querySelector('input[type=submit]')
let formData = htmx.__collectFormData(submit, form, null)
assert.equal(formData.get('txt'), 'hello')
assert.equal(formData.get('btn'), 'go')
})

it('button with no type (defaults to submit) inside form sends its own name/value', function () {
let form = createProcessedHTML('<form><input name="txt" value="hello"><button name="btn" value="implicit"></button></form>')
let btn = form.querySelector('button')
let formData = htmx.__collectFormData(btn, form, null)
assert.equal(formData.get('txt'), 'hello')
assert.equal(formData.get('btn'), 'implicit')
})

it('submit button value is not duplicated', function () {
let form = createProcessedHTML('<form><input name="txt" value="hello"><button type="submit" name="btn" value="B"></button></form>')
let btn = form.querySelector('button')
let formData = htmx.__collectFormData(btn, form, null)
assert.deepEqual(formData.getAll('btn'), ['B'])
})
});
Loading