-1

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"
                ]
            ]
        }
    ]
}

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Ok, thanks. That true, my brain was a little tired i guess. But that's not my main issue, i can handle this without dirtying my code. I still guess i'm doing something wrong..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.