最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

SvelteSuperForm - Checkbox value instead of boolean - Stack Overflow

programmeradmin1浏览0评论

I try to use checkboxs with SuperForm (and formFieldProxy).

And i have some problems:

  • i don't understand why i have no way (or don't find the one) to retrieve checkbox value instead of the checked boolean (native html checkbox send input value, the value is just conditioned by the checked state)
  • when i try to use bind:group i retrieve checkboxs values but all are stored as array

My reservation Zod schema

const ReservationObject = z.object({
    id: z.string().uuid(),
    reservation_id: z.string(),
    denomination: z.string(),
    price: z.coerce.number(),
    options: z.array(
        z.object({
            id: z.string().uuid(),
            optionDenomination: z.string(),
            price: z.coerce.number()
        })
    ),
    total: z.number().optional(),
    isBooked: z.boolean()
});

const ReservationsObject = z.object({
    reservation_id: z.string(),
    isSuspended: z.boolean(),
    booking: z.array(ReservationObject)
});

The schema used for form values

export const BuyingReservation = z.object({
    buying: z.array(
        z.object({
            buyReservation: z.string().uuid(),
            buyReservationOption: z.array(z.string().uuid())
        })
    )
});

SuperForm object

const defaultBuyingEntry = [{ buyReservation: '', buyReservationOption: [] }];
const buying: BuyingReservation = { buying: defaultBuyingEntry };
const superform = superForm(buying, {
    dataType: 'json',
    resetForm: false,
    invalidateAll: false
});
const { form, submitting, enhance } = superform;

The form

