Web TippsUse custom web fonts in Google Sheets charts(08.09.2026 um 17:05 Uhr)
Web TippsIntroducing the new 1Password App for Google Chat(08.09.2026 um 18:02 Uhr)
Web TippsUse custom web fonts in Google Sheets charts(08.09.2026 um 17:05 Uhr)
Web TippsIntroducing the new 1Password App for Google Chat(08.09.2026 um 18:02 Uhr)

🔧 Programmierung 🕛 vor 1 Monat 5 Min Lesezeit
0

Sveltekit การทำงานกับ remote function [Part 3]

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

สวัสดีครับเพื่อนๆ! 👋 กลับมาเจอกันอีกแล้วในซีรีส์ SvelteKit Remote function! จากบทความก่อนๆ ที่เราลุยตระกูล query กันไปแบบจัดเต็ม ทั้งดึงข้อมูลธรรมดา มัดรวมรีเควสต์ (batch) และดึงแบบเรียลไทม์ (live) หวังว่าเพื่อนๆ คงจะสนุกกับการ "ดึง" ข้อมูลกันไปแล้วนะครับ 😎



แต่วันนี้... เราจะมาเปลี่ยนโหมดกันบ้าง! เพราะเมื่อมี "ดึง" ก็ต้องมี "ดัน"!! เอยย "ส่ง" ถูกไหมครับ? 😅 ถ้าเราอยากจะส่งข้อมูล เพื่อบันทึก (POST) หรืออัปเดต (PUT) อะไรบางอย่างกลับไปที่ Server ผ่าน FormData ล่ะจะต้องทำยังไง?



ขอต้อนรับทุกคนเข้าสู่โลกของ Remote function ประเภท form 📝 เจ้าตัวนี้เกิดมาเพื่อช่วยเราจัดการกับการส่งข้อมูลโดยเฉพาะ (Mutation) โดยในบทความนี้ เราจะมาค่อยๆ ปูพื้นฐานทำความเข้าใจกันตั้งแต่เรื่องการจัดการช่องรับข้อมูล (Fields) กันก่อนสำหรับบทความนี้ และในบทความถัดๆไปจะเล่าถึงการ Validate ข้อมูลใน form, การนำค่าใน form มาแสดงผล รวมถึงการจัดการกับข้อมูลที่ถูกส่งกลับมาหรือการเปลี่ยนเส้นทางไปยังส่วนอื่นๆของเว็บ (Returns and redirects) กันอีกทีนะครับ



เอาละ!! พร้อมที่จะบอกลาความยุ่งยากของการจัดการฟอร์มแบบเดิมๆ แล้วหรือยังครับ? ถ้าพร้อมแล้ว เตรียมนิ้วให้พร้อมโค้ดแล้วลุยกันเลย! 🚀














src/routes/blog/data.remote.js






CODE
import * as v from 'valibot';
import { error, redirect } from '@sveltejs/kit';
import { form } from '$app/server';
import * as db from '$lib/server/database';
import * as auth from '$lib/server/auth';

export const createPost = form(
// ส่วนของ Validation schema
v.object({
title: "v.pipe(v.string(), v.nonEmpty()),"
content:v.pipe(v.string(), v.nonEmpty())
}),
//Callback function ที่รับค่า data ที่เป็น FormData เข้ามา
async ({ title, content }) => {
// เช็ค auth เรื่องของ User ว่าถูกต้องไหม
const user = await auth.getUser();
if (!user) error(401, 'Unauthorized');

const slug = title.toLowerCase().replace(/ /g, '-');

// ทำการ Insert เข้าไปยัง Database
await db.sql`
INSERT INTO post (slug, title, content)
VALUES (
${slug}, ${title}, ${content})
`
;

// ทำการ Redirect ผู้ใช้ไปยังหน้า blog ใหม่ที่ถูกสร้าง
redirect(303, `/blog/${slug}`);
}
);






และในทางกลับกันเจ้าฟังก์ชัน form ก็จะคืนค่า object ที่เราสามารถนำไป spread ใส่เข้าไปยัง <form> element ในส่วนของ client ได้ด้วย ซึ่งเจ้าตัว Callback function ด้านบนนั้นจะทำงานก็ต่อเมื่อเกิด event ประเภท form submit เท่านั้น






src/routes/blog/new/+page.svelte






CODE
<script>
import { createPost } from '../data.remote';
</script>

<h1>Create a new post</h1>
<!-- vvvvvvvvvvv สามารถนำ `form` มา spread ได้เลย -->
<form {...createPost}>
<!-- คอนเท้นต์ของ form ก็ใส่เข้ามาตรงส่วนนี้ -->

<button>Publish!</button>
</form>






ซึ่งใช่แล้วครับ เจ้าตัวฟังก์ชัน form ที่ถูกส่งกลับมานั้นมันเป็น object ที่จะมี properties ของ method รวมถึง action อยู่ด้วยซึ่งนั้นสามารถทำให้การส่งข้อมูลฟอร์ม ของเราจะทำงานได้แม้ว่าเราจะไม่มีสามารถเข้าถึง JavaScript ได้นั้นเอง ที่มากไปกว่านั้นมันยังมี ให้เป็น argument ตัวแรกของเจ้าฟังก์ชัน form









📊Fields



โดยตัวฟอร์มของเราเนี่ย จะประกอบไปด้วยช่องกรอกข้อมูล (fields) หลายๆ ช่องรวมกัน ซึ่งหน้าตาและประเภทของช่องพวกนี้จะถูกกำหนดโดยตัว schema ที่เราตั้งไว้นั่นเองครับ 📝



อย่างในกรณีของฟังก์ชัน createPost เราก็จะมีอยู่ 2 ฟิลด์หลักๆ คือ title (หัวข้อ) และ content (เนื้อหา) ซึ่งข้อมูลทั้งสองตัวนี้ก็จะเป็นประเภทข้อความ (strings) ทั้งคู่เลย ✍️



ทีนี้ เวลาที่เราอยากจะดึงพวก attributes ต่างๆ ของแต่ละฟิลด์ออกมาแปะใช้งาน เราก็แค่เรียกใช้ method ที่ชื่อว่า .as(...) แล้วระบุประเภทของช่อง input ที่เราอยากจะใช้งานลงไปได้เลย 🛠️



และสำหรับช่อง input ส่วนใหญ่นั้น เรายังสามารถแอบส่งค่าที่ 2 (second argument) พ่วงเข้าไปเพิ่มได้ด้วยนะ หน้าตาจะเป็นแบบนี้เลย 👉 .as(type, value) ซึ่งเจ้านี่จะเอาไว้ใช้สำหรับควบคุมค่า (value) ที่จะถูกแสดงผลออกมาบนหน้าเว็บนั่นเองครับ: ✨






src/routes/blog/new/+page.svelte






CODE
<form {...createPost}>
<label>
<h2>Title</h2>
<input {...createPost.fields.title.as('text')} />
</label>

<label>
<h2>Write your post</h2>
<textarea {...createPost.fields.content.as('text')}></textarea>
</label>

<button>Publish!</button>
</form>






ซึ่งเจ้าพวก attribute เหล่านี้แหละที่จะเป็นตัวช่วยให้ SvelteKit รู้ว่าต้องตั้งค่าช่อง input เป็นประเภทไหน กำหนดชื่อ (name) สำหรับแพ็คข้อมูลส่งไปให้ handler จัดการต่อ และที่เจ๋งสุดคือมันช่วยเติมค่า (value) กลับลงไปในฟอร์มให้แบบอัตโนมัติด้วย! (อย่างเช่น เวลาผู้ใช้กด submit แล้วเกิด error กรอกข้อมูลไม่ผ่าน เขาจะได้ไม่ต้องมานั่งพิมพ์ใหม่ทั้งหมดให้เมื่อยมือยังไงล่ะ 😌) แถมยังช่วยเซ็ตสถานะ aria-invalid เพื่อบอกระบบได้ด้วยนะว่าช่องนี้ข้อมูลพังหรือกรอกผิด 🚨



และในส่วนการที่เราส่งค่าที่ 2 พ่วงเข้าไปใน .as(...) เนี่ย จะมีประโยชน์สุดๆ เวลาที่เราต้องเรนเดอร์ฟอร์มโดยดึงข้อมูลที่มีอยู่แล้วมาแสดงครับ อย่างเช่นตอนทำ "ฟอร์มแก้ไขข้อมูล" (edit form) หรือเวลาที่เราต้องเสกฟอร์มหน้าตาเหมือนกันออกมาหลายๆ อันผ่านลูป for(...) 🔄



ซึ่งนอกจากมันจะช่วยตั้งค่าเริ่มต้นตอนที่ฟอร์มถูกเรนเดอร์ขึ้นมาครั้งแรกแล้ว เจ้านี่ยังเป็นตัวคุมค่าของช่อง input นั้นๆ เวลาที่ฟอร์มถูกสั่ง reset (ล้างค่า) กลับไปเป็นค่าตั้งต้นอีกด้วยนะ 🧹



📝 จุดที่ต้องโน้ตไว้เพิ่มเติมคือ:

สำหรับ input ประเภท radio, submit และ hidden จะบังคับว่า ต้องใส่ ค่าที่ 2 นี้เสมอนะครับ

ส่วน checkbox จะต้องใส่ก็ต่อเมื่อมันทำหน้าที่เป็นหนึ่งในตัวเลือกของฟิลด์ข้อมูลแบบ array

และข้อควรระวังสุดท้ายคือ... เรา ไม่สามารถ ใช้วิธีนี้เติมค่าให้กับ input ประเภท file (อัปโหลดไฟล์) ได้นะครับ 📁❌




ตัว attribute name ที่ระบบสร้างขึ้นมาให้ จะใช้รูปแบบการเขียนอ้างอิงแบบ JS object เลยครับ (หน้าตาก็ประมาณนี้ nested.array[0].value)



แต่มีข้อควรระวังนิดนึงคือ ตอนนี้มัน ยังไม่รองรับ พวก key ที่เป็น string แบบที่ต้องใช้เครื่องหมายคำพูด (quotes) ครอบนะครับ อย่างเช่น object['nested-array'][0].value แบบนี้จะยังเอามาใช้ไม่ได้เด้อ 🚫



และถ้าเราแอบไปแงะดูการทำงานหลังบ้าน (Under the hood) ⚙️ สำหรับช่อง input ประเภทติ๊กถูก (boolean checkbox) และช่องตัวเลข (number) ตัวแอตทริบิวต์ชื่อ (name) ของมันจะถูกแอบเติมคำนำหน้าด้วย b: และ n: ตามลำดับครับ



ถามว่าทำไปทำไม? ก็เพื่อเป็นการส่งซิก 🤫 กระซิบบอก SvelteKit ให้รู้ว่า "เฮ้ย! ช่วยแปลงค่าพวกนี้จาก string ให้กลับมาเป็น boolean หรือ number ตามที่มันควรจะเป็นให้หน่อยนะ" ก่อนที่ข้อมูลจะถูกส่งข้ามไปสู่ขั้นตอนการตรวจสอบ (validation) อีกทีนั่นเองครับ ระบบเขาคิดมาเผื่อแล้ว ✨




ซึ่งไอ้เจ้า Fields ทั้งหลายที่เราทำเนี่ยมันสามารถถูกซ้อนเข้าไปอยู่ใน object (nested object) หรือ array (nested array) ได้ ซึ่งค่า (value) ของมันก็สามารถเป็นได้ทั้งข้อความ (string) ตัวเลข (number) ค่า True/False (boolean) หรือจะเป็น object ของไฟล์ (File objects) ได้เช่นกัน เช่นตัวอย่างถ้าเรามีข้อมูล schema ดังนี้





