0

so on this page I have 2 drop-down and when submit button is clicked it is fetching data from a pocketbase backend. I am making a table component for each raw of data. (Component displays a id, link, a dropdown to change it's status and a submit button that uses form action again to update that particular row of data in the collection). I am using enhance (also tried using prevent default) but still the page is still refreshing. 1 thing to point out is I am using a variable named linkType in main script tag that stores value for what a user have selected from dropdown. It is shared among all components

Any idea how can I prevent it?

<script>
    import { enhance } from '$app/forms';

    export let data;
    let selectedUser = '';
    let selectedCourse = '';
    function handleUserChange(event) {
        selectedUser = event.target.value;
        selectedCourse = '';
    }
    function handleCourseChange(event) {
        selectedCourse = event.target.value;
    }
    async function showSelection() {
        console.log('Selected User:', selectedUser);
        console.log('Selected Course:', selectedCourse);
    }

    export let form;
    let linkType = '';
    let linkResult = '';

    let linkTypes = ['Type1', 'Type'];
    let linkResults = ['Result1', 'Result2'];

    function handleLinkTypeChange(event) {
        linkType = event.target.value;
    }

    function handleLinkResultChange(event) {
        linkResult = event.target.value;
    }
</script>

<div>
    <h1 class="text-white-700 text-center text-4xl font-bold">Select Client Data</h1>

    {#if data}
        <form
            action="?/userSelection"
            method="POST"
            use:enhance
            class="flex flex-col items-center space-y-4 p-10"
        >
            <select
                name="user"
                class="select select-accent w-full max-w-xs"
                value={selectedUser}
                on:change={handleUserChange}
            >
                <option disabled selected>Select a User</option>
                {#each data.userData as user}
                    <option value={user.user}>{user.user}</option>
                {/each}
            </select>
            {#if selectedUser !== ''}
                <select
                    name="course"
                    class="select select-accent w-full max-w-xs"
                    value={selectedCourse}
                    on:change={handleCourseChange}
                >
                    <option disabled selected>Select a Course</option>
                    {#each data.userData.find((user) => user.user === selectedUser)?.courses || [] as course}
                        <option value={course}>{course}</option>
                    {/each}
                </select>
            {/if}
            <button type="submit" on:click={showSelection} class="btn btn-primary">Get Data</button>
        </form>
    {:else}
        <p>Loading...</p>
    {/if}

    {#if form && form.response}
        {#each form.response as row}
            <div class="overflow-x-auto">
                <table class="min-w-full divide-y divide-gray-200">
                    <thead class="bg-gray-50">
                        <tr>
                            <th
                                scope="col"
                                class="w-1/5 px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
                                >ID</th
                            >
                            <th
                                scope="col"
                                class="w-1/5 px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
                                >Link</th
                            >
                            <th
                                scope="col"
                                class="w-2/5 px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
                                >Link Type</th
                            >
                            <th
                                scope="col"
                                class="w-2/5 px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
                                >Link Result</th
                            >
                            <th
                                scope="col"
                                class="w-2/5 px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
                                >Update</th
                            >
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-gray-200 bg-white">
                        <tr class="border-b border-gray-200 hover:bg-gray-100">
                            <td class="whitespace-nowrap px-6 py-4">{row.id}</td>
                            <td
                                class="whitespace-nowrap px-6 py-4"
                                style="max-width: 300px; overflow-x: auto; width: 100%;"
                                ><a href={row.url} class="truncate">{row.url}</a></td
                            >
                            <td class="whitespace-nowrap px-6 py-4">
                                <select
                                    class="block rounded-md border border-gray-300 bg-white px-3 py-2 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
                                >
                                    {#each linkTypes as type}
                                        <option value={type}>{type}</option>
                                    {/each}
                                </select>
                            </td>
                            <td class="whitespace-nowrap px-6 py-4">
                                <select
                                    class="block rounded-md border border-gray-300 bg-white px-3 py-2 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
                                >
                                    {#each linkResults as result}
                                        <option value={result}>{result}</option>
                                    {/each}
                                </select>
                            </td>
                            <td class="whitespace-nowrap px-6 py-4 text-right">
                                <form
                                    action="?/update"
                                    method="POST"
                                    use:enhance
                                    on:submit={(event) => event.preventDefault()}
                                >
                                    <input type="hidden" hidden value={row.id} name="id" />
                                    <input type="hidden" hidden value={linkType} name="linkType" />
                                    <input type="hidden" hidden value={linkResult} name="linkResult" />
                                    <button
                                        type="submit"
                                        class="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-700"
                                        >Update</button
                                    >
                                </form>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        {/each}
    {:else}
        <div><p>Select User First</p></div>
    {/if}
</div>


Also this is my +page.server.js file that has action -->

export async function load({ locals }) {
    try {
        const users = await locals.pb.collection('UserData').getFullList();
        const userCoursesMap = new Map();
        users.forEach(entry => {
            const userId = entry.user[0];
            const courseName = entry.courseName;
            if (userCoursesMap.has(userId)) {
                userCoursesMap.get(userId).push(courseName);
            } else {
                userCoursesMap.set(userId, [courseName]);
            }
        });
        const userData = Array.from(userCoursesMap).map(([userId, courses]) => ({
            user: userId,
            courses: courses
        }));
        return { userData };
    } catch (error) {
        console.error('Error fetching user data:', error);
        throw error;
    }
}
export const actions = {
    userSelection: async ({ request, locals }) => {
        const formData = await request.formData();
        // const user = Object.fromEntries(formData);
        const user = formData.get("user"); // add course name as well. ""
        try {
            const response = await locals.pb.collection("Orbittest").getFullList({
                filter: `user = "${user}"`, fields: "id, user, url, linkType, linkResult"
            });
            const jsonResponse = JSON.stringify(response);
            console.log("Fetched data:", jsonResponse);
            return { response };
        } catch (error) {
            console.error("Error fetching data:", error);
            return { error };
        }

    },

    update: async ({ request }) => {
        const formData = await request.formData();
        const id = formData.get("id")
        const linkType = formData.get("linkType")
        const linkResult = formData.get("linkResult")
        console.log(id, linkType, linkResult)
        return { status: 200, id }
    }

};

I am getting id, and type for the link I just updated but after that entire page refreshing.

CC BY-SA 4.0

2 Answers 2

1

You can give enhance an argument that is a submit function and if that function returns another function (which is called with the server response), you can override the default behavior. See the docs.

<form
    method="POST"
    use:enhance={({ formElement, formData, action, cancel, submitter }) => {
        // `formElement` is this `<form>` element
        // `formData` is its `FormData` object that's about to be submitted
        // `action` is the URL to which the form is posted
        // calling `cancel()` will prevent the submission
        // `submitter` is the `HTMLElement` that caused the form to be submitted

        return async ({ result, update }) => {
            // `result` is an `ActionResult` object
            // `update` is a function which triggers the default logic
            // that would be triggered if this callback wasn't set
        };
    }}
>
CC BY-SA 4.0
3
  • Sorry if my question seems stupid but how do I exactly implement this. I sent about 2 hours reading the docs and searched for any other resources but codun't figure out how can I use this here is a screen record of what is happening - drive.google.com/file/d/1NHdd92MhKoa19lvCaV8u0mvURe0Ml6J0/… I would really appreciate some guidance here
    – What
    Commented Mar 21 at 16:23
  • I've also updates the code in the post with the actual code I am using. In contains 2 dropdown to get data from a pocketbase collection.
    – What
    Commented Mar 21 at 16:31
  • 1
    By default the use:enhance will load the returned data into the form property. If you don't return the full state of what you need, this will "reset" the page. So you either have to return everything from the update action or you have to prevent it from doing this by customizing the enhance action. Currently you just have use:enhance which follows the default behavior.
    – brunnerh
    Commented Mar 21 at 16:48
0

I don't think the page should reload (full page navigation) on a form submit.

Seems like use:enhance is not working, and would love to see a reproduction.


Suggestions are:

  1. Use URLs to determine what data to display.
  2. Wrap the table with a single <form>. You can set a value in the button.
<script lang="ts">
  import { enhance } from '$app/forms';
  import { goto } from '$app/navigation';

  export let data;
  export let form;

  let linkType: string;
</script>


<select name="" on:change={()=>(goto('desired_url'))}>
  <option value=""></option>
</select>
  

<form action="?/update" method="post" use:enhance>
  <input type="hidden" name="link_type" value={linkType}>
  <table>
    <tbody>
      {#each { length: 3 } as _}
        <tr>
          <button value="{row.id}"></button>
        </tr>
      {/each}
    </tbody>
  </table>
</form>
CC BY-SA 4.0
2

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.