ในตัวอย่างนี้จะเป็นใช้ widget Dependent Dropdown Widget ของ krajee
ถามว่าตัวนี้มันดียังไง? อย่างแรกเพราะมันสามารถใช้งานได้ง่ายๆ สามารถสร้างให้เป็นตัวเลือกสับย่อยๆ เข้าไปได้หลายๆ ตัว
อย่างที่สองก็คือ เพียงแค่เราสร้าง action ตามที่ Widget กำหนดโดยที่ไม่ต้องไปยุ่งกับ javascript มากมายเพราะ Widget ทำไว้ให้หมดแล้ว เรามีหน้าที่ config
ให้มันรู้ว่า action ใหนที่จะไปดึงข้อมูลอำเภอ action ใหนจะไปดึงข้อมูลตำบล
ถ้าง่ายขนาดนั้น งั้นเรามาลองกัน!
หลักการทำงาน
เราจะทำการสร้าง DropdownList ไวัทั้งหมด 3 ตัว ตัวแรก จังหวัดจะเป็น DropdownList ธรรมดา และดึงข้อมูลจังหวัดมาแสดง ส่วนอีก 2 ตัวที่เหลือ จะทำการเรียกข้อมูลผ่าน Request ajax เมื่อมีการคลิกเลือกอำเภอ และตำบลตามลำดับ
ขั้นตอนแรก ตัวเลือกจังหวัด เราจะทำการใช้ dropdownList แบบธรรมดาและคิวรีข้อมูลขึ้นมาเพื่อกำหนดค่าให้กับ dropdownList จังหวัดเพื่อแสดงผล
เมื่อมีการคลิกเลือกจังหวัด ก็จะทำการส่งข้อมูลรหัสจังหวัด ที่เลือกไปที่
actionGetAmphur()
เพื่อทำการค้นหาอำเภอ และจะส่งข้อมูลกลับมาในรูปแบบjson
ไปให้ widget และนำไปแสดงผลที่ DropdownList อำเภอเมื่อทำการเลือกอำเภอ ก็จะทำการส่งข้อมูลรหัสอำเภอที่เลือก ไปที่
actionGetDistrict()
เพื่อทำการค้นหาข้อมูลตำบล และส่งข้อมูลกลับให้ widget ในรูปแบบของjson
เพื่อนำไปแสดงผลต่อที่ dropdownList ตำบล
ตัว Widget สามารถสร้างตัวเลือกสับย่อยๆ เข้าไปอีกได้ อาจจะมากกว่า 3 ก็ได้ ก็แล้วแต่กรณีที่เราจะสามารถนำไปใช้ เช่น ข้อมูลหมวดหมู่ประเภทสินค้า
การติดตั้ง Widget
ในตัวอย่างนี้เราใช้ Widget Dependent Dropdown Widget ซึ่งจะเป็นเพ็คเก็จที่รวมอยุ่ใน Yii2 Widgets ซึ่งจะมี widget อื่นๆ อีกหลายตัว
widget นี้ใช้งานร่วมกับ yiisoft/yii2-bootstrap แต่ส่วนใหญ่ก็ติดตั้งมาพร้อมอยู่แล้ว
รันคำสั่งเพื่อทำการติดตั้ง
composer require kartik-v/yii2-widgets "*"
หรือเพิ่ม
"kartik-v/yii2-widgets": "*"
ที่แท็ค require ในไฟล์ composer.json จากนั้น composer update
สร้าง Model
ทำการสร้าง gii Model ให้ครบทั้ง 3 ตารางคือ province, amphur, district
ข้อมูล จังหวัด,อำเภอ,ตำบล ดูได้ที่นี่
เรียกใช้งานใน Form
ทำการเรียกใช้งาน model ทั้งหมด เรียก ArrayHelper และ DepDrop
<?php
use yii\helpers\Html;
use yii\helpers\Url;
use yii\helpers\ArrayHelper;
use yii\bootstrap\ActiveForm;
use kartik\widgets\DepDrop;
use app\models\Province;
use app\models\Amphur;
use app\models\District;
สร้าง DropdownList จังหวัด
ในการเรียกข้อมูลเพื่อมาใช้กับ DropdownList โดยเรียกผ่าน model นั้นเราจะเป็นจะต้องใช้ ArrayHelper
เพื่อสร้าง array ที่สามารถใช้กับ dropdownList ได้ โดยใช้ ArrayHelper::map("model","ชื่อฟิวด์รหัส","ชื่อฟิวด์ที่เป็นข้อความ")
ArrayHelper::map(Province::find()->all(),
'PROVINCE_ID',
'PROVINCE_NAME')
จากนั้นเราจะได้ Array กลับมาในรูปแบบ
array(
'28'=>'ขอนแก่น',
'29'=>'มาหาสารคาม',
.......
)
เมื่อได้ข้อมูลแล้วเราก็เรียกใช้งานและทำการตั้งชื่อให้กับ DropdownList จังหวัดชื่อ ddl-province
<?= $form->field($model, 'province')->dropdownList(
ArrayHelper::map(Province::find()->all(),
'PROVINCE_ID',
'PROVINCE_NAME'),
[
'id'=>'ddl-province',
'prompt'=>'เลือกจังหวัด'
]); ?>
ซึ่งก็จะเห็นว่าเราสามารถเลือกจังหวัดได้แล้ว
ตอนนี้เราตั้ง id dropdownlist
ddl-province
สร้าง DropdownList อำเภอ
เราจะใช้ widget DepDrop
เพื่อทำการสร้าง dropdownlist และกำหนดชื่อเป็น ddl-amphur
ซึ่งจะเป็นอำเภอว่างๆ ไว้เพื่อรอให้มีการส่งข้อมูลมา ซึ่งตัว dropdownList อำเภอจะมีการกำหนดค่า 3 ตัวคือ
- data
ตรงนี้เอาไว้ใช้รับมูลมาแสดงในกรณี update
เพื่อให้แสดงค่าว่าเราได้เลือกอำเภอใหนแต่ตอนนี้ใส่เป็น array ว่างๆ ไว้ก่อน
- depends
เป็นการระบุชื่อ dropdownlist จังหวัดเพื่อจับ event เมื่อมีการคลิกเลือกจังหวัด
- url
เป็นการระบุชื่อ action ที่จะให้ dropdownlist ไปเรียกข้อมูลอำเภอ
โดยกำหนดค่าดังนี้
<?= $form->field($model, 'amphur')->widget(DepDrop::classname(), [
'options'=>['id'=>'ddl-amphur'],
'data'=> [],
'pluginOptions'=>[
'depends'=>['ddl-province'],
'placeholder'=>'เลือกอำเภอ...',
'url'=>Url::to(['/employee/get-amphur'])
]
]); ?>
สร้าง DropdownList ตำบล
การกำหนดค่าจะคล้ายกับ อำเภอ แต่ต่างกันที่ depends
จะมีการกำหนดค่าชื่อไว้สองตัวคือ ชือ dropdownlist จังหวัดและ dropdownlist อำเภอ
<?= $form->field($model, 'district')->widget(DepDrop::classname(), [
'data' =>[],
'pluginOptions'=>[
'depends'=>['ddl-province', 'ddl-amphur'],
'placeholder'=>'เลือกตำบล...',
'url'=>Url::to(['/employee/get-district'])
]
]); ?>
เราจะได้ form แบบนี้
แต่ตอนนี้จะยังใช้งานไม่ได้เพราะเรายังไม่ได้สร้าง action เพื่อรองรับการค้นข้อมูลและส่งข้อมูลให้กับ dropdownlist
สร้าง Action เพื่อรองรับการคลิกเลือกจังหวัดและอำเภอ
เราจะทำการสร้าง action ไว้ที่ controllers/EmployeeController.php action แรกจะเป็น actionGetAmphur() ตรงนี้จะรองรับการคลิกเลือกจังหวัดและส่งค่าอำเภอกลับไปให้กับ dropdownlist อำเภอเป็น json
Use
use Yii;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\web\UploadedFile;
use yii\filters\VerbFilter;
use yii\helpers\Json;
use yii\helpers\ArrayHelper;
use yii\helpers\BaseFileHelper;
use app\models\Province;
use app\models\Amphur;
use app\models\District;
use app\models\Uploads;
use yii\helpers\Html;
use yii\helpers\Url;
เพิ่ม function
public function actionGetAmphur() {
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$province_id = $parents[0];
$out = $this->getAmphur($province_id);
echo Json::encode(['output'=>$out, 'selected'=>'']);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
action ที่สองจะเป็น actionGetDistrict() ตรงนี้จะรองรับการคลิกเลือกอำเภอและ ส่งค่าตำบลกลับไปให้กับ dropdownlist ตำบลเป็น json
public function actionGetDistrict() {
$out = [];
if (isset($_POST['depdrop_parents'])) {
$ids = $_POST['depdrop_parents'];
$province_id = empty($ids[0]) ? null : $ids[0];
$amphur_id = empty($ids[1]) ? null : $ids[1];
if ($province_id != null) {
$data = $this->getDistrict($amphur_id);
echo Json::encode(['output'=>$data, 'selected'=>'']);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
action actionGetAmphur() ข้างใน function จะมีการเรียกใช้งาน getAmphur($id) และส่งค่ารหัส จังหวัดมาให้ เพื่อนำไปค้นที่ model Amphur
protected function getAmphur($id){
$datas = Amphur::find()->where(['PROVINCE_ID'=>$id])->all();
return $this->MapData($datas,'AMPHUR_ID','AMPHUR_NAME');
}
action actionGetDistrict() ข้างใน function จะมีการเรียกใช้งาน getDistrict($id) และส่งค่ารหัส อำเภอมาให้ เพื่อนำไปค้นที่ model District
protected function getDistrict($id){
$datas = District::find()->where(['AMPHUR_ID'=>$id])->all();
return $this->MapData($datas,'DISTRICT_ID','DISTRICT_NAME');
}
และ function getAmphur()
และ getDistrict()
จะทำการเรียก MapData
เพื่อทำการนำค่าที่ได้สร้าง array ในรูปแบบ ['id'=>'','name'=>'']
เพราะตัว widget DepDrop ได้ระบบให้สร้างตาม format นี้
protected function MapData($datas,$fieldId,$fieldName){
$obj = [];
foreach ($datas as $key => $value) {
array_push($obj, ['id'=>$value->{$fieldId},'name'=>$value->{$fieldName}]);
}
return $obj;
}
ทดลองใช้งาน
เลือกจังหวัด
เลือกอำเภอ
เลือกตำบล
กรณี Update
ในกรณีอัพเดท เราจำเป็นจะต้องนำค่าอำเภอและค่าตำบล ที่ได้บันทึกไว้ไปค้นข้อมูล เพื่อนำมาแสดงผล ว่าเคยเลือกอะไรไปแล้ว
ไปที่ actionUpdate() ทำการเรียกฟังชั่น getAmphur(), getDistrict() เพื่อดึงข้อมูลไปแสดงที่ dropdownlist อำเภอและตำบล และให้มันเลือกที่รายการที่เราเคยเลือกไว้ก่อนหน้านี้
public function actionUpdate($id)
{
$model = $this->findModel($id);
$amphur = ArrayHelper::map($this->getAmphur($model->province),'id','name');
$district = ArrayHelper::map($this->getDistrict($model->amphur),'id','name');
//..........
return $this->render('update', [
'model' => $model,
'amphur'=> $amphur,
'district' =>$district
]);
}
และที่ ไฟล์ views/employee/update.php อย่างลืมส่งค่าไปให้ฟอร์มด้วย
php
<?= $this->render('_form', [
'model' => $model,
'amphur'=> $amphur,
'district' =>$district
]) ?>
จากนั้นเปลี่ยนค่า data
ใน dropdownlist อำเภอและตำบลเป็นค่าที่ส่งมาซึ่งในตอนแรกเรากำหนดค่าเป็น array ว่างๆ ไว้
<?= $form->field($model, 'amphur')->widget(DepDrop::classname(), [
'options'=>['id'=>'ddl-amphur'],
'data'=> $amphur, //<---------
'pluginOptions'=>[
'depends'=>['ddl-province'],
'placeholder'=>'เลือกอำเภอ...',
'url'=>Url::to(['/employee/get-amphur'])
]
]); ?>
<?= $form->field($model, 'district')->widget(DepDrop::classname(), [
'data' =>$district, //<---------
'pluginOptions'=>[
'depends'=>['ddl-province', 'ddl-amphur'],
'placeholder'=>'เลือกตำบล...',
'url'=>Url::to(['/employee/get-district'])
]
]); ?>
เหลืออีกอย่าง อย่าลืมสร้างตัวแปร array ว่างๆ ให้กับ /views/employee/create.php เพื่อในตอน create จะได้ไม่ error ตัวแปรไม่ได้ถูกสร้าง
<?= $this->render('_form', [
'model' => $model,
'amphur'=> [],
'district' =>[],
]) ?>
ลองใช้กันดูนะครับ ดาวน์โหลด source code ทั้งหมด ได้ทีนี่
หรือดูเฉพาะไฟล์ได้ที่นี่
- Controller Controller
- view _form.php