Sveltekit 从表单操作更新响应式变量

huangapple go评论70阅读模式
英文:

Sveltekit update reactive variable from form action

问题

export const actions = {
    deleteSmoothie: async ({ request }) => {
        let { smoothie } = Object.fromEntries(await request.formData());
        smoothie = JSON.parse(smoothie);

        try {
            await supabase.from('smoothies').delete().eq('id', smoothie.id);
        } catch (err) {
            console.error(err);
            return fail(500, { message: 'Could not delete smoothie' });
        }
    },
    sortSmoothies: async ({ request }) => {
        console.log('action');
        const formData = Object.fromEntries(await request.formData());

        let orderBy;
        for (const prop in formData) {
            if (formData[prop] === 'true') {
                orderBy = prop;
                break;
            }
        }

        const data = await fetchSmoothies(orderBy);
        console.log(data);

        return {
            smoothies: data ?? []
        };
    }
};
英文:

Hi!

So I'm working on a simple crud application with Sveltekit and Supabase. I'm trying to implement this sorting feature by fetching the table with the added .order() function when the user selects a sorting option. My problem is that I want to update the smoothies variable after the form action takes place with the new sorting option. Right now I'm just returning smoothies like I would in the load function but that doesn't seem to be right. So, how would I go about updating smoothies, and the dom, with the new data from the form action (and not reload the page as it would just get overriden by the default load function).

I am a Sveltekit and Supabase newbie so your help is greatly appreciated!

+page.svelte

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

	export let data;

	$: ({ smoothies } = data);

	const tabs = (e) => {
		e.target.classList.add('tab-active');

		const siblings = e.target.parentNode.children;

		for (let i = 0; i < siblings.length; i++) {
			if (siblings[i] !== e.target) {
				siblings[i].classList.remove('tab-active');
			}
		}
	};

	const handleSubmit = ({ form, data, action, cancel, submitter }) => {
		return async ({ result, update }) => {};
	};
</script>

<div class="flex flex-col items-center mx-auto gap-8">
	<a role="button" href="/create" class="btn btn-success mt-8">Create Smoothie</a>

	<form action="?/sortSmoothies" method="POST" use:enhance={handleSubmit}>
		<div class="tabs tabs-boxed">
			<button
				type="submit"
				name="created_at"
				value="true"
				class="tab tab-active"
				on:click={(e) => tabs(e)}>Created</button
			>
			<button type="submit" name="title" value="true" class="tab" on:click={(e) => tabs(e)}
				>Title</button
			>
			<button type="submit" name="rating" value="true" class="tab" on:click={(e) => tabs(e)}
				>Rating</button
			>
		</div>
	</form>

	<div class="grid 2xl:grid-cols-4 xl:grid-cols-3 lg:grid-cols-2 gap-6 mt-4">
		{#each smoothies as smoothie}
			<div class="card w-96 bg-base-100 shadow-xl">
				<div class="card-body">
					<h2 class="card-title">{smoothie.title}</h2>
					<p>{smoothie.method}</p>
					<div class="rating absolute -right-5 -top-5">
						<div
							class="mask mask-star-2 bg-orange-400 w-12 h-12 flex items-center justify-center font-bold"
						>
							{smoothie.rating}
						</div>
					</div>

					<div class="card-actions justify-end">
						<a role="button" href="/{smoothie.id}" class="btn btn-warning btn-sm">Edit</a>
						<form action="?/deleteSmoothie" method="POST">
							<input type="hidden" name="smoothie" value={JSON.stringify(smoothie)} />
							<button type="submit" class="btn btn-error btn-sm">Remove</button>
						</form>
					</div>
				</div>
			</div>
		{/each}
	</div>
</div>

+page.server.js

import { supabase } from '$lib/supabaseClient';
import { fail } from '@sveltejs/kit';

const fetchSmoothies = async (orderBy) => {
	const { data, error } = await supabase
		.from('smoothies')
		.select()
		.order(orderBy, { ascending: false });

	if (error) {
		throw new Error('Could not fetch smoothies');
	}

	return data ?? [];
};

export const load = async () => {
	console.log('load');
	const data = await fetchSmoothies('created_at');

	return {
		smoothies: data ?? []
	};
};

export const actions = {
	deleteSmoothie: async ({ request }) => {
		let { smoothie } = Object.fromEntries(await request.formData());
		smoothie = JSON.parse(smoothie);

		try {
			await supabase.from('smoothies').delete().eq('id', smoothie.id);
		} catch (err) {
			console.error(err);
			return fail(500, { message: 'Could not delete smoothie' });
		}
	},
	sortSmoothies: async ({ request }) => {
		console.log('action');
		const formData = Object.fromEntries(await request.formData());

		let orderBy;
		for (const prop in formData) {
			if (formData[prop] === 'true') {
				orderBy = prop;
				break;
			}
		}

		const data = await fetchSmoothies(orderBy);
		console.log(data);

		return {
			smoothies: data ?? []
		};
	}
};

答案1

得分: 1

一般情况下,不应该从表单操作中返回页面数据。在使用 enhance 操作时,成功的操作会自动使页面数据失效,导致 load 函数再次运行,从而应该更新您的列表。

尽管在这种情况下,您可能希望将排序变量转换为查询参数,这样 load 函数就可以访问它并以正确的顺序返回列表。您也不需要使用操作,而是使用 goto 来更新 URL,添加新的参数。

简化示例:

function sort(e) {
    const url = new URL($page.url);
    url.searchParams.set('sort', e.currentTarget.value);
    goto(url.href, { replaceState: true });
}
<select on:change={sort}>
    <option value="asc">升序</option>
    <option value="desc">降序</option>
</select>
// +page.server.js
export const load = e => {
    const sort = e.url.searchParams.get('sort');
    // ...
};

当然,您也可以使用多个参数,使用表单的 submit 事件来触发排序等。

英文:

You should generally not return page data from form actions. When using the enhance action, a successful action will automatically invalidate the page data causing load to run again which in turn should update your list.

Though in this case, you might want to turn the sorting variable into a query parameter, that way the load function can access it and return the list in the correct order. You also would not need an action but instead use goto to update the URL with the new parameter.

Simplified example:

function sort(e) {
    const url = new URL($page.url);
    url.searchParams.set(&#39;sort&#39;, e.currentTarget.value);
    goto(url.href, { replaceState: true });
}
&lt;select on:change={sort}&gt;
    &lt;option value=&quot;asc&quot;&gt;Ascending&lt;/option&gt;
    &lt;option value=&quot;desc&quot;&gt;Descending&lt;/option&gt;
&lt;/select&gt;
// +page.server.js
export const load = e =&gt; {
    const sort = e.url.searchParams.get(&#39;sort&#39;);
    // ...
};

Of course you can use multiple parameters, use a form's submit event to trigger the sorting, etc.

huangapple
  • 本文由 发表于 2023年4月7日 03:09:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75952963.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定