data.remote.js





CODE
const datingProfile = v.object({
name: v.string(),
photo: v.file(),
info: v.object({
height: v.number(),
likesDogs: v.optional(v.boolean(), false)
}),
attributes: v.array(v.string())
});

export const createProfile = form(datingProfile, (data) => { /* ... */ });





พวกเราก็จะมีฟอร์มที่หน้าตาประมาณนี้





src/routes/profile/new/+page.svelte





CODE
<script>
import { createProfile } from './data.remote';

const { name, photo, info, attributes } = createProfile.fields;
</script>

<form {...createProfile} enctype="multipart/form-data">
<label>
<input {...name.as('text')} /> Name
</label>

<label>
<input {...photo.as('file')} /> Photo
</label>

<label>
<input {...info.height.as('number')} /> Height (cm)
</label>

<label>
<input {...info.likesDogs.as('checkbox')} /> I like dogs
</label>

<h2>My best attributes</h2>
<input {...attributes[0].as('text')} />
<input {...attributes[1].as('text')} />
<input {...attributes[2].as('text')} />

<button>submit</button>
</form>





และเนื่องจากฟอร์มของเราในรอบนี้ดันมีช่องให้อัปโหลดไฟล์ (file input) รวมอยู่ด้วย เราเลยต้องไม่ลืมแปะ attribute enctype="multipart/form-data" เข้าไปที่ตัวฟอร์มด้วยนะครับ ส่วนพวกค่าข้อมูลอย่าง info.height และ info.likesDogs ระบบก็จะจัดการแปลงร่าง (coerce) ให้กลับไปเป็นตัวเลข (number) และค่าความจริง (boolean) ให้เองตามลำดับเลย สบายใจได้! ✨




💡 แวะโน้ตไว้นิดนึงเรื่อง Checkbox:

ธรรมชาติของช่อง checkbox เนี่ย ถ้าผู้ใช้ไม่ได้ติ๊กเลือกไว้ ❌ ข้อมูลของมันจะ ไม่ถูกรวม ส่งไปกับก้อน FormData ที่ SvelteKit เอามาใช้ประกอบร่างข้อมูลนะครับ

เพราะฉะนั้น ในตอนที่เราตั้งตัว schema เราเลยต้องทำเผื่อไว้ โดยตั้งให้ค่านี้เป็นแบบ "มีหรือไม่มีก็ได้" (optional) ด้วยนะ

ถ้าใครใช้ Valibot ก็ให้เขียนแบบนี้: v.optional(v.boolean(), false) แทนที่จะใช้แค่ v.boolean() เพียวๆ

ส่วนถ้าใครเป็นสาย Zod ก็จะเขียนหน้าตาประมาณนี้ครับ: z.coerce.boolean<boolean>()




และในกรณีที่พวกเราใช้งานช่อง input แบบกลุ่มอย่าง radio และ checkbox (ที่เป็นตัวเลือกหลายๆ อันภายใต้ฟิลด์หัวข้อเดียวกัน) กฎเหล็กก็คือ การบังคับต้องระบุค่า (value) เข้าไปเป็น argument ตัวที่สองในคำสั่ง .as(...) เสมอ แบบนี้เลย 👇





constants.js





CODE
export const operatingSystems = /** @type {const} */ (['windows', 'mac', 'linux']);
export const languages = /** @type {const} */ (['html', 'css', 'js']);







data.remote.js





CODE
import { operatingSystems, languages } from './constants';

export const survey = form(
v.object({
operatingSystem: v.picklist(operatingSystems),
languages: v.optional(v.array(v.picklist(languages)), []),
}),
(data) => { /* ... */ },
);







src/routes/coding/+page.svelte





CODE
<form {...survey}>
<h2>Which operating system do you use?</h2>

