Skip to content

Fields ​

หน้านี้สอนอะไร

field ทุกประเภท ตัวเลือก หน้าตาในหน้า admin และวิธีจัดเก็บ

ควรอ่านก่อน: การตั้งค่า

ทุก field มี name และ type ตัวเลือกที่ใช้ร่วมกัน:

ตัวเลือก
labelstring หรือ { en, th } ค่าเริ่มต้นคือชื่อ field ที่แปลงให้อ่านง่าย
requiredต้องมีค่า (ข้ามการตรวจสอบขณะบันทึก ฉบับร่าง (draft))
defaultValueใช้เมื่อสร้างเอกสารโดยไม่มี field นี้
uniqueเอกสารสองรายการใช้ค่าซ้ำกันไม่ได้ (field ระดับบนสุด)
indexสร้าง index ในฐานข้อมูล
validate(value, { data, operation }) => true | 'error message' เป็น async ได้
access{ read, update } สิทธิ์ระดับ field
hiddenถูกจัดเก็บ แต่ API จะไม่ส่งคืนและไม่รับเป็น input
localizedเก็บค่าแยกตามภาษา ดู หลายภาษา
position'sidebar': แสดงในแถบข้างของหน้าแก้ไข (สำหรับ field ระดับบนสุด เช่น หมวดหมู่ แท็ก หรือวันที่)
admin{ component, after }: admin components แทนช่องกรอก และต่อท้าย field

ประเภท ​

ประเภทค่าตัวเลือก
textstringminLength, maxLength
textareastringminLength, maxLength
emailstring จัดเก็บเป็นตัวพิมพ์เล็ก
numbernumbermin, max
booleanboolean
datestring แบบ ISO 8601 (รับ Date ได้)
selectหนึ่งในตัวเลือก หรือ array เมื่อใช้ hasManyoptions, hasMany
slugstring ที่ปลอดภัยสำหรับ URL และไม่ซ้ำภายใน collectionfrom
jsonค่า JSON ใดก็ได้
richTextเอกสาร JSON ของ Tiptapดู Rich text
uploadid ของเอกสาร mediaดู การอัปโหลด
relationshipid ของเอกสารใน collection อื่นto, hasMany
arrayรายการของแถว แต่ละแถวมี id และ field ย่อยfields, minRows, maxRows
groupobject ซ้อนfields
blocksรายการของแถวที่มีหลายชนิด แต่ละแถวมี id และ blockTypeblocks, minRows, maxRows

select ​

ts
{ name: 'kind', type: 'select', options: ['news', { label: { en: 'Blog', th: 'บล็อก' }, value: 'blog' }] }
{ name: 'tags', type: 'select', options: ['vue', 'react'], hasMany: true }

slug ​

ts
{ name: 'slug', type: 'slug', from: 'title' }

เติมค่าจาก title เมื่อว่าง ตัวอักษรของทุกภาษาจะถูกเก็บไว้ (สวัสดี ชาวโลก → สวัสดี-ชาวโลก) ค่าที่ซ้ำจะได้ -2, -3 การเปลี่ยน title ภายหลังจะไม่เปลี่ยน slug

uniqueWithin: 'parent' ทำให้ slug ห้ามซ้ำเฉพาะเอกสารที่มีค่าของอีก field เหมือนกัน เช่น หน้าที่อยู่ใต้หน้าแม่เดียวกัน (แบบที่ plugin หน้าย่อย ใช้)

relationship ​

ts
{ name: 'author', type: 'relationship', to: 'users' }
{ name: 'related', type: 'relationship', to: 'posts', hasMany: true }

id จะถูกตรวจสอบว่ามีอยู่จริงเมื่อบันทึก การอ่านจะดึงเอกสารที่เกี่ยวข้องมาแทนที่ตามจำนวนระดับ depth (ค่าเริ่มต้น 1 สูงสุด 3) ที่ depth 0 จะได้เพียง id เอกสารที่ถูกลบหรืออ่านไม่ได้จะกลายเป็น null หรือ ถูกตัดออกจากรายการ hasMany

