Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialize FormData #137

Open
fregante opened this issue May 9, 2023 · 6 comments
Open

Deserialize FormData #137

fregante opened this issue May 9, 2023 · 6 comments

Comments

@fregante
Copy link

fregante commented May 9, 2023

There's an excellent module for serializing and deserializing forms: https://www.npmjs.com/package/dom-form-serializer

However this is quite old and we have since gained FormData as a way to serialize forms into a string, which dom-form-serializer doesn't support (it has its own object format)

What's missing is a way to apply the contents of FormData back to a form (rehydrate, if you will).

This form.elements.namedItem() API can help match the field name in FormData to the actual fields, but then the logic to select the right checkbox, radio, select, multi-select isn't straightforward. It'd be great to have a modern, simple way to do this.

@Richienb
Copy link

Richienb commented May 9, 2023

Setting .value seems to work on every element (including checkboxes, radio fields, and selects) except those where there are security concerns. For example, file inputs don't have a .value and trying to use its own API to shim it doesn't work because it seems that the native element doesn't react at all.

Thus:

function hydrateForm(formData, formElement) {
	for (const [name, value] of formData.entries()) {
		const escapedName = CSS.escape(name);
		const input = formElement.querySelector(`[name='${escapedName}']`);

		if (input === null) {
			throw new Error(name === escapedName ? `Form element for ${name} not found` : `Form element for ${name} (escaped: ${escapedName}) not found`);
		}

		input.value = value;
	}
}

@fregante
Copy link
Author

fregante commented May 9, 2023

seems to work

I don’t think so. "Setting the value" of a checkbox means:

  • uncheck every checkbox with the same name
  • for each checkbox value
    • find the checkbox with that value
      • set checkbox.checked = true

If you just set checkbox.value = 'on' you're overriding the value without actually checking it.

@fregante
Copy link
Author

fregante commented May 9, 2023

@Richienb
Copy link

Ok that reveals a slight confict: both of these are saved as the same thing;

<input type="checkbox" name="state" checked>
<input type="checkbox" name="state" value="on" checked>
<input type="checkbox" name="state" value="off">

But that seems pretty minor, though worth documenting if it ever gets published.

What's the use case, btw?

@fregante
Copy link
Author

fregante commented May 10, 2023

No, that’s the standard behavior of FormData. Unchecked fields are not included in the data. So "unchecked === might as well not exist."

The only thing your example shows is that it will need to match the data state=on to to value-less input fields.

FormData doesn’t save the exact HTML, but just the data. This is the main difference with “classic” serializers which would have a hard time picking the right value for those fields (because they usually save true as the value of a checked checkbox)

@fregante
Copy link
Author

What's the use case, btw?

I use the mentioned module in https://github.com/fregante/webext-options-sync

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants