Tag Archive form

c#: Multiple Document Interface (MDI)

ตัวอย่างเขียน app แบบมีหลายฟอร์มย่อยอยู่ใน window หลัก หรือที่ฝรั่งเรียกไว้ว่า Multiple Document Interface (MDI)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PrototypesCSharp
{
    public partial class FormMDI : Form
    {
        public FormMDI()
        {
            InitializeComponent();
        }

        public Form TryGetFormByName(string frmName)
        {
            if (panelMDI.Controls.Count > 0)
            {
                panelMDI.Controls.RemoveAt(0);
            }

            var formType = Assembly.GetExecutingAssembly().GetTypes()
                .Where(a => a.BaseType == typeof(Form) && a.Name == frmName)
                .FirstOrDefault();

            if (formType == null)
            {//if no form
                return null;
            }

            Form frm = (Form)Activator.CreateInstance(formType);

            //https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.form.acceptbutton?view=net-5.0

            frm.AutoSize = true;
            frm.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            frm.Height = panelMDI.Height;
            frm.TopLevel = false;
            frm.TopMost = true;
            frm.WindowState = FormWindowState.Maximized;
            frm.Width = panelMDI.Width;

            frm.Show();

            panelMDI.Controls.Add(frm);

            return frm;
        }

        //on menu click
        private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            try
            {
                String formName = e.ClickedItem.Name.Split(new[] { "toolStripMenuItem" }, StringSplitOptions.None)[1];

                Form frm = TryGetFormByName(formName);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        //resize form inside when main windows resize
        private void panelMDI_Resize(object sender, EventArgs e)
        {
            foreach (Form frm in panel1.Controls)
            {
                frm.WindowState = FormWindowState.Normal;

                frm.WindowState = FormWindowState.Maximized;
            }
        }

    }
}

code ชุดนี้ทำงานโดยเมื่อ user click บน menuStrip (ไม่ใช้ตัว item นะ) จะอ่าน item name แล้วตัด toolStripMenuItem ออกเพื่อเรียกฟอร์ม ต้องขอขอบคุณ nemesv สำหรับคำตอบในเรื่อง Winforms, create form instance by form name ทำให้เขียน code สะอาดขึ้นเยอะเลย ไม่ต้องมา set ให้ item ทีละตัวแล้ว

jQuery: upload แบบ ajax

ตัวอย่างการใช้ jQuery upload ไฟล์แบบ ajax[code language=”html” title=”ajax.form.upload.html”]<!doctype html>
<html>

<head>
<meta charset="utf-8">
<title>jQuery: form > send file</title>
<link href="../vendor/twbs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<style>
.progressbar {
background: #c00000;
clear: both;
height: 10px;
width: 0;
}

.progressLoaded {
width: 50px;
}

.progressLoaded::after {
content: " bytes";
}

.progressPercent {
width: 50px;
}

.progressPercent::after {
content: " %";
}

.progressTotal {
float: left;
width: 50px;
}

.progressTotal::after {
content: " bytes";
}

.progressTotal::before {
content: " of ";
}
</style>
</head>

<body>
<h1>upload file with ajax</h1>
<form action="values.php" class="form-horizontal" enctype="multipart/form-data" id="formA" method="post">
<div class="form-group">
<label class="col-sm-2 control-label" for="socialidI">หมายเลขบัตรประชาชน</label>
<div class="col-sm-10">
<input class="form-control" id="socialidI" maxlength="13" name="socialid" placeholder="หมายเลขบัตรประชาชน" type="number">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="photoI">ภาพถ่าย</label>
<div class="col-sm-10">
<input class="form-control" id="photoI" name="photo" placeholder="upload file" type="file">
</div>
</div>
<div class="form-group">
<div class="col-sm-10 text-right">
<button type="submit" class="btn btn-success">ส่งข้อมูล</button>
</div>
</div>
</form>
<div class="col-sm-12">
<h4>Progress</h4>
<div class="progressLoaded"></div>
<div class="progressTotal"></div>
<div class="progressPercent"></div>
<div class="progressbar"></div>
</div>
<div class="col-sm-12" id="resultA"></div>
<script src="../vendor/components/jquery/jquery.min.js"></script>
<script>
function xhrProgress(xhr) {
if (xhr.upload) {
// For handling the progress of the upload
xhr.upload.addEventListener(‘progress’, function (e) {
if (e.lengthComputable) {
$(‘.progressTotal’).html(e.total);
$(‘.progressLoaded’).html(e.loaded);

percentComplete = parseInt((e.loaded / e.total * 100), 10);
$(‘.progressPercent’).html(percentComplete);
$(‘.progressbar’).css("width", percentComplete + ‘%’);
}
}, false);
}
return xhr;
}

$(function () {

var formA = $(‘#formA’);

formA.submit(function (event) {
event.preventDefault();

$.ajax({
"beforeSend": function (jqXHR, settings) {
/* แยกตัวแปรไว้ตรวจสอบข้อมูล */
var params = settings.data;

if (settings.data.get(‘socialid’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกหมายเลขบัตรประชาชน’);

return false;
}

if (settings.data.get(‘photo’).name == ”) {

jqXHR.abort();
alert(‘กรุณาอัพโหลดรูปภาพ’);

return false;
}

},
"contentType": false,
"data": new FormData(formA[0]),
"method": "POST",
"processData": false,
"success": function (data, textStatus, jqXHR) {
$(‘#resultA’).html(data);
},
"url": "values.php",
"xhr": function () {
return xhrProgress($.ajaxSettings.xhr());
},

});

});

});
</script>
</body>

</html>[/code]ไฟล์ที่รอรับข้อมูล[code language=”php” title=”values.php”]<?php
echo ‘FILE<pre>’, print_r($_FILES, true), ‘</pre>’;
echo ‘GET<pre>’, print_r($_GET, true), ‘</pre>’;
echo ‘POST<pre>’, print_r($_POST, true), ‘</pre>’;
[/code]

วิธีนี้ใช้ความสามารถใหม่ FormData ที่ใช้กับ browser เก่าแก่กว่า Internet Explorer 10 หรือ Edge ไม่ได้ ดูเพิ่มเติม

jQuery: ส่ง form แบบ ajax ชั้นสูง

ก่อนที่จะใช้ jQuery ส่งข้อมูลแบบ ajax ออกไป อาจจะใช้ javascript ทำงานเบื้องต้นก่อนได้เช่น การตรวจสอบข้อมูล (validation) ว่า user ได้ทำการกรอกข้อมูลตามที่จำเป็นครบรึเปล่า หรือนำข้อมูลออกไปจากแบบฟอร์ม โดยที่ไม่ต้องไปทำในฝั่ง server

ใน jQuery Ajax สามารถทำได้โดยการระบุ “beforeSend” ตาม code ตัวอย่าง[code language=”javascript” title=”jQuery: advance process before send data”]$.ajax({
"beforeSend": function(jqXHR, settings) {

/* ใส่ตัวแปรเข้าไปเพิ่ม */
settings.data += ‘&ajax=true’;

/* แยกตัวแปรไว้ตรวจสอบข้อมูล */
var params = new URLSearchParams(settings.data);

/* บังคับกรอกข้อมูล */
if (params.get(‘way’) == ‘socialid’ && params.get(‘socialid’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกหมายเลขบัตรประชาชน’);

return false;
} else if (params.get(‘way’) == ‘phone’ && params.get(‘phone’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกหมายเลขโทรศัพท์’);

return false;
}

if (params.get(‘amount’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกจำนวนเงิน’);

return false;
}

/* เอาข้อมูลที่ไม่ต้องการส่งออก */
settings.data = RemoveParameterFromUrl(settings.data, ‘way’);
settings.data = RemoveParameterFromUrl(settings.data, ‘way’);
if (params.get(‘way’) == ‘socialid’) {
settings.data = RemoveParameterFromUrl(settings.data, ‘phone’);
} else {
settings.data = RemoveParameterFromUrl(settings.data, ‘socialid’);
}

},
"data": formA.serialize(),
"method": "POST",
"success": function(data, textStatus, jqXHR) {
$(‘#resultA’).html(data);
},
"url": "values.php",
});[/code]เราจะดูข้อมูลที่รวบรวมมาได้ใน object settings.data และสามารถต่อ string เพิ่มเข้าไปได้เหมือนการต่อ string[code language=”javascript” title=”add new data”]settings.data += ‘&ajax=true’;[/code]การที่จะแยกข้อมูลออกมาสามารถใช้[code language=”javascript” title=”get value from query string”]var params = new URLSearchParams(settings.data);[/code]แบ่งข้อมูลออกมาเป็น array เพื่อใช้ตรวจสอบข้อมูลหรือจะนำไปใช้ในการเปลี่ยนแปลงข้อมูล เช่นเดียวกันก็สามารถ delete ลบข้อมูลที่ไม่ได้การออกไปได้โดยใช้ function[code language=”javascript” title=”delete data from url”]function RemoveParameterFromUrl(url, parameter) {
return url.replace(new RegExp(‘^([^#]*\?)(([^#]*)&)?’ + parameter + ‘(\=[^&#]*)?(&|#|$)’), ‘$1$3$5’).replace(/^([^#]*)((\?)&|\?(#|$))/, ‘$1$3$4’);
}[/code]

ตัวอย่าง form เขียนโดยยกกรณีโอนเงินโดยใช้ พร้อมเพย์ (PromptPay) ที่ user จะเลือกได้ว่าจะโอนเงินโดยใช้ บัตรประชาชน หรือหมายเลขโทรศัพท์ของผู้รับแทนที่จะใช้หมายเลขบัญชี

[code language=”html” title=”ajax.form.advance.html”]<!doctype html>
<html>

<head>
<meta charset="utf-8">
<title>jQuery: Advance Form Send</title>
<link href="../vendor/twbs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>

<body>
<h1>พร้อมเพย์ (PromptPay)</h1>
<form action="values.php" class="form-horizontal" id="formA" method="post">
<div class="form-group">
<label class="col-sm-2 control-label">โอนเงินด้วย</label>
<div class="col-sm-10">
<div class="radio">
<label>
<input checked name="way" type="radio" value="socialid"> หมายเลขบัตรประชาชน
</label>
</div>
<div class="radio">
<label>
<input name="way" type="radio" value="phone"> หมายเลขโทรศัพท์
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="socialidI">หมายเลขบัตรประชาชน</label>
<div class="col-sm-10">
<input class="form-control" id="socialidI" maxlength="13" name="socialid" placeholder="หมายเลขบัตรประชาชน" type="number">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="phoneI">หมายเลขโทรศัพท์</label>
<div class="col-sm-10">
<input class="form-control" id="phoneI" maxlength="11" name="phone" placeholder="หมายเลขโทรศัพท์" type="tel">
</div>
</div>
<div class="form-group">
<label for="amount" class="col-sm-2 control-label">จำนวนเงิน</label>
<div class="col-sm-10">
<div class="input-group">
<input class="form-control" id="amount" max="5000" min="0" name="amount" placeholder="จำนวนเงิน" type="number">
<div class="input-group-addon">&#3647;</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-10 text-right">
<button type="submit" class="btn btn-success">โอนเงิน</button>
</div>
</div>
</form>
<div class="col-sm-12" id="resultA"></div>
<script src="../vendor/components/jquery/jquery.min.js"></script>
<script>
function RemoveParameterFromUrl(url, parameter) {
return url.replace(new RegExp(‘^([^#]*\?)(([^#]*)&)?’ + parameter + ‘(\=[^&#]*)?(&|#|$)’), ‘$1$3$5’).replace(/^([^#]*)((\?)&|\?(#|$))/, ‘$1$3$4’);
}

$(function () {
var formA = $(‘#formA’);

formA.submit(function (event) {
event.preventDefault();

$.ajax({
"beforeSend": function (jqXHR, settings) {

/* ใส่ตัวแปรเข้าไปเพิ่ม */
settings.data += ‘&ajax=true’;

/* แยกตัวแปรไว้ตรวจสอบข้อมูล */
var params = new URLSearchParams(settings.data);

/* บังคับกรอกข้อมูล */
if (params.get(‘way’) == ‘socialid’ && params.get(‘socialid’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกหมายเลขบัตรประชาชน’);

return false;
} else if (params.get(‘way’) == ‘phone’ && params.get(‘phone’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกหมายเลขโทรศัพท์’);

return false;
}

if (params.get(‘amount’) == ”) {

jqXHR.abort();
alert(‘กรุณากรอกจำนวนเงิน’);

return false;
}

/* เอาข้อมูลที่ไม่ต้องการส่งออก */
settings.data = RemoveParameterFromUrl(settings.data, ‘way’);
settings.data = RemoveParameterFromUrl(settings.data, ‘way’);
if (params.get(‘way’) == ‘socialid’) {
settings.data = RemoveParameterFromUrl(settings.data, ‘phone’);
} else {
settings.data = RemoveParameterFromUrl(settings.data, ‘socialid’);
}

},
"data": formA.serialize(),
"method": "POST",
"success": function (data, textStatus, jqXHR) {
$(‘#resultA’).html(data);
},
"url": "values.php",
});
});
});
</script>
</body>

</html>[/code]และฝั่ง server side ที่ควรจะมีการ validation ตรวจสอบข้อมูลซ้ำอีกครั้งเพื่อความมั่นใจ แต่ตัวอย่างนี้จะแสดงข้อมูลที่ทางฝั่ง server ได้รับเท่านั้น เพื่อให้เห็นการ edit แก้ข้อมูลที่ส่งไป[code language=”php” title=”values.php”]<?php
echo ‘GET<pre>’, print_r($_GET, true), ‘</pre>’;
echo ‘POST<pre>’, print_r($_POST, true), ‘</pre>’;[/code]

jQuery: ส่ง form แบบ ajax

พื้นฐานการส่งข้อมูลจากแบบฟอร์มไปประมวลผลโดย jQuery Ajax ทำได้ง่ายๆ

องค์ประกอบ

  1. ส่วนประกอบแรกก็คือฟอร์มที่ใช้กรอกข้อมูล[code language=”html” title=”ajax.form.html”]<form action="values.php" id="formA" method="post">

    <input name="socialid" type="text">

    <button type="submit" class="btn btn-success">ส่งข้อมูล</button>
    …</form>[/code]ส่วนสำคัญคือ id (id=”formA”) ของฟอร์มที่จะใช้อ้างถึงใน JavaScript
  2. ส่วน JavaScript ที่จะรวบรวมข้อมูลส่งออกไปหาเซิร์ฟเวอร์[code language=”javascript” title=”send form by ajax”]$(function() {
    var formA = $(‘#formA’);

    formA.submit(function(event) {
    event.preventDefault();

    $.ajax({
    "data": formA.serialize(),
    "method": "POST",
    "success": function(data, textStatus, jqXHR) {
    $(‘#resultA’).html(data);
    },
    "url": "values.php",
    });
    });
    });[/code]

    data
    ข้อมูลที่จะส่งออกไป ตัวอย่างนี้ข้อมูลในแบบฟอร์มจะถูกรวบรวมโดย function .serialize()

    method
    คือจะส่งข้อมูลไปหา server แบบ get หรือ post
    success
    code ในส่วนนี้จะทำงานเมื่อทำงานสำเร็จเท่านั้น
    url
    เป็น url ที่จะส่งข้อมุลไปหา
  3. ฝั่ง server ที่ทำหน้าที่ประมวลผล[code language=”php” title=”values.php”]<?php
    echo ‘GET<pre>’, print_r($_GET, true), ‘</pre>’;
    echo ‘POST<pre>’, print_r($_POST, true), ‘</pre>’;[/code]
  4. ส่วนแสดงผล เพราะว่าการส่งแบบ ajax จะส่งไปเป็นแบบ background จึงควรมีการแสดงให้เห็นว่ามีการทำงานเกิดขึ้น ใน code ชุดนี้คือแสดงผลในพื้นที่[code language=”html” tilte=”พื้นที่แสดงผล”]<div class="col-sm-12" id="resultA"></div>[/code]

ตัวอย่าง code ที่เขียนเสร็จแล้ว[code language=”html” title=”ajax.form.html”]<!doctype html>
<html>

<head>
<meta charset="utf-8">
<title>jQuery: Form Send</title>
<link href="../vendor/twbs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>

<body>
<h1>พร้อมเพย์ (PromptPay)</h1>
<form action="values.php" class="form-horizontal" id="formA" method="post">
<div class="form-group">
<label class="col-sm-2 control-label">โอนเงินด้วย</label>
<div class="col-sm-10">
<div class="radio">
<label>
<input checked name="way" type="radio" value="socialid"> หมายเลขบัตรประชาชน
</label>
</div>
<div class="radio">
<label>
<input name="way" type="radio" value="phone"> หมายเลขโทรศัพท์
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="socialidI">หมายเลขบัตรประชาชน</label>
<div class="col-sm-10">
<input class="form-control" id="socialidI" maxlength="13" name="socialid" placeholder="หมายเลขบัตรประชาชน" type="number">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="phoneI">หมายเลขโทรศัพท์</label>
<div class="col-sm-10">
<input class="form-control" id="phoneI" maxlength="11" name="phone" placeholder="หมายเลขโทรศัพท์" type="tel">
</div>
</div>
<div class="form-group">
<label for="amount" class="col-sm-2 control-label">จำนวนเงิน</label>
<div class="col-sm-10">
<div class="input-group">
<input class="form-control" id="amount" max="5000" min="0" name="amount" placeholder="จำนวนเงิน" type="number">
<div class="input-group-addon">&#3647;</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-10 text-right">
<button type="submit" class="btn btn-success">โอนเงิน</button>
</div>
</div>
</form>
<div class="col-sm-12" id="resultA"></div>
<script src="../vendor/components/jquery/jquery.min.js"></script>
<script>
$(function () {
var formA = $(‘#formA’);

formA.submit(function (event) {
event.preventDefault();

$.ajax({
"data": formA.serialize(),
"method": "POST",
"success": function (data, textStatus, jqXHR) {
$(‘#resultA’).html(data);
},
"url": "values.php",
});
});
});
</script>
</body>

</html>[/code]และ code ที่ประมวลผลข้อมูล[code language=”php” title=”values.php”]<?php
echo ‘GET<pre>’, print_r($_GET, true), ‘</pre>’;
echo ‘POST<pre>’, print_r($_POST, true), ‘</pre>’;[/code]

DataTable: การค้นหาชั้นสูง

เราสามารถเพิ่มเงื่อนไขให้ DataTables ใช้ในการค้นหาได้ โดยส่วนที่เปลี่ยนไปจากเดิมคือใช้ “beforeSend” ในการรวมข้อมูลจาก form (formA) และเขียน validation ง่ายๆ โดยบังคับว่าถ้า advanceSearch ถูกติ๊กอยู่จะต้องเลือก geo_id ด้วย (จริงๆคือ ถึงไม่ติ๊ก advanceSearch ก็ใช้ geo_id search ได้เหมือนกัน)

[code language=”html” title=”jQuery.DataTables/data.json.external.search.html”]<!doctype html>
<html>

<head>
<meta charset="utf-8">
<meta name="author" content="Pitt Phunsanit">
<title>DataTables: external.search</title>
<link href="../vendor/twbs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="../vendor/twbs/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css">
<link href="../vendor/datatables/datatables/media/css/dataTables.bootstrap.min.css" rel="stylesheet" type="text/css">
</head>

<body>
<form action="DataTables.json.php" class="form-inline" id="formA" method="post">
<div class="form-group">
<input name="advanceSearch" type="checkbox">
<label for="advanceSearch">advance Search</label>
</div>
<div class="form-group">
<label for="geo_id">ภูมิภาค:</label>
<select class="form-control" name="geo_id">
<option selected="selected" value="">— Select —</option>
<option value="1">ภาคเหนือ</option>
<option value="2">ภาคกลาง</option>
<option value="3">ภาคตะวันออกเฉียงเหนือ</option>
<option value="4">ภาคตะวันตก</option>
<option value="5">ภาคตะวันออก</option>
<option value="6">ภาคใต้</option>
</select>
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
<table class="table table-bordered table-hover table-striped" id="tableA" width="100%"></table>
<script src="../vendor/components/jquery/jquery.min.js"></script>
<script src="../vendor/datatables/datatables/media/js/jquery.dataTables.min.js"></script>
<script src="../vendor/datatables/datatables/media/js/dataTables.bootstrap.min.js"></script>
<script src="data.json.external.search.js"></script>
</body>

</html>[/code][code language=”javascript” title=”jQuery.DataTables/data.json.external.search.js”]$(function() {

formA = $(‘#formA’);
tableA = $(‘#tableA’);

datatable = tableA.DataTable({
"ajax": {
"beforeSend": function(jqXHR, settings) {
/* add value form from to DataTable params */
settings.data = formA.serialize() + ‘&’ + settings.data;

/* validation */
var params = new URLSearchParams(settings.data);

/* user must selected region if enable advance search */
if (params.get(‘advanceSearch’) == ‘on’ && params.get(‘geo_id’) == ”) {
jqXHR.abort();
alert(‘กรุณาเลือกภูมิภาค’);
return false;
}

return true;
},
"dataSrc": function(json) {
alert(‘data back ‘ + json.data.length + ‘ items’);

return json.data;
},
"method": "POST",
"url": "data.json.php",
},
"columns": [{
"orderable": false,
"render": function(data, type, row, meta) {
return parseInt(meta.row) + parseInt(meta.settings._iDisplayStart) + 1;
},
"title": ‘No.’,
"width": "10px",
},
{
"orderable": false,
"render": function(data, type, row, meta) {
return ‘<input type="checkbox" value="’ + row.DISTRICT_CODE + ‘">’;
},
"title": ‘<input class="checkAll" type="checkbox">’,
"width": "10px",
},
{
"orderable": false,
"render": function(data, type, row, meta) {
if (row.enable == ‘1’) {
return ‘<span class="glyphicon glyphicon-ok"></span>’;
} else {
return ‘<span class="glyphicon glyphicon-remove"></span>’;
}
},
"title": "Enable",
"width": "10px",
}, {
"data": "DISTRICT_CODE",
"title": "District Code",
"width": "90px",
}, {
"data": "DISTRICT_NAME",
"title": "District Name",
}, {
"data": "PROVINCE_NAME",
"title": "Province Name",
}
],
/* default sort */
"order": [
[3, "asc"],
[4, "asc"],
],
"processing": true,
"serverSide": true,
"stateSave": true,
});

$(‘.checkAll’, tableA).click(function() {
$(‘input:checkbox’, tableA).not(this).prop(‘checked’, this.checked);
});

formA.submit(function(event) {
event.preventDefault();

datatable.ajax.reload();
});

});[/code]

  • ข้อมูลจากฟอร์ม [code language=”html”]id="formA"[/code] จะถูกรวมกับ data ที่ DataTable สร้างขึ้นมาเองโดย[code language=”javascript” title=”beforeSend”]"beforeSend": function(jqXHR, settings) {
    settings.data = formA.serialize() + ‘&’ + settings.data;
    },[/code]
  • สามารถทำ validation data ก่อนส่งข้อมูลออกไป ถ้าต้องการหยุดการทำงาน ก็ให้ใช้[code language=”javascript” title=”beforeSend”]"beforeSend": function(jqXHR, settings) {
    jqXHR.abort();
    },[/code]ไม่ให้ส่งข้อมูลกลับไป server อาจจะดัดแปลงให้ datatable ไม่ขอข้อมูลจาก server กรณีที่ไม่มีการเลือกตัว filter ก็ได้เช่นกัน
  • หลังได้ข้อมูลกลับมายังสามารถใช้[code language=”javascript” title=”dataSrc / success”]"dataSrc": function(json) {
    alert(‘data back ‘ + json.data.length + ‘ items’);

    return json.data;
    },[/code]แก้ไขข้อมูลก่อนแสดงผลได้ แต่ไม่ใช่ “success” เหมือนใน jQuery ajax ตามปกตินะครับ เพราะจะทำให้ DataTable มันทำงานผิดปกติได้เลย

  • ถ้าต้องการให้ DataTable ดึงข้อมูลใหม่ให้ใช้รูปแบบ[code language=”javascript” title=”refresh datatable”]datatable.ajax.reload();[/code]

[code language=”php” title=”jQuery.DataTables/data.json.php”]<?php
/* https://datatables.net/manual/server-side */

$output = [
‘data’ => [],
‘debug’ => [
‘length’ => $_REQUEST[‘length’],
‘post’ => $_REQUEST,
‘sqlCount’ => ”,
‘sqlResult’ => ”,
‘start’ => $_REQUEST[‘start’],
],
‘draw’ => $_REQUEST[‘draw’],
‘recordsFiltered’ => $_REQUEST[‘length’],
‘recordsTotal’ => 0,
];

$dns = new PDO(‘mysql:host=localhost;dbname=snippets’, ‘root’, ”, [
//PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => ‘SET NAMES utf8’,
]);

$condition = [];
$from = ‘ FROM district AS d LEFT JOIN province AS p ON d.PROVINCE_ID = p.PROVINCE_ID’;
$parameters = [];
$where = ”;

if (isset($_REQUEST[‘filters’]) || isset($_REQUEST[‘search’][‘value’])) {

if (isset($_REQUEST[‘search’][‘value’])) {
if ($_REQUEST[‘search’][‘value’] != ”) {

$parameter = ‘:d_DISTRICT_NAME’;

$parameters[$parameter] = ‘%’ . $_REQUEST[‘search’][‘value’] . ‘%’;
array_push($condition, ‘d.DISTRICT_NAME LIKE ‘ . $parameter);
}
}

if (isset($_REQUEST[‘filters’])) {
foreach ($_REQUEST[‘filters’] as $tableAlias => $filter) {
foreach ($filter as $field => $value) {
if ($value != ”) {
$parameter = ‘:’ . $tableAlias . ‘_’ . $field;

$parameters[$parameter] = ‘%’ . $value . ‘%’;
array_push($condition, $tableAlias . ‘.’ . $field . ‘ LIKE ‘ . $parameter);
}
}
}
}

}

if (isset($_REQUEST[‘geo_id’]) && $_REQUEST[‘geo_id’] != ”) {
$parameter = ‘:d_geo_id’;

$parameters[$parameter] = $_REQUEST[‘geo_id’];
array_push($condition, ‘d.GEO_ID = ‘ . $parameter);
}

if (count($parameters)) {
$where = ‘ WHERE ‘ . implode("\n\t AND ", $condition);
}

if (isset($_REQUEST[‘order’]) && isset($_REQUEST[‘order’][0])) {
$columns = [
0 => ‘DISTRICT_NAME’,
3 => ‘DISTRICT_CODE’,
4 => ‘DISTRICT_NAME’,
5 => ‘PROVINCE_NAME’,
];

$order = ‘ ORDER BY ‘ . $columns[$_REQUEST[‘order’][0][‘column’]] . ‘ ‘ . strtoupper($_REQUEST[‘order’][0][‘dir’]);
} else {
$order = ‘ ORDER BY DISTRICT_NAME ASC’;
}

$output[‘debug’][‘parameters’] = $parameters;

/* Total records, before filtering */
$sql = ‘SELECT COUNT(d.DISTRICT_ID)’ . $from;
try {
$output[‘debug’][‘sqlCount’] = $sql;
$stmt = $dns->prepare($sql);
$stmt->execute($parameters);
$output[‘recordsTotal’] = (int) $stmt->fetchColumn(0);
} catch (PDOException $e) {
exit($e->getMessage());
}

/* Total records, after filtering */
$sql = ‘SELECT COUNT(d.DISTRICT_ID)’ . $from . $where;
try {
$output[‘debug’][‘sqlCount’] = $sql;
$stmt = $dns->prepare($sql);
$stmt->execute($parameters);
$output[‘recordsFiltered’] = (int) $stmt->fetchColumn(0);
} catch (PDOException $e) {
exit($e->getMessage());
}

/* data */
if ($output[‘recordsTotal’] > 0) {
$sql = ‘SELECT d.enable, d.DISTRICT_ID, d.DISTRICT_CODE, d.DISTRICT_NAME, p.PROVINCE_NAME’ . $from . $where . $order . " LIMIT " . $_REQUEST[‘start’] . ", " . $_REQUEST[‘length’] . ";";

try {
$output[‘debug’][‘sqlResult’] = $sql;
$stmt = $dns->prepare($sql);
$stmt->execute($parameters);
$output[‘data’] = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
exit($e->getMessage());
}
}

/* unset debug for security */
unset($output[‘debug’]);

header(‘Content-type: application/json; charset=utf-8’);
echo json_encode($output);[/code]

อ่านเพิ่มเติม

Custom Rules Validation

ตัวอย่างการเขียน custom rule validation[code language=”php” title=”\application\controllers\FormValidationCustomRules.php”]<?php
class FormValidationCustomRules extends CI_Controller
{

public function __construct()
{
parent::__construct();
// Your own constructor code
}

public function uploadJPEG()
{
$this->form_validation->set_rules(‘cover’, ‘JPEG Upload’, ‘trim|xss_clean’);

if ($this->form_validation->run() == true) {
$fileDir = ‘assets/contents/’;
$fileName = date(‘U’) . ‘.jpeg’;

$config = [
‘allowed_types’ => ‘jfi|jfif|jif|jpe|jpeg|jpg’,
‘file_ext_tolower’ => true,
‘file_name’ => $fileName,
‘max_size’ => ‘10000’,
‘overwrite’ => false,
‘upload_path’ => $fileDir,
];

$this->load->library(‘upload’, $config);

if ($this->upload->do_upload(‘cover’, false)) {
$this->uploadFile = $fileDir . $fileName;
return true;
} else {
$this->form_validation->set_message(‘uploadJPEG’, $data[‘error’] = $this->upload->display_errors());

if ($_FILES[‘cover’][‘error’] != 4) {
return false;
}
}
}

return false;
}

public function index()
{
$this->load->library(‘form_validation’);

$formValidation = [
[
‘field’ => ‘cover’,
‘label’ => ‘JPEG Upload’,
‘rules’ => ‘callback_uploadJPEG’,
],
];
$this->form_validation->set_rules($formValidation);

if ($this->form_validation->run() == true) {
echo ‘upload file to ‘, $this->uploadFile, ‘<br><img alt="’, $this->uploadFile, ‘" class="img-thumbnail" src="../’, $this->uploadFile, ‘">’;
}

$this->load->view(‘FormValidation/CustomRules’);
}
}
[/code]

หลักการคือ

  • สร้าง function ขึ้นมา แล้วเรียกใช้โดยมี callback_ นำหน้า
  • ส่ง message กลับมาโดยใช้ $this->form_validation->set_message(‘function name’,’ข้อความ’)

แก้ validation error ใน YII 2

ฟอร์มของ yii จะมีการแจ้งเตือนถ้าหากพบว่าข้อมูล input ที่เรากรอกใน form ไม่ถูกต้อง โดยจะทำกรอบอินพุต ป้าย label เป็นสีแดงและมีข้อความแสดงใน help-block เพิ่มขึ้นมา บางครั้งก็ทำให้ฟอร์มที่จัดไว้แน่นๆ ไม่ใช่แบบบรรทัดละกล่องข้อความตามแบบเว็บสมัยใหม่ เวลาเจอความผิดพลาด มันก็จะถีบตัวอื่นออกไป หรือดูอัดแน่นเกินไปจนดูไม่สวย

ก็สามารถเอาออกได้โดยใช้ form template เหมือนเดิม โดยยังสามารถทำ validation ได้ตามปกติ

วิธีการคือ

  1. เปิดไฟล์ _form.php ใน view เป้าหมาย
  2. เปลี่ยน
    [code language=”php”]
    <?php $form = ActiveForm::begin([‘id’ => ‘login-form’]); ?>
    [/code]เป็น
    [code language=”php”]
    <?php $form = ActiveForm::begin([
    ‘fieldConfig’ => [
    ‘template’ => "{label}\n{input}\n{hint}"
    ],
    ‘id’ => ‘login-form’
    ]); ?>
    [/code]

อย่าลืมเปลี่ยน id นะครับ

ถ้าใช้[code language=”php”]use yii\bootstrap\ActiveForm;[/code]ให้เปลี่ยน template เป็น[code language=”php”]’template’ => "{label}\n{beginWrapper}\n{input}\n{hint}\n{endWrapper}"[/code]

YII2 GRUD GRID FROM หลายภาษา

จากเรื่องที่แล้ว ทำตาราง yii 2 ให้เก็บหลายภาษา โดยเราสามารถอ้างถึง attribute ตามรูปแบบ {attribute name}_{language} เช่น ในตาราง _lang ฟิลย์ชื่อ name ก็ใช้ $model->name_en, $model->name_jp, $model->name_th ในวิวถ้าต้องการแสดงผล

ในบทความที่ยังขาดตัวอย่างในการแสดงข้อมูล การใช้ในกริดที่แสดงรายการทั้งหมด, ฟอร์มที่จะกรอกข้อมูล และวิวที่จะแสดงสิ่งที่เราเก็บเอาไว้ออกมา ตัวอย่าง code ที่ผมใช้

GridView ต้องการให้แสดงภาษาอังกฤษเป็นหลัก อีกช่องที่เหลือแสดงสลับกันระหว่างภาษาไทย และญี่ปุ่น ทำได้โดยแทนที่จะอ้าง name_th หรือ name_jp ตรงๆ ก็อ้างผ่านตัวแปรไปแทน [code lang=”php” title=”index.php”]

if(Yii::$app->language == ‘jp’)
{
$name = ‘name_jp’;
}
else
{
$name = ‘name_th’;
}

echo GridView::widget([
‘dataProvider’ => $dataProvider,
‘filterModel’ => $searchModel,
‘columns’ => [
[‘class’ => ‘yii\grid\SerialColumn’],

‘name_en’,
$name,

‘post_id’,
‘status’,
],
]);

[/code]

form ก็สามารถใช้เหมือนรูบแบบปกติได้เลย โดยเราสามารถกรอกข้อมูล แก้ไขตัวแปลภาษาทั้งหมดได้พร้อมกันในครั้งเดียว เช่น[code lang=”php” title=”_form.php”]

<?= $form->field($model, ‘name_en’)->textInput() ?>
<?= $form->field($model, ‘name_jp’)->textInput() ?>
<?= $form->field($model, ‘name_th’)->textInput() ?>

[/code]

วิวก็ตามรูปแบบเหมือนตัวอื่นๆตามปกติ[code lang=”php” title=”view.php”]

<?= DetailView::widget([
‘model’ => $model,
‘attributes’ => [
‘post_id’,
‘status’,

‘name_en’,
‘name_jp’,
‘name_th’,

‘date_publish’,
‘date_expire’,
‘log_created’,
‘log_created_by’,
‘log_updated’,
‘log_updated_by’,
],
]) ?>
…[/code]

YII 2 : Horizontal / inline form

ตามปกติ form ของ yii ที่ใช้ GII generate ออกมาจะเป็นรูปแบบ label บรรทัดหนึ่ง input อีกบรรทัดหนึ่ง อ่านง่าย สวยงามพอสมควร แต่อาจจะไม่ถูกใจบรรดาหัวหน้าอนุรักษ์นิยมทั้งหลาย

yii มีอีกทางเลือกให้ใช้ทำฟอร์ม คือ มี Horizontal form ให้เลือกใช้ yii bootstrap activeform (Horizontal form) อีกตัว

วิธีการคือ

  1. เปิดไฟล์ _form.php ใน view เป้าหมาย
  2. เปลี่ยน use yii\widgets\ActiveForm; เป็น use yii\bootstrap\ActiveForm; ถ้าไม่เปลี่ยนจะเจอ error Setting unknown property: yii\widgets\ActiveForm::layout
  3. เปลี่ยน[code language=”PHP”]$form = ActiveForm::begin();[/code]เป็น[code language=”PHP”]$form = ActiveForm::begin([
    ‘fieldConfig’ => [
    ‘horizontalCssClasses’ => [
    ‘label’ => ‘col-sm-2’,
    ‘offset’ => ‘col-sm-offset-2’,
    ‘wrapper’ => ‘col-sm-10’
    ]
    ],
    ‘layout’ => ‘horizontal’
    ]);[/code]
  4. สำเร็จแล้ว ฟอร์มจะเปลี่ยนเป็นรูปแบบเหมือนกับ Bootstrap Horizontal form โดย

    • layout คือ จะวางฟอร์มเป็นแบบไหน มีให้เลือก คือ default, horizontal และ inline
    • label คือ ค่า grid ของ label
    • wrapper คือ ความกว้างของช่อง input
    • offset คือ การเว้นระยะของพวก checkbox ตั้งไว้เท่ากับ label จะได้ตรงกันพอดี

    เสร็จแล้ว หรือจะใช้การจัด code แบบของผมก็ได้ครับ ไม่อยากสลับ php เข้าออก ไปๆ มาๆ [code language=”PHP”]
    <?php

    use yii\helpers\Html;
    use yii\bootstrap\ActiveForm;

    ?>

    <div class="user-form">
    <?php
    $form = ActiveForm::begin([
    ‘fieldConfig’ => [
    ‘horizontalCssClasses’ => [
    ‘label’ => ‘col-sm-2’,
    ‘offset’ => ‘col-sm-offset-2’,
    ‘wrapper’ => ‘col-sm-10’
    ]
    ],
    ‘layout’ => ‘horizontal’
    ]);

    echo $form->field($model, ‘username’)->textInput(),
    $form->field($model, ’email’)->textInput(),
    $form->field($model, ‘status’)->checkbox(array(‘label’=>’enable’)),
    ‘<div class="form-group">’,Html::submitButton($model->isNewRecord ? Yii::t(‘app’, ‘Create’) : Yii::t(‘app’, ‘Update’), [‘class’ => $model->isNewRecord ? ‘btn btn-success’ : ‘btn btn-primary’]);
    ActiveForm::end();
    echo'</div>’;[/code]

ตรวจฟอร์มด้วย HTML 5 / jQuery Validation Plugin

HTML 5 มี attribute อย่าง required ช่วยตรวจสอบฟอร์ม แต่มันยังไม่สมบูรณ์ เช่น ใช้ required กับกลุ่ม checkbox ไม่ได้ มันตรวจได้แค่เลือก checkbox ตัวนั้นๆเท่านั้น จะบังคับให้เลือก 1 ในตัวเลือกไม่ได้

ทำให้ต้องใช้เจคิวรี่อย่าง jQuery Validation Plugin ช่วย

[code language=”html”]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery Validation : html5 / inline</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<!– HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries –>
<!–[if lt IE 9]>
<script src="http://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="http://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]–>
</head>
<body>
<form action="validation.php" enctype="multipart/form-data" id="formA" method="post">
<div class="form-group">
<p>เครื่องปรุง</p>
<!– ใส่ required ใน input ตัวแรกก็พอ –>
<label>
<input type="checkbox" name="flavoring[]" value="1" required>
เกลือ</label>
<label>
<input type="checkbox" name="flavoring[]" value="2">
น้ำตาล</label>
<label>
<input type="checkbox" name="flavoring[]" value="3">
น้ำปลา</label>
<label>
<input type="checkbox" name="flavoring[]" value="4">
พริกป่น</label>
<!– แสดง error ตรงนี้ อย่าลืม class="error" –>
<label for="flavoring[]" class="error"></label>
</div>
<div class="form-inline">
<div class="form-group"><!– input text ธรรมดา –>
<label>สั่งวันที่
<input type="text" name="dateOrder" required data-rule-date="true">
</label>
</div>
<div class="form-group"><!– input date –>
<label>ส่งวันที่
<input type="date" name="dateDelivery" required>
</label>
</div>
</div>
<div class="form-inline">
<div class="form-group"><!– min and max length –>
<label>
<input type="text" id="sendto" name="sendto" required minlength="10" maxlength="50" data-rule-email="true">
Email</label>
</div>
<div class="form-group"> <!– data-rule-equalTo id sendto –>
<label>
<input type="email" id="sendtoSame" name="sendtoSame" required data-rule-equalTo="#sendto">
Email Confirm</label>
</div>
</div>
<div class="form-inline">
<div class="form-group">
<label>รับเฉพาะภาพ
<input type="file" name="image" accept="image/*">
</label>
</div>
<div class="form-group"><!– style input –>
<label class="btn btn-primary">รับแต่ .jpeg
<input type="file" name="jpeg" accept="image/jpeg" style="display:none;">
</label>
</div>
</div>
<div class="form-inline">
<div class="form-group">
<label>ข้าวเปล่า
<input type="text" name="rice" data-rule-number="true">
</label>
</div>
<div class="form-group">
<label>แคปหมู (ปลีก สั่งเป็นขีดได้ เช่น 0.5)
<input type="number" name="friedPorkSkin" step="0.1">
</label>
</div>
<div class="form-group"><!– custom message –>
<label>แคปหมู (ส่ง kg.)
<input type="number" name="friedPorkSkin" data-rule-digits="true" data-message-digits="ขายแต่เป็น KG ครับ">
</label>
</div>
</div>
<div class="form-group">
<p>เส้น</p>
<!– ใส่ required ใน input ตัวแรกก็พอ –>
<label>
<input type="radio" name="noodle" value="1" required>
เส้นหมี่</label>
<label>
<input type="radio" name="noodle" value="2">
เส้นเล็ก</label>
<label>
<input type="radio" name="noodle" value="3">
เส้นใหญ่</label>
<label>
<input type="radio" name="noodle" value="4">
เส้นหมี่</label>
<!– แสดง error ตรงนี้ อย่าลืม class="error" –>
<label for="noodle" class="error"></label>
</div>
<div class="form-group">
<label>ลวกนานมั๋ย
<input type="range" min="2" max="8" step="1">
</label>
</div>
<div class="form-inline">
<div class="form-group">
<label>เว็บบริษัท
<input type="text" name="officeUrl" data-rule-url="true">
</label>
</div>
<div class="form-group">
<label>เว็บส่วนตัว
<input type="url" name="blogUrl">
</label>
</div>
</div>
<input type="submit" value="Submit">
</form>
<script src="assets/jQuery/jquery.min.js"></script>
<script src="plus/jQuery/jquery-validation/jquery.validate.min.js"></script>
<script>
$(function()
{
$(‘#formA’).validate();
});
</script>
</body>
</html>
[/code]