Skip to content

Send nested data in a plain form #186

@douglasward

Description

@douglasward

I would like to understand why forms with nested data require JS in order to work.

I thought one of the ideas of superforms was to make use of the progressive enhancement that sveltekit provides, i.e. allowing forms to work without JS if necessary. And I know that nested data works with forms in general. So why is JS required for superforms to allow nested data?

Activity

ciscoheat

ciscoheat commented on Jun 12, 2023

@ciscoheat
Owner

Nested data doesn't work with forms in general, since html forms only deals with string values in non-nestable input elements. So a serialization is required for nested data (with the exception of arrays of primitive values).

// You can't express this structure in a plain html form.
{
  tags: [ { id: 1, name: 'first' }, { id: 2, name: 'second' }]
}
OllieJT

OllieJT commented on Jun 15, 2023

@OllieJT

...with the exception of arrays of primitive types like string[] or number[] because with those, you can reuse the name attribute.

<input type="text" name="tag" id="tag-01" />
<input type="text" name="tag" id="tag-02" />
<input type="text" name="tag" id="tag-03" />
const formData = await event.request.formData()
formData.get('tag') // gets the first tag in the dom (string)
formData.getAll('tag') // gets all tags in the dom (string[])
ciscoheat

ciscoheat commented on Jun 16, 2023

@ciscoheat
Owner

Yes, this is automatically handled by Superforms, so you don't need to go through FornData: https://superforms.rocks/concepts/nested-data#arrays-with-primitive-values

douglasward

douglasward commented on Jun 17, 2023

@douglasward
Author

Thank you for your answers! Would it be possible to somehow flatten before creating the form and unflatten again after validation in the action handler? Or is this kind of pattern not supported by zod?
For example if you started with your example of

{
  tags: [ { id: 1, name: 'first' }, { id: 2, name: 'second' }]
}

this be flattened to something html forms would support like:

{
  "tags.0.id": 1,
  "tags.0.name": "first",
  "tags.1.id: 2,
  "tags.1.name": "second"
}

I just don't know how one could define a zod schema for this flattened version in order to create the superform, or if it is even possible.

ciscoheat

ciscoheat commented on Jun 17, 2023

@ciscoheat
Owner

It's not a Zod thing, it only matches keys of the object to the schema. So it has to be a different dataType, nested-html for example. And the keys should be compatible with the FormPath type, so they should be in the format tags[0].id.

With that, it's not that hard to implement, but I haven't planned any feature releases yet, so this issue can be used as an enhancement, and I would be happy to see a PR for it!

changed the title [-]Why does nested data require JS? [/-] [+]Send nested data in a plain form[/+] on Jun 17, 2023
douglasward

douglasward commented on Jun 18, 2023

@douglasward
Author

Okay, that sounds promising, thank you. I haven't looked into the codebase yet, but if you say it shouldn't be hard to implement then maybe I will try take a look this week. If you had any pointers off the top of your head to help me get started then that would be most appreciated - otherwise I'll give a shout if anything is unclear once I've taken an initial look.

ciscoheat

ciscoheat commented on Jun 20, 2023

@ciscoheat
Owner

Sure, it's a server-side thing, so in superValidate.ts there is a formDataToValidation function that is the best entry point for this.

I'm not sure though how to detect that it's this nested-html datatype that's been posted, especially since it's plain html (assume no JS), so the only way to communicate things to the server is to add another field or as a query parameter.

denlukia

denlukia commented on Jun 21, 2023

@denlukia

+1 for this issue. Nested fields is a great feature but it needing JS kinda defeats SvelteKit's "Let's make Apps that work without JS, let's use forms instead of fetch because they work without JS". So right now I'm doing it via functions nestify and flatify that convert to and from this dotted notation (although maybe better and more complex notations exist for such cases?) and I have to use them in every superForms in-out kind of "boundary"

ciscoheat

ciscoheat commented on Jun 21, 2023

@ciscoheat
Owner

I find this "no JS"-idea to be wishful thinking in most cases. For just browsing a content site and maybe searching with a one-field form, fine, that should work. But for any kind of complexity, and especially if you're submitting nested data, a website that works without one line of JS (while still supporting the other case with a nice UX) is very ambitious and time-consuming.

ciscoheat

ciscoheat commented on Jun 21, 2023

@ciscoheat
Owner

Btw @douglasward there is a function called splitPath that you may also find useful, when building the nested object from the posted string paths.

ciscoheat

ciscoheat commented on Jun 21, 2023

@ciscoheat
Owner

And finally, there are some "test.ts" files in src, if you can make another one with tests for this feature, that'd be great. :)

ciscoheat

ciscoheat commented on Sep 12, 2023

@ciscoheat
Owner
Stadly

Stadly commented on Dec 20, 2023

@Stadly

This is a great idea!

7 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @ciscoheat@BradNut@Stadly@douglasward@denlukia

      Issue actions

        Send nested data in a plain form · Issue #186 · ciscoheat/sveltekit-superforms