{#each operatingSystems as os}
<label>
<input {...survey.fields.operatingSystem.as('radio', os)}>
{os}
</label>
{/each}

<h2>Which languages do you write code in?</h2>

{#each languages as language}
<label>
<input {...survey.fields.languages.as('checkbox', language)}>
{language}
</label>
{/each}

<button>submit</button>
</form>





หรือจะเขียนอีกแบบโดยใช้ select หรือ select multiple ก็ได้นะ โค้ดหน้า +page.svelte ก็จะกลายเป็น




CODE
<form {...survey}>
<h2>Which operating system do you use?</h2>

<select {...survey.fields.operatingSystem.as('select')}>
{#each operatingSystems as os}
<option>{os}</option>
{/each}
</select>

<h2>Which languages do you write code in?</h2>

<select {...survey.fields.languages.as('select multiple')}>
{#each languages as language}
<option>{language}</option>
{/each}
</select>

<button>submit</button>
</form>







และก็เหมือนกับกรณีของช่อง checkbox ที่ไม่ได้ถูกติ๊กนั่นแหละครับ... ถ้าผู้ใช้ไม่ได้เลือกตัวเลือกอะไรมาเลย ข้อมูลที่วิ่งส่งมาก็จะหายวับและมีค่ากลายเป็น undefined ไปโดยปริยาย 👻



ด้วยเหตุผลนี้เอง สำหรับฟิลด์อย่าง languages (ที่อาจจะให้เลือกได้หลายภาษา) เราเลยต้องเขียนตัว schema เผื่อทางหนีทีไล่ไว้โดยใช้คำสั่ง v.optional(v.array(...), []) (เพื่อให้มันแอบเซ็ตค่าเริ่มต้นเป็น array ว่างๆ [] ให้ถ้าไม่มีคนเลือก) แทนที่จะไปบังคับโหดๆ ว่าต้องมี array ส่งมาเสมอด้วยคำสั่ง v.array(...) เพียวๆ ครับ 🛡️✨







เป็นยังไงกันบ้างครับเพื่อนๆ กับการใช้งาน form แบบฉบับ SvelteKit Remote function 🤩 ในส่วนของการจัดการฟิลด์ข้อมูลต่างๆ มันดูคลีนและสมูทขึ้นกว่าเดิม ไหมครับ? หรือมันเพิ่มความลำบากกว่าเดิมนะเนี่ย 😵‍💫😵‍💫



แต่เดี๋ยวก่อน... มหากาพย์เรื่องฟอร์มของเรายังไม่จบลงง่ายๆ แค่นี้ครับ! เพราะสิ่งที่เราทำกันไปวันนี้เป็นเพียงแค่จุดเริ่มต้นเท่านั้น



ถ้าใครกำลังมีคำถามในหัวว่า "แล้วถ้าอยากให้ฟอร์มมีการ Validate แบบ ทั้งฝั่ง Client ด้วยจะทำยังไงละ ?? แล้วจะเอาข้อมูลในฟอร์มมาแสดงได้ยังไง ??" 🤯



เก็บคำถามนั้นไว้ครับ! เพราะในบทความถัดไป เราจะมาจัดกันต่อในหัวข้อของการ Validate 🔍 รวมถึงการ Get/Set ข้อมูลจาก form และสุดท้ายก็จะเป็นเรื่องการนำค่าที่ถูกส่งกลับ (Return Data) มาใช้งานได้อย่างไรด้วย ↩️



รับรองว่าบทความหน้าจะช่วยปลดล็อกสกิลให้เพื่อนๆ จัดการฟอร์มบน SvelteKit ได้อยู่หมัดในทุกสถานการณ์แน่นอน! เตรียมตัวรอติดตามกันได้เลยครับ แล้วเจอกันใหม่นะเพื่อนๆ 😉✨

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
Use custom web fonts in Google Sheets charts
2 Quellen
Introducing the new 1Password App for Google Chat
1 Quelle
Context-aware access controls are available for Gemini Enterprise in the Admin console
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Sveltekit การทำงานกับ remote function [Part 3]

Thematisch verwandte Begriffe: Sveltekit, การทำงานกบ, remote, function · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...