Kotchasan Framework Documentation

Kotchasan Framework Documentation

การสร้างฟอร์มและ HTML

TH 05 Feb 2026 06:23

การสร้างฟอร์มและ HTML

Kotchasan Framework มีชุดคลาสที่ครอบคลุมสำหรับการสร้างฟอร์มและการจัดการ HTML ตั้งแต่การสร้างฟิลด์อินพุตพื้นฐาน การจัดการตาราง จนถึงการสร้างเลย์เอาต์ที่ซับซ้อน

สารบัญ

  1. Form Class - การสร้างฟิลด์ฟอร์ม
  2. Html Class - การจัดการ HTML Elements
  3. HtmlTable Class - การสร้างตาราง
  4. Grid Class - การจัดการเลย์เอาต์กริด
  5. การใช้งานในระบบจริง
  6. Best Practices

Form Class - การสร้างฟิลด์ฟอร์ม

Input Fields พื้นฐาน

use Kotchasan\Form;

// Text input
$textInput = Form::text([
    'id' => 'username',
    'name' => 'username',
    'class' => 'g-input',
    'placeholder' => 'กรุณากรอกชื่อผู้ใช้',
    'maxlength' => 50,
    'required' => true
]);

// Password input
$passwordInput = Form::password([
    'id' => 'password',
    'name' => 'password',
    'class' => 'g-input',
    'placeholder' => 'กรุณากรอกรหัสผ่าน',
    'required' => true
]);

// Email input with validation
$emailInput = Form::email([
    'id' => 'email',
    'name' => 'email',
    'class' => 'g-input',
    'placeholder' => 'name@example.com',
    'required' => true,
    'title' => 'กรุณากรอกอีเมลที่ถูกต้อง'
]);

// Number input
$ageInput = Form::number([
    'id' => 'age',
    'name' => 'age',
    'class' => 'g-input',
    'min' => 1,
    'max' => 120,
    'placeholder' => 'อายุ'
]);

Select และ Options

// Simple select
$countrySelect = Form::select([
    'id' => 'country',
    'name' => 'country',
    'class' => 'g-select',
    'options' => [
        'TH' => 'ประเทศไทย',
        'US' => 'สหรัฐอเมริกา',
        'JP' => 'ญี่ปุ่น',
        'UK' => 'สหราชอาณาจักร'
    ],
    'value' => 'TH' // ค่าเริ่มต้น
]);

// Select with grouped options
$productSelect = Form::select([
    'id' => 'product',
    'name' => 'product',
    'class' => 'g-select',
    'options' => [
        'Electronics' => [
            'laptop' => 'โน๊ตบุ๊ก',
            'smartphone' => 'สมาร์ทโฟน',
            'tablet' => 'แท็บเล็ต'
        ],
        'Clothing' => [
            'shirt' => 'เสื้อเชิ้ต',
            'pants' => 'กางเกง',
            'shoes' => 'รองเท้า'
        ]
    ],
    'required' => true
]);

// Multi-select
$skillsSelect = Form::select([
    'id' => 'skills',
    'name' => 'skills[]',
    'class' => 'g-select',
    'multiple' => true,
    'size' => 5,
    'options' => [
        'php' => 'PHP',
        'javascript' => 'JavaScript',
        'python' => 'Python',
        'java' => 'Java',
        'css' => 'CSS/HTML'
    ]
]);

Checkbox และ Radio

// Single checkbox
$agreeCheckbox = Form::checkbox([
    'id' => 'agree',
    'name' => 'agree',
    'value' => '1',
    'checked' => false
]);

// Radio group
$genderOptions = [
    'M' => 'ชาย',
    'F' => 'หญิง',
    'O' => 'อื่นๆ'
];

foreach ($genderOptions as $value => $label) {
    $genderRadio = Form::radio([
        'id' => 'gender_' . $value,
        'name' => 'gender',
        'value' => $value,
        'checked' => ($value === 'M') // เซ็ตค่าเริ่มต้น
    ]);
}

// Checkbox group
$hobbies = [
    'reading' => 'อ่านหนังสือ',
    'music' => 'ฟังเพลง',
    'sports' => 'กีฬา',
    'travel' => 'ท่องเที่ยว',
    'cooking' => 'ทำอาหาร'
];

foreach ($hobbies as $value => $label) {
    $hobbyCheckbox = Form::checkbox([
        'id' => 'hobby_' . $value,
        'name' => 'hobbies[]',
        'value' => $value
    ]);
}

ฟิลด์พิเศษ

// File upload
$avatarUpload = Form::file([
    'id' => 'avatar',
    'name' => 'avatar',
    'accept' => 'image/*',
    'class' => 'g-file'
]);

// Multiple file upload
$documentsUpload = Form::file([
    'id' => 'documents',
    'name' => 'documents[]',
    'multiple' => true,
    'accept' => '.pdf,.doc,.docx,.txt'
]);

// Date input
$birthdateInput = Form::date([
    'id' => 'birthdate',
    'name' => 'birthdate',
    'class' => 'g-input',
    'max' => date('Y-m-d'), // ไม่เกินวันปัจจุบัน
    'required' => true
]);

// DateTime-local input
$appointmentInput = Form::datetime([
    'id' => 'appointment',
    'name' => 'appointment',
    'class' => 'g-input',
    'min' => date('Y-m-d\TH:i'), // ไม่น้อยกว่าปัจจุบัน
    'step' => 1800 // ทุก 30 นาที
]);

// Color picker
$colorInput = Form::color([
    'id' => 'theme_color',
    'name' => 'theme_color',
    'value' => '#3498db'
]);

// Range slider
$volumeRange = Form::range([
    'id' => 'volume',
    'name' => 'volume',
    'min' => 0,
    'max' => 100,
    'value' => 50,
    'step' => 1
]);
*/

Currency และ Number Format

// Currency input (Thai Baht)
$priceInput = Form::currency([
    'id' => 'price',
    'name' => 'price',
    'class' => 'g-input',
    'placeholder' => '0.00',
    'min' => 0,
    'step' => 0.01,
    'currency' => 'THB'
]);

// Integer input
$quantityInput = Form::integer([
    'id' => 'quantity',
    'name' => 'quantity',
    'class' => 'g-input',
    'min' => 1,
    'max' => 999,
    'value' => 1
]);

Buttons

// Submit button
$submitButton = Form::submit([
    'id' => 'submit_btn',
    'class' => 'button save large',
    'value' => 'บันทึกข้อมูล'
]);

// Reset button
$resetButton = Form::reset([
    'id' => 'reset_btn',
    'class' => 'button cancel',
    'value' => 'ล้างข้อมูล'
]);

// Custom button
$customButton = Form::button([
    'id' => 'custom_btn',
    'class' => 'button action',
    'value' => 'ดำเนินการ',
    'onclick' => 'handleCustomAction()'
]);

Html Class - การจัดการ HTML Elements

การสร้างฟอร์มที่สมบูรณ์

use Kotchasan\Html;

// สร้างฟอร์มหลัก
$form = Html::create('form', [
    'id' => 'user_form',
    'class' => 'setup_frm',
    'method' => 'post',
    'action' => 'index.php/demo/save',
    'autocomplete' => 'off',
    'ajax' => true,
    'token' => true
]);

// เพิ่ม fieldset
$personalInfo = $form->add('fieldset', [
    'title' => 'ข้อมูลส่วนตัว',
    'titleClass' => 'icon-user'
]);

// เพิ่มกลุ่มฟิลด์
$nameGroup = $personalInfo->add('groups');

// ชื่อจริง
$nameGroup->add('label', [
    'for' => 'first_name',
    'innerHTML' => 'ชื่อจริง <span class="required"></span>'
]);
$nameGroup->add('input', [
    'type' => 'text',
    'id' => 'first_name',
    'name' => 'first_name',
    'class' => 'g-input',
    'maxlength' => 50,
    'required' => true
]);

// นามสกุล
$nameGroup->add('label', [
    'for' => 'last_name',
    'innerHTML' => 'นามสกุล <span class="required"></span>'
]);
$nameGroup->add('input', [
    'type' => 'text',
    'id' => 'last_name',
    'name' => 'last_name',
    'class' => 'g-input',
    'maxlength' => 50,
    'required' => true
]);

Input Groups และ Row Groups

// Input groups สำหรับการจัดกลุ่มฟิลด์
$contactGroup = $personalInfo->add('inputgroups');

// อีเมล
$emailRow = $contactGroup->add('groups');
$emailRow->add('label', [
    'for' => 'email',
    'innerHTML' => 'อีเมล <span class="required">*</span>'
]);
$emailRow->add('input', [
    'type' => 'email',
    'id' => 'email',
    'name' => 'email',
    'class' => 'g-input',
    'required' => true,
    'pattern' => '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$'
]);

// เบอร์โทรศัพท์
$phoneRow = $contactGroup->add('groups');
$phoneRow->add('label', [
    'for' => 'phone',
    'innerHTML' => 'เบอร์โทรศัพท์'
]);
$phoneRow->add('input', [
    'type' => 'tel',
    'id' => 'phone',
    'name' => 'phone',
    'class' => 'g-input',
    'pattern' => '[0-9]{9,10}'
]);

Radio Groups และ Checkbox Groups

// Radio groups
$genderGroup = $personalInfo->add('radiogroups', [
    'label' => 'เพศ <span class="required">*</span>',
    'labelClass' => 'g-input',
    'name' => 'gender',
    'options' => [
        'M' => 'ชาย',
        'F' => 'หญิง',
        'O' => 'ไม่ระบุ'
    ],
    'value' => 'M' // ค่าเริ่มต้น
]);

// Checkbox groups
$skillsGroup = $personalInfo->add('checkboxgroups', [
    'label' => 'ทักษะ',
    'labelClass' => 'g-input',
    'name' => 'skills[]',
    'options' => [
        'php' => 'PHP',
        'javascript' => 'JavaScript',
        'mysql' => 'MySQL',
        'css' => 'CSS/HTML',
        'python' => 'Python'
    ],
    'value' => ['php', 'mysql'] // ค่าเริ่มต้นที่เลือก
]);
// Menu button พร้อม dropdown
$actionMenu = $form->add('menubutton', [
    'class' => 'button action',
    'text' => 'เลือกการดำเนินการ',
    'options' => [
        [
            'text' => 'บันทึกและส่ง',
            'onclick' => 'submitForm("send")'
        ],
        [
            'text' => 'บันทึกร่าง',
            'onclick' => 'submitForm("draft")'
        ],
        '-', // separator
        [
            'text' => 'ส่งออก PDF',
            'onclick' => 'exportPDF()'
        ],
        [
            'text' => 'ส่งออก Excel',
            'onclick' => 'exportExcel()'
        ]
    ]
]);

การใช้ CKEditor

// Rich text editor
$descriptionEditor = $form->add('ckeditor', [
    'id' => 'description',
    'name' => 'description',
    'height' => 300,
    'language' => 'th',
    'toolbar' => [
        ['Bold', 'Italic', 'Underline'],
        ['NumberedList', 'BulletedList'],
        ['Link', 'Unlink'],
        ['Image', 'Table'],
        ['Source']
    ],
    'value' => '<p>เนื้อหาเริ่มต้น</p>'
]);

การจัดการ JavaScript

// เพิ่ม JavaScript ลงในฟอร์ม
$form->script('
    // Validation เบื้องต้น
    document.getElementById("user_form").addEventListener("submit", function(e) {
        var firstName = document.getElementById("first_name").value;
        var lastName = document.getElementById("last_name").value;

        if (!firstName.trim() || !lastName.trim()) {
            alert("กรุณากรอกชื่อและนามสกุล");
            e.preventDefault();
            return false;
        }

        // ตรวจสอบรูปแบบอีเมล
        var email = document.getElementById("email").value;
        var emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
        if (email && !emailPattern.test(email)) {
            alert("รูปแบบอีเมลไม่ถูกต้อง");
            e.preventDefault();
            return false;
        }

        return true;
    });
');

HtmlTable Class - การสร้างตาราง

การสร้างตารางพื้นฐาน

use Kotchasan\HtmlTable;

// สร้างตารางใหม่
$table = new HtmlTable([
    'id' => 'users_table',
    'class' => 'data fullwidth',
    'border' => 0
]);

// เพิ่ม caption
$table->addCaption('รายชื่อผู้ใช้งานในระบบ');

// เพิ่ม header
$table->addHeader([
    'รหัส',
    'ชื่อ-นามสกุล',
    'อีเมล',
    'สถานะ',
    'วันที่สมัคร',
    'การจัดการ'
]);

// เพิ่มข้อมูลแถว
$users = [
    [
        'id' => 1,
        'name' => 'สมชาย ใจดี',
        'email' => 'somchai@example.com',
        'status' => 'active',
        'created' => '2024-01-15',
        'actions' => ['edit', 'delete']
    ],
    [
        'id' => 2,
        'name' => 'สมหญิง รักเรียน',
        'email' => 'somying@example.com',
        'status' => 'inactive',
        'created' => '2024-01-20',
        'actions' => ['edit', 'delete']
    ]
];

foreach ($users as $user) {
    // สร้างปุ่มการจัดการ
    $actions = [];
    if (in_array('edit', $user['actions'])) {
        $actions[] = '<a href="edit.php?id=' . $user['id'] . '" class="icon-edit" title="แก้ไข"></a>';
    }
    if (in_array('delete', $user['actions'])) {
        $actions[] = '<a href="javascript:void(0)" onclick="confirmDelete(' . $user['id'] . ')" class="icon-delete" title="ลบ"></a>';
    }

    // สถานะแบดจ์
    $statusBadge = $user['status'] === 'active'
        ? '<span class="badge green">ใช้งาน</span>'
        : '<span class="badge red">ไม่ใช้งาน</span>';

    $table->addRow([
        $user['id'],
        $user['name'],
        $user['email'],
        $statusBadge,
        date('d/m/Y', strtotime($user['created'])),
        implode(' ', $actions)
    ]);
}

// เพิ่ม footer (ถ้าต้องการ)
$footerRow = \Kotchasan\TableRow::create();
$footerRow->addCell('รวม ' . count($users) . ' รายการ', [
    'colspan' => 6,
    'class' => 'center'
]);
$table->addFooter($footerRow);

การสร้างตารางข้อมูลแบบซับซ้อน

// ตารางรายงานยอดขาย
$salesTable = new HtmlTable([
    'id' => 'sales_report',
    'class' => 'data responsive fullwidth'
]);

$salesTable->addCaption('รายงานยอดขายรายเดือน');

// Header แบบ multi-level
$salesTable->addHeader([
    ['text' => 'เดือน', 'rowspan' => 2],
    ['text' => 'ยอดขาย', 'colspan' => 3],
    ['text' => 'เปรียบเทียบ', 'rowspan' => 2]
]);

$salesTable->addHeader([
    'เป้าหมาย',
    'ยอดจริง',
    'ร้อยละ'
]);

// ข้อมูลยอดขาย
$salesData = [
    ['มกราคม', 100000, 95000, 95.0, '+5%'],
    ['กุมภาพันธ์', 120000, 135000, 112.5, '+12%'],
    ['มีนาคม', 110000, 108000, 98.2, '-2%']
];

foreach ($salesData as $data) {
    $row = [];
    $row[] = $data[0]; // เดือน
    $row[] = number_format($data[1]); // เป้าหมาย
    $row[] = number_format($data[2]); // ยอดจริง

    // ร้อยละ พร้อมสีตามผลงาน
    $percentage = $data[3];
    $percentageClass = $percentage >= 100 ? 'text-success' : 'text-warning';
    $row[] = '<span class="' . $percentageClass . '">' . $percentage . '%</span>';

    // การเปรียบเทียบ
    $comparison = $data[4];
    $comparisonClass = str_starts_with($comparison, '+') ? 'text-success' : 'text-danger';
    $row[] = '<span class="' . $comparisonClass . '">' . $comparison . '</span>';

    $salesTable->addRow($row);
}

// เพิ่มแถวสรุป
$totalRow = \Kotchasan\TableRow::create(['class' => 'summary']);
$totalRow->addCell('รวม', ['class' => 'bold']);
$totalRow->addCell(number_format(330000), ['class' => 'bold']);
$totalRow->addCell(number_format(338000), ['class' => 'bold']);
$totalRow->addCell('<span class="text-success bold">102.4%</span>');
$totalRow->addCell('<span class="text-success bold">+2.4%</span>');
$salesTable->addFooter($totalRow);

Grid Class - การจัดการเลย์เอาต์กริด

การใช้งาน Grid System

use Kotchasan\Grid;

// สร้าง grid container
$grid = new Grid();
$grid->setCols(12); // ระบบ 12 คอลัมน์

// เพิ่มเนื้อหาลงใน grid
$content = '
<div class="ggrid">
    <div class="block4 tablet6 mobile12">
        <div class="card">
            <h3>สถิติผู้ใช้งาน</h3>
            <div class="stat-number">1,234</div>
            <div class="stat-text">ผู้ใช้งานทั้งหมด</div>
        </div>
    </div>

    <div class="block4 tablet6 mobile12">
        <div class="card">
            <h3>ยอดขายวันนี้</h3>
            <div class="stat-number">฿45,680</div>
            <div class="stat-text">เพิ่มขึ้น 12%</div>
        </div>
    </div>

    <div class="block4 tablet12 mobile12">
        <div class="card">
            <h3>คำสั่งซื้อใหม่</h3>
            <div class="stat-number">28</div>
            <div class="stat-text">รอการยืนยัน</div>
        </div>
    </div>
</div>';

// Responsive grid layout
$responsiveLayout = '
<div class="ggrid">
    <!-- Main content -->
    <div class="block8 tablet12 mobile12">
        <div class="content-area">
            <h2>เนื้อหาหลัก</h2>
            <p>เนื้อหาของหน้าเว็บไซต์...</p>
        </div>
    </div>

    <!-- Sidebar -->
    <div class="block4 tablet12 mobile12">
        <div class="sidebar">
            <h3>เมนูด้านข้าง</h3>
            <ul>
                <li><a href="#section1">หัวข้อ 1</a></li>
                <li><a href="#section2">หัวข้อ 2</a></li>
                <li><a href="#section3">หัวข้อ 3</a></li>
            </ul>
        </div>
    </div>
</div>';

การใช้งานในระบบจริง

ฟอร์มสมัครสมาชิก

use Kotchasan\Html;
use Kotchasan\Form;

class RegistrationForm
{
    public static function create()
    {
        // สร้างฟอร์มหลัก
        $form = Html::create('form', [
            'id' => 'registration_form',
            'class' => 'setup_frm',
            'method' => 'post',
            'action' => 'index.php/register/save',
            'autocomplete' => 'off',
            'ajax' => true,
            'token' => true
        ]);

        // ข้อมูลส่วนตัว
        $personalSection = $form->add('fieldset', [
            'title' => 'ข้อมูลส่วนตัว',
            'titleClass' => 'icon-user'
        ]);

        // ชื่อ-นามสกุล
        $nameGroup = $personalSection->add('groups');
        $nameGroup->add('label', [
            'for' => 'first_name',
            'innerHTML' => 'ชื่อจริง <span class="required"></span>'
        ]);
        $nameGroup->add('input', [
            'type' => 'text',
            'id' => 'first_name',
            'name' => 'first_name',
            'class' => 'g-input',
            'maxlength' => 50,
            'required' => true,
            'autofocus' => true
        ]);

        $nameGroup->add('label', [
            'for' => 'last_name',
            'innerHTML' => 'นามสกุล <span class="required"></span>'
        ]);
        $nameGroup->add('input', [
            'type' => 'text',
            'id' => 'last_name',
            'name' => 'last_name',
            'class' => 'g-input',
            'maxlength' => 50,
            'required' => true
        ]);

        // อีเมลและรหัสผ่าน
        $credentialGroup = $personalSection->add('groups');
        $credentialGroup->add('label', [
            'for' => 'email',
            'innerHTML' => 'อีเมล <span class="required"></span>'
        ]);
        $credentialGroup->add('input', [
            'type' => 'email',
            'id' => 'email',
            'name' => 'email',
            'class' => 'g-input',
            'required' => true
        ]);

        $credentialGroup->add('label', [
            'for' => 'password',
            'innerHTML' => 'รหัสผ่าน <span class="required"></span>'
        ]);
        $credentialGroup->add('input', [
            'type' => 'password',
            'id' => 'password',
            'name' => 'password',
            'class' => 'g-input',
            'minlength' => 8,
            'required' => true
        ]);

        // เพศ
        $genderGroup = $personalSection->add('radiogroups', [
            'label' => 'เพศ <span class="required"></span>',
            'labelClass' => 'g-input',
            'name' => 'gender',
            'options' => [
                'M' => 'ชาย',
                'F' => 'หญิง',
                'O' => 'ไม่ระบุ'
            ]
        ]);

        // วันเกิด
        $birthdateGroup = $personalSection->add('groups');
        $birthdateGroup->add('label', [
            'for' => 'birthdate',
            'innerHTML' => 'วันเกิด'
        ]);
        $birthdateGroup->add('input', [
            'type' => 'date',
            'id' => 'birthdate',
            'name' => 'birthdate',
            'class' => 'g-input',
            'max' => date('Y-m-d')
        ]);

        // ข้อมูลติดต่อ
        $contactSection = $form->add('fieldset', [
            'title' => 'ข้อมูลติดต่อ',
            'titleClass' => 'icon-phone'
        ]);

        // โทรศัพท์
        $phoneGroup = $contactSection->add('groups');
        $phoneGroup->add('label', [
            'for' => 'phone',
            'innerHTML' => 'เบอร์โทรศัพท์'
        ]);
        $phoneGroup->add('input', [
            'type' => 'tel',
            'id' => 'phone',
            'name' => 'phone',
            'class' => 'g-input',
            'pattern' => '[0-9]{9,10}',
            'placeholder' => '0812345678'
        ]);

        // ที่อยู่
        $addressGroup = $contactSection->add('groups');
        $addressGroup->add('label', [
            'for' => 'address',
            'innerHTML' => 'ที่อยู่'
        ]);
        $addressGroup->add('textarea', [
            'id' => 'address',
            'name' => 'address',
            'class' => 'g-input',
            'rows' => 3,
            'placeholder' => 'ที่อยู่ปัจจุบัน'
        ]);

        // จังหวัด
        $provinceGroup = $contactSection->add('groups');
        $provinceGroup->add('label', [
            'for' => 'province',
            'innerHTML' => 'จังหวัด'
        ]);
        $provinceGroup->add('select', [
            'id' => 'province',
            'name' => 'province',
            'class' => 'g-select',
            'options' => self::getProvinceOptions()
        ]);

        // เงื่อนไขการใช้งาน
        $termsSection = $form->add('fieldset', [
            'title' => 'เงื่อนไขการใช้งาน',
            'titleClass' => 'icon-verfied'
        ]);

        $termsGroup = $termsSection->add('groups');
        $termsGroup->add('label', [
            'for' => 'accept_terms',
            'innerHTML' => 'ยอมรับ <a href="terms.php" target="_blank">เงื่อนไขการใช้งาน</a> <span class="required"></span>'
        ]);
        $termsGroup->add('input', [
            'type' => 'checkbox',
            'id' => 'accept_terms',
            'name' => 'accept_terms',
            'value' => '1',
            'required' => true
        ]);

        $newsletterGroup = $termsSection->add('groups');
        $newsletterGroup->add('label', [
            'for' => 'newsletter',
            'innerHTML' => 'รับข่าวสารทางอีเมล'
        ]);
        $newsletterGroup->add('input', [
            'type' => 'checkbox',
            'id' => 'newsletter',
            'name' => 'newsletter',
            'value' => '1',
            'checked' => true
        ]);

        // ปุ่มส่งข้อมูล
        $submitGroup = $form->add('groups', ['class' => 'submit']);
        $submitGroup->add('input', [
            'type' => 'submit',
            'class' => 'button save large',
            'value' => 'สมัครสมาชิก'
        ]);
        $submitGroup->add('input', [
            'type' => 'reset',
            'class' => 'button cancel',
            'value' => 'ล้างข้อมูล'
        ]);

        // เพิ่ม JavaScript validation
        $form->script('
            // Real-time validation
            document.getElementById("email").addEventListener("blur", function() {
                checkEmailAvailability(this.value);
            });

            document.getElementById("password").addEventListener("input", function() {
                checkPasswordStrength(this.value);
            });

            // ฟังก์ชันตรวจสอบอีเมลซ้ำ
            function checkEmailAvailability(email) {
                if (email.length > 0) {
                    // Ajax request to check email
                    fetch("index.php/register/checkEmail", {
                        method: "POST",
                        headers: {"Content-Type": "application/json"},
                        body: JSON.stringify({email: email})
                    })
                    .then(response => response.json())
                    .then(data => {
                        const emailField = document.getElementById("email");
                        if (data.available) {
                            emailField.setCustomValidity("");
                        } else {
                            emailField.setCustomValidity("อีเมลนี้ถูกใช้งานแล้ว");
                        }
                    });
                }
            }

            // ฟังก์ชันตรวจสอบความแข็งแกร่งของรหัสผ่าน
            function checkPasswordStrength(password) {
                const strengthMeter = document.getElementById("password_strength");
                let strength = 0;
                let message = "";

                if (password.length >= 8) strength++;
                if (/[a-z]/.test(password)) strength++;
                if (/[A-Z]/.test(password)) strength++;
                if (/[0-9]/.test(password)) strength++;
                if (/[^A-Za-z0-9]/.test(password)) strength++;

                switch(strength) {
                    case 0:
                    case 1:
                        message = "อ่อน";
                        break;
                    case 2:
                    case 3:
                        message = "ปานกลาง";
                        break;
                    case 4:
                    case 5:
                        message = "แข็งแกร่ง";
                        break;
                }

                if (strengthMeter) {
                    strengthMeter.innerHTML = message;
                    strengthMeter.className = "password-strength " + message.toLowerCase();
                }
            }
        ');

        return $form->render();
    }

    private static function getProvinceOptions()
    {
        // ตัวอย่างรายชื่อจังหวัด
        return [
            '' => 'เลือกจังหวัด',
            'กรุงเทพมหานคร' => 'กรุงเทพมหานคร',
            'เชียงใหม่' => 'เชียงใหม่',
            'เชียงราย' => 'เชียงราย',
            'ขอนแก่น' => 'ขอนแก่น',
            'นครราชสีมา' => 'นครราชสีมา',
            'ภูเก็ต' => 'ภูเก็ต',
            'สุราษฎร์ธานี' => 'สุราษฎร์ธานี'
        ];
    }
}

ตารางจัดการข้อมูลผู้ใช้

use Kotchasan\HtmlTable;
use Kotchasan\Html;

class UserManagementTable
{
$perPage = 2; // 0)
    {
        // Container
        $container = Html::create('div', ['class' => 'content_bg']);

        // Header พร้อมปุ่มเพิ่ม
        $header = $container->add('div', ['class' => 'table-header']);
        $header->add('h2', ['innerHTML' => 'จัดการผู้ใช้งาน']);

        $actions = $header->add('div', ['class' => 'table-actions']);
        $actions->add('a', [
            'href' => 'index.php/users/add',
            'class' => 'button add',
            'innerHTML' => '<span class="icon-plus"></span> เพิ่มผู้ใช้ใหม่'
        ]);

        // ฟอร์มค้นหา
        $searchForm = $container->add('form', [
            'id' => 'search_form',
            'class' => 'table-search',
            'method' => 'get'
        ]);

        $searchGroup = $searchForm->add('div', ['class' => 'inputgroup']);
        $searchGroup->add('input', [
            'type' => 'text',
            'name' => 'search',
            'class' => 'g-input',
            'placeholder' => 'ค้นหาชื่อ หรือ อีเมล...',
            'value' => isset($_GET['search']) ? $_GET['search'] : ''
        ]);
        $searchGroup->add('button', [
            'type' => 'submit',
            'class' => 'button search',
            'innerHTML' => '<span class="icon-search"></span>'
        ]);

        // สร้างตาราง
        $table = new HtmlTable([
            'id' => 'users_table',
            'class' => 'data fullwidth sortable'
        ]);

        // Header
        $table->addHeader([
            '<input type="checkbox" id="select_all">',
            'รูปภาพ',
            'ชื่อ-นามสกุล',
            'อีเมล',
            'สถานะ',
            'วันที่สมัคร',
            'ล็อกอินล่าสุด',
            'การจัดการ'
        ]);

        // เพิ่มข้อมูลแถว
        if (empty($users)) {
            $table->addRow([
                ['text' => 'ไม่พบข้อมูล', 'colspan' => 8, 'class' => 'center empty']
            ]);
        } else {
            foreach ($users as $user) {
                $table->addRow([
                    '<input type="checkbox" name="id[]" value="' . $user['id'] . '">',
                    self::renderAvatar($user),
                    self::renderUserName($user),
                    $user['email'],
                    self::renderStatus($user['status']),
                    date('d/m/Y', strtotime($user['created_at'])),
                    $user['last_login'] ? date('d/m/Y H:i', strtotime($user['last_login'])) : '-',
                    self::renderActions($user)
                ]);
            }
        }

        $container->add('div', ['innerHTML' => $table->render()]);

        // Pagination
        if ($total > $perPage) {
            $container->add('div', [
                'innerHTML' => self::renderPagination($total, $page, $perPage)
            ]);
        }

        // Bulk actions
        $bulkActions = $container->add('div', ['class' => 'bulk-actions']);
        $bulkActions->add('select', [
            'id' => 'bulk_action',
            'class' => 'g-select',
            'options' => [
                '' => 'เลือกการดำเนินการ',
                'activate' => 'เปิดใช้งาน',
                'deactivate' => 'ปิดใช้งาน',
                'delete' => 'ลบ'
            ]
        ]);
        $bulkActions->add('button', [
            'type' => 'button',
            'class' => 'button action',
            'onclick' => 'performBulkAction()',
            'innerHTML' => 'ดำเนินการ'
        ]);

        // JavaScript
        $container->script('
            // Select all checkbox
            document.getElementById("select_all").addEventListener("change", function() {
                const checkboxes = document.querySelectorAll("input[name=\'id[]\']");
                checkboxes.forEach(cb => cb.checked = this.checked);
            });

            // Bulk actions
            function performBulkAction() {
                const action = document.getElementById("bulk_action").value;
                const selected = document.querySelectorAll("input[name=\'id[]\']:checked");

                if (!action) {
                    alert("กรุณาเลือกการดำเนินการ");
                    return;
                }

                if (selected.length === 0) {
                    alert("กรุณาเลือกรายการที่ต้องการดำเนินการ");
                    return;
                }

                const ids = Array.from(selected).map(cb => cb.value);
                const confirmMessage = `ต้องการ${getActionText(action)} ${ids.length} รายการ?`;

                if (confirm(confirmMessage)) {
                    // Submit form or Ajax request
                    submitBulkAction(action, ids);
                }
            }

            function getActionText(action) {
                switch(action) {
                    case "activate": return "เปิดใช้งาน";
                    case "deactivate": return "ปิดใช้งาน";
                    case "delete": return "ลบ";
                    default: return "";
                }
            }

            function submitBulkAction(action, ids) {
                // Ajax request
                fetch("index.php/users/bulk", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "X-Requested-With": "XMLHttpRequest"
                    },
                    body: JSON.stringify({
                        action: action,
                        ids: ids
                    })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        location.reload();
                    } else {
                        alert(data.message || "เกิดข้อผิดพลาด");
                    }
                })
                .catch(error => {
                    console.error("Error:", error);
                    alert("เกิดข้อผิดพลาดในการดำเนินการ");
                });
            }

            // Delete confirmation
            function confirmDelete(id, name) {
                if (confirm(`ต้องการลบผู้ใช้ "${name}" ?`)) {
                    window.location.href = `index.php/users/delete/${id}`;
                }
            }
        ');

        return $container->render();
    }

    private static function renderAvatar($user)
    {
        $avatar = $user['avatar'] ? $user['avatar'] : 'skin/img/noicon.png';
        return '<img src="' . $avatar . '" alt="Avatar" class="avatar-small">';
    }

    private static function renderUserName($user)
    {
        $name = $user['first_name'] . ' ' . $user['last_name'];
        $link = '<a href="index.php/users/view/' . $user['id'] . '">' . $name . '</a>';

        if (!empty($user['role'])) {
            $link .= '<br><small class="text-muted">' . $user['role'] . '</small>';
        }

        return $link;
    }

    private static function renderStatus($status)
    {
        $badges = [
            'active' => '<span class="badge green">ใช้งาน</span>',
            'inactive' => '<span class="badge red">ไม่ใช้งาน</span>',
            'pending' => '<span class="badge yellow">รอยืนยัน</span>',
            'suspended' => '<span class="badge gray">ถูกระงับ</span>'
        ];

        return $badges[$status] ?? '<span class="badge gray">ไม่ทราบ</span>';
    }

    private static function renderActions($user)
    {
        $actions = [];

        // ดูรายละเอียด
        $actions[] = '<a href="index.php/users/view/' . $user['id'] . '" class="icon-eye" title="ดูรายละเอียด"></a>';

        // แก้ไข
        $actions[] = '<a href="index.php/users/edit/' . $user['id'] . '" class="icon-edit" title="แก้ไข"></a>';

        // เปิด/ปิดใช้งาน
        if ($user['status'] === 'active') {
            $actions[] = '<a href="index.php/users/deactivate/' . $user['id'] . '" class="icon-ban" title="ปิดใช้งาน"></a>';
        } else {
            $actions[] = '<a href="index.php/users/activate/' . $user['id'] . '" class="icon-check" title="เปิดใช้งาน"></a>';
        }

        // ลบ
        $actions[] = '<a href="javascript:void(0)" onclick="confirmDelete(' . $user['id'] . ', \'' . addslashes($user['first_name'] . ' ' . $user['last_name']) . '\')" class="icon-delete" title="ลบ"></a>';

        return '<div class="actions">' . implode(' ', $actions) . '</div>';
    }

    private static function renderPagination($total, $page, $perPage)
    {
        $totalPages = ceil($total / $perPage);
        $pagination = '<div class="pagination">';

        // Previous page
        if ($page > 1) {
            $pagination .= '<a href="?page=' . ($page - 1) . '" class="prev">« ก่อนหน้า</a>';
        }

        // Page numbers
        $start = max(1, $page - 2);
        $end = min($totalPages, $page + 2);

        if ($start > 1) {
            $pagination .= '<a href="?page=1">1</a>';
            if ($start > 2) {
                $pagination .= '<span class="ellipsis">...</span>';
            }
        }

        for ($i = $start; $i <= $end; $i++) {
            if ($i == $page) {
                $pagination .= '<span class="current">' . $i . '</span>';
            } else {
                $pagination .= '<a href="?page=' . $i . '">' . $i . '</a>';
            }
        }

        if ($end < $totalPages) {
            if ($end < $totalPages - 1) {
                $pagination .= '<span class="ellipsis">...</span>';
            }
            $pagination .= '<a href="?page=' . $totalPages . '">' . $totalPages . '</a>';
        }

        // Next page
        if ($page < $totalPages) {
            $pagination .= '<a href="?page=' . ($page + 1) . '" class="next">ถัดไป »</a>';
        }

        $pagination .= '</div>';

        return $pagination;
    }
}

