Skip to content

Commit

Permalink
feat(form-data): allow passing a form to FormData (#84)
Browse files Browse the repository at this point in the history
* feat(form-data): allow passing a form to FormData

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* chore: update return

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* test: add test

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* Create real-news-divide.md

* chore: use setAttribute

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* chore: add jsdom

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* fix: setup entries before going through form

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* test: setup jsdom in caller file

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* chore: left over debug

* chore: remove jsdom, pass fake form object

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* test: update fake form

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* chore: use isHTMLFormElement function

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* chore: use real HTMLFormElement in the browser

Signed-off-by: Logan McAnsh <logan@mcan.sh>

* chore: fix changeset

---------

Signed-off-by: Logan McAnsh <logan@mcan.sh>
Co-authored-by: Logan McAnsh <logan@mcan.sh>
  • Loading branch information
MichaelDeBoey and mcansh authored Aug 28, 2023
1 parent 3c20536 commit fd274bd
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/real-news-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web-std/form-data": minor
---

allow passing a `form` to `FormData`. implementation taken from https://github.com/tchak/remix-router-turbo/blob/main/test/setup-test-env.ts, thank you @tchak
48 changes: 36 additions & 12 deletions packages/form-data/src/form-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@ export class FormData {
* @param {HTMLFormElement} [form]
*/
constructor(form) {
if (form !== undefined) {
const error = isHTMLFormElement(form)
? new TypeError(
"FormData constructor: HTMLFormElement parameter is not supported, if you need it submit an issue"
)
: new TypeError(
"FormData constructor: Argument 1 does not implement interface HTMLFormElement."
)

throw error
}

/**
* @private
* @readonly
Expand All @@ -26,6 +14,24 @@ export class FormData {
this._entries = []

Object.defineProperty(this, "_entries", { enumerable: false })

if (isHTMLFormElement(form)) {
for (const element of form.elements) {
if (isSelectElement(element)) {
for (const option of element.options) {
if (option.selected) {
this.append(element.name, option.value);
}
}
} else if (
isInputElement(element) &&
(element.checked || !["radio", "checkbox"].includes(element.type)) &&
element.name
) {
this.append(element.name, element.value);
}
}
}
}
get [Symbol.toStringTag]() {
return "FormData"
Expand Down Expand Up @@ -312,3 +318,21 @@ const BlobFile = class File {
const panic = error => {
throw error
}

/**
*
* @param {Element} element
* @returns {element is HTMLSelectElement}
*/
function isSelectElement(element) {
return element.tagName === "SELECT";
}

/**
*
* @param {Element} element
* @returns {element is HTMLInputElement}
*/
function isInputElement(element) {
return element.tagName === "INPUT" || element.tagName === "TEXTAREA";
}
72 changes: 71 additions & 1 deletion packages/form-data/test/form-data.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { assert } from "./test.js"
* @param {import('./test').Test} test
*/
export const test = test => {
test("test baisc", async () => {
test("test basic", async () => {
assert.equal(typeof FormData, "function")
assert.isEqual(typeof lib.FormData, "function")
})
Expand Down Expand Up @@ -248,4 +248,74 @@ export const test = test => {
"rename.md"
)
})

test("Should allow passing a form element", () => {
/** @type {globalThis.HTMLFormElement} */
let form;

if (typeof window === 'undefined') {
/** @implements {globalThis.HTMLFormElement} */
class FakeForm {
get [Symbol.toStringTag]() {
return "HTMLFormElement";
}

toString() {
return `<form></form>`;
}

// @ts-ignore
get elements() {
return [
{
tagName: "INPUT",
name: "inside",
value: "",
},
{
tagName: "INPUT",
name: "outside",
value: "",
form: "my-form",
},
{
tagName: "INPUT",
name: "remember-me",
value: "on",
checked: true,
}
]
}

get id() {
return "my-form"
}
}

form = /** @type {globalThis.HTMLFormElement} */ (/** @type {unknown} */ (new FakeForm()))
} else {
form = document.createElement('form');
let inside = document.createElement('input')
let outside = document.createElement('input')
let checkbox = document.createElement('input')

form.id = 'my-form'
inside.name = 'inside'
outside.name = 'outside'
outside.setAttribute('form', 'my-form')
checkbox.name = "remember-me"
checkbox.type = 'checkbox'
checkbox.checked = true;

form.appendChild(inside);
form.appendChild(checkbox);
document.body.appendChild(form);
document.body.appendChild(outside);
}

const formData = new FormData(form);
assert.equal(formData.has("inside"), true)
assert.equal(formData.has("outside"), true)
assert.equal(formData.get("remember-me"), "on")
})
}

0 comments on commit fd274bd

Please sign in to comment.