<form method="POST" use:enhance action="/" class={styles['form']}>
    {#each booking.booking as item, index}
        <div class={styles['booking__row']}>
            <p class={styles['booking__row-denomination']}>
                {item.denomination} : <span>{item.price}€</span>
                <Input
                    {superform}
                    id={`${index}-buyReservation`}
                    field="buying[{index}].buyReservation"
                    type="checkbox"
                    label={'Réserver'}
                    value={item.id}
                    grouped={true}
                />
            </p>
            <div class={styles['booking__row-options']}>
                {#each item.options as option, optionIndex}
                    <div class={styles['booking__row-option']}>
                        <p class={styles['booking__row-options-denomination']}>
                            {option.optionDenomination} : <span>{option.price}€</span>
                        </p>
                        <Input
                            {superform}
                            id={`${index}-${optionIndex}-buyReservationOption`}
                            field="buying[{index}].buyReservationOption[{optionIndex}]"
                            type="checkbox"
                            label={'Ajouter'}
                            value={option.id}
                            grouped={true}
                        />
                    </div>
                {/each}
            </div>
        </div>
    {/each}
    <input
        type="submit"
        class={styles['form__field-static']}
        value="Reserver et payer"
        disabled={$submitting}
    />
</form>

My reusable input

let { label, className, field, superform, grouped, ...others }: Props = $props();
const { value, errors, constraints } =
    !!field && !!superform ? formFieldProxy(superform, field) : {};

<input
    {...others}
    name={field}
    data-invalid={$errors}
    aria-invalid={$errors ? 'true' : undefined}
    class={[styles['input'], className].join(' ')}
    {...$constraints}
    type="checkbox"
    bind:group={$value} // or bind:checked={$value}
/>

The results: if bind:checked

{
    "buying": [
        {
            "buyReservation": true,
            "buyReservationOption": [
                true,
                false
            ]
        },
    ]
}

if bind:group

{
    "buying": [
        {
            "buyReservation": [
                "61ee077d-9db9-4286-bd57-25d5ab0fe27e"
            ],
            "buyReservationOption": [
                [
                    "6b2fe441-96eb-46fe-aa2b-fe78319d27fc"
                ],
                [
                    "0fa3b2ab-e2bc-4407-8827-7de6a8f7fb06"
                ]
            ]
        }
    ]
}

I try to use checkboxs with SuperForm (and formFieldProxy).

And i have some problems:

  • i don't understand why i have no way (or don't find the one) to retrieve checkbox value instead of the checked boolean (native html checkbox send input value, the value is just conditioned by the checked state)
  • when i try to use bind:group i retrieve checkboxs values but all are stored as array

My reservation Zod schema

const ReservationObject = z.object({
    id: z.string().uuid(),
    reservation_id: z.string(),
    denomination: z.string(),
    price: z.coerce.number(),
    options: z.array(
        z.object({
            id: z.string().uuid(),
            optionDenomination: z.string(),
            price: z.coerce.number()
        })
    ),
    total: z.number().optional(),
    isBooked: z.boolean()
});

const ReservationsObject = z.object({
    reservation_id: z.string(),
    isSuspended: z.boolean(),
    booking: z.array(ReservationObject)
});

The schema used for form values

export const BuyingReservation = z.object({
    buying: z.array(
        z.object({
            buyReservation: z.string().uuid(),
            buyReservationOption: z.array(z.string().uuid())
        })
    )
});

SuperForm object

const defaultBuyingEntry = [{ buyReservation: '', buyReservationOption: [] }];
const buying: BuyingReservation = { buying: defaultBuyingEntry };
const superform = superForm(buying, {
    dataType: 'json',
    resetForm: false,
    invalidateAll: false
});
const { form, submitting, enhance } = superform;

The form

<form method="POST" use:enhance action="/" class={styles['form']}>
    {#each booking.booking as item, index}
        <div class={styles['booking__row']}>
            <p class={styles['booking__row-denomination']}>
                {item.denomination} : <span>{item.price}€</span>
                <Input
                    {superform}
                    id={`${index}-buyReservation`}
                    field="buying[{index}].buyReservation"
                    type="checkbox"
                    label={'Réserver'}
                    value={item.id}
                    grouped={true}
                />
            </p>
            <div class={styles['booking__row-options']}>
                {#each item.options as option, optionIndex}
                    <div class={styles['booking__row-option']}>
                        <p class={styles['booking__row-options-denomination']}>
                            {option.optionDenomination} : <span>{option.price}€</span>
                        </p>
                        <Input
                            {superform}
                            id={`${index}-${optionIndex}-buyReservationOption`}
                            field="buying[{index}].buyReservationOption[{optionIndex}]"
                            type="checkbox"
                            label={'Ajouter'}
                            value={option.id}
                            grouped={true}
                        />
                    </div>
                {/each}
            </div>
        </div>
    {/each}
    <input
        type="submit"
        class={styles['form__field-static']}
        value="Reserver et payer"
        disabled={$submitting}
    />
</form>

My reusable input

let { label, className, field, superform, grouped, ...others }: Props = $props();
const { value, errors, constraints } =
    !!field && !!superform ? formFieldProxy(superform, field) : {};

<input
    {...others}
    name={field}
    data-invalid={$errors}
    aria-invalid={$errors ? 'true' : undefined}
    class={[styles['input'], className].join(' ')}
    {...$constraints}
    type="checkbox"
    bind:group={$value} // or bind:checked={$value}
/>

The results: if bind:checked

{
    "buying": [
        {
            "buyReservation": true,
            "buyReservationOption": [
                true,
                false
            ]
        },
    ]
}

if bind:group

{
    "buying": [
        {
            "buyReservation": [
                "61ee077d-9db9-4286-bd57-25d5ab0fe27e"
            ],
            "buyReservationOption": [
                [
                    "6b2fe441-96eb-46fe-aa2b-fe78319d27fc"
                ],
                [
                    "0fa3b2ab-e2bc-4407-8827-7de6a8f7fb06"
                ]
            ]
        }
    ]
}
Share Improve this question asked Mar 2 at 22:49 GeioGeio 9719 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

i don't understand why i have no way (or don't find the one) to retrieve checkbox value instead of the checked boolean (native html checkbox send input value, the value is just conditioned by the checked state)

The browser does that when submitting a form:

value The value attribute is one which all <input>s share; however, it serves a special purpose for inputs of type checkbox: when a form is submitted, only checkboxes which are currently checked are submitted to the server, and the reported value is the value of the value attribute. If the value is not otherwise specified, it is the string on by default

However when you're on the client side, no form submission happens, and the value attribute is just an attribute, that's present regardless of the checked state, see the "Clicky" button:

function doThing() {
  for (const cb of document.querySelectorAll("input[type=checkbox]"))
    console.log(cb.value, cb.checked);
}

function doFilter() {
  console.log(JSON.stringify(
    [...document.querySelectorAll("input[type=checkbox]")]
    .filter(cb => cb.checked)
    .map(cb => cb.value)));
}
<input type="checkbox" value="hello">hello <input type="checkbox" value="world" checked>world<br>
<button onclick="doThing()">Clicky</button><br><button onclick="doFilter()">Filter</button>

While there's a chance that svelte supports what you want, with vanilla JS you have to combine the two attributes yourself, as the "Filter" button shows.

发布评论

评论列表(0)

  1. 暂无评论