Best Practices

1. การตั้งชื่อและการจัดระเบียบ

// ✅ ใช้ชื่อที่มีความหมาย
$userRegistrationForm = Html::create('form', [
    'id' => 'user_registration_form',
    'class' => 'setup_frm user-form'
]);

// ❌ หลีกเลี่ยงชื่อที่ไม่มีความหมาย
$form1 = Html::create('form', ['id' => 'f1']);

// ✅ จัดกลุ่มฟิลด์ที่เกี่ยวข้องกัน
$personalInfo = $form->add('fieldset', ['title' => 'ข้อมูลส่วนตัว']);
$contactInfo = $form->add('fieldset', ['title' => 'ข้อมูลติดต่อ']);
$preferences = $form->add('fieldset', ['title' => 'การตั้งค่า']);

2. Accessibility และ UX

// ✅ ใช้ label ที่เหมาะสม
$emailGroup->add('label', [
    'for' => 'email',
    'innerHTML' => 'อีเมล <span class="required" aria-label="จำเป็น">*</span>'
]);

// ✅ เพิ่ม ARIA attributes
$form->add('input', [
    'type' => 'password',
    'id' => 'password',
    'name' => 'password',
    'aria-describedby' => 'password_help',
    'aria-required' => 'true'
]);

// ✅ Placeholder ที่มีประโยชน์
$form->add('input', [
    'type' => 'tel',
    'placeholder' => '0XX-XXX-XXXX',
    'pattern' => '[0-9]{3}-[0-9]{3}-[0-9]{4}'
]);

3. การจัดการข้อผิดพลาด

// ✅ Client-side validation
$form->script('
    function validateForm() {
        const email = document.getElementById("email");
        const password = document.getElementById("password");

        // Custom validation
        if (!isValidEmail(email.value)) {
            showError(email, "รูปแบบอีเมลไม่ถูกต้อง");
            return false;
        }

        if (password.value.length < 8) {
            showError(password, "รหัสผ่านต้องมีอย่างน้อย 8 ตัวอักษร");
            return false;
        }

        return true;
    }

    function showError(field, message) {
        field.setCustomValidity(message);
        field.reportValidity();
    }
');

// ✅ Server-side validation feedback
if (isset($errors['email'])) {
    $emailInput->setAttribute('class', 'g-input error');
    $emailInput->setAttribute('title', $errors['email']);
}

4. Performance

// ✅ โหลด JavaScript เมื่อจำเป็น
$form->script('
    // โหลด library เมื่อต้องการใช้งาน
    if (typeof DatePicker === "undefined") {
        loadScript("/js/datepicker.js", function() {
            initDatePicker("#birthdate");
        });
    }
');

// ✅ ใช้ lazy loading สำหรับตาราง
$table->setAttribute('data-lazy', 'true');
$table->setAttribute('data-source', 'index.php/api/users');

5. Security

// ✅ เพิ่ม CSRF token
$form = Html::create('form', [
    'token' => true, // เพิ่ม CSRF token อัตโนมัติ
    'method' => 'post'
]);

// ✅ Escape user input
$userInput = htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');

// ✅ Validate file uploads
$fileUpload = Form::file([
    'accept' => 'image/jpeg,image/png,image/gif',
    'max-size' => '2MB'
]);

การใช้คลาส Form, Html, HtmlTable และ Grid ของ Kotchasan จะช่วยให้การสร้างฟอร์มและตารางเป็นไปอย่างมีประสิทธิภาพ รวดเร็ว และปลอดภัย พร้อมรองรับการใช้งานบนอุปกรณ์ต่างๆ ได้อย่างสมบูรณ์