filterOptions จำกัดว่า relationship ชี้ไปเอกสารใดได้บ้าง ทำงานฝั่ง server โดยได้รับ id ของเอกสาร (undefined ตอนสร้าง) และผู้ใช้ แล้วคืน where ของ collection ปลายทาง หรือ true ถ้าเลือกได้ทุกเอกสาร ช่องเลือกใน admin แสดงเฉพาะเอกสารเหล่านั้น และตรวจซ้ำตอนบันทึก

ts
{
  name: 'manager',
  type: 'relationship',
  to: 'users',
  filterOptions: ({ id }) => ({ role: { equals: 'admin' } }),
}

array และ group ​

ts
{
  name: 'links',
  type: 'array',
  maxRows: 5,
  fields: [
    { name: 'label', type: 'text', required: true },
    { name: 'url', type: 'text' },
  ],
}
{ name: 'seo', type: 'group', fields: [{ name: 'title', type: 'text' }] }

การอัปเดต array จะแทนที่แถวทั้งหมด หากต้องการคงตัวตนของแถวไว้ ให้คง id ของแถวนั้นไว้

blocks ​

แถวที่มีหลายชนิด สำหรับหน้าที่ผู้แก้ไขเนื้อหาจัดวางเอง:

ts
{
  name: 'layout',
  type: 'blocks',
  blocks: [
    {
      slug: 'hero',
      labels: { singular: 'Hero' },
      fields: [
        { name: 'heading', type: 'text', required: true },
        { name: 'image', type: 'upload' },
      ],
    },
    { slug: 'text', fields: [{ name: 'body', type: 'richText' }] },
  ],
}

แต่ละแถวคือ { id, blockType, ...fields } โดย blockType ใช้เลือก block แถวจะถูกตรวจสอบความถูกต้อง relationship และ upload ภายในแถวจะถูก populate และ type ที่สร้างขึ้นจะเป็น union ของ block แต่ละชนิด

blocks จัดเก็บเป็น JSON และ where ค้นข้างในได้: ชื่อ field หมายถึง field นั้นในบล็อกชนิดใดก็ตามที่มี และเอกสารจะตรงเงื่อนไขเมื่อมีบล็อกใดบล็อกหนึ่งตรง

ts
await cms.find('pages', { where: { 'layout.blockType': { equals: 'hero' } } })
await cms.find('pages', { where: { 'layout.heading': { like: 'sale' } } })
await cms.find('pages', { where: { 'layout.heading.en': { equals: 'Hello' } } }) // ระบุภาษา
await cms.find('pages', { where: { layout: { exists: false } } }) // ไม่มีบล็อกเลย

list ที่อยู่ในบล็อกก็ค้นได้แบบเดียวกัน โดยต้องมีบางแถวตรงเงื่อนไข

ts
await cms.find('pages', { where: { 'layout.meta.tone': { equals: 'warm' } } }) // group
await cms.find('pages', { where: { 'layout.items.title': { equals: 'One' } } }) // array
await cms.find('pages', { where: { 'layout.tags': { in: ['sale'] } } }) // ค่า hasMany
await cms.find('pages', { where: { 'layout.content.blockType': { equals: 'quote' } } }) // blocks

sort ใช้ค่าแรกที่พบ โดยไล่ตามลำดับบล็อก (และแถวของ list ข้างในบล็อก): sort: '-layout.columns', sort: 'layout.items.title' การค้นแบบนี้ต้องอ่าน JSON ของทุกเอกสาร จึงเหมาะกับการกรองมากกว่ารายการใหญ่ที่ถูกเรียกบ่อย

วิธีจัดเก็บ field ​

แต่ละ collection คือตารางหนึ่งตาราง field คือคอลัมน์ (field ใน group จะถูกแผ่ออกเป็นระดับเดียว: seo.title → seo_title) ค่าของ array และ hasMany อยู่ในตารางลูก ส่วน blocks เป็นคอลัมน์ JSON field สองรายการที่จะแมปไปยังคอลัมน์ เดียวกันจะถูกรายงานเป็นข้อผิดพลาดของ config

ขั้นต่อไป ​

เผยแพร่ภายใต้สัญญาอนุญาต MIT