英文:
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('sort', e.currentTarget.value);
goto(url.href, { replaceState: true });
}
<select on:change={sort}>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
// +page.server.js
export const load = e => {
const sort = e.url.searchParams.get('sort');
// ...
};
Of course you can use multiple parameters, use a form's submit
event to trigger the sorting, etc.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论