ในตัวอย่างนี้จะเป็นใช้ 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 [Dependent Dropdown 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
ทำการสร้าง gii Model ให้ครบทั้ง 3 ตารางคือ province, amphur, district
ข้อมูล จังหวัด,อำเภอ,ตำบล ดูได้ที่นี่
ทำการเรียกใช้งาน model ทั้งหมด เรียก ArrayHelper และ DepDrop
<?php
use app\models\Province;
use app\models\Amphur;
use app\models\District;
use yii\helpers\ArrayHelper;
use kartik\widgets\DepDrop;ในการเรียกข้อมูลเพื่อมาใช้กับ 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
เราจะใช้ 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'])
]
]); ?>การกำหนดค่าจะคล้ายกับ อำเภอ แต่ต่างกันที่ 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 ไว้ที่ controllers/EmployeeController.php action แรกจะเป็น actionGetAmphur() ตรงนี้จะรองรับการคลิกเลือกจังหวัดและส่งค่าอำเภอกลับไปให้กับ dropdownlist อำเภอเป็น json
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;
}เลือกอำเภอ
เลือกตำบล
ในกรณีอัพเดท เราจำเป็นจะต้องนำค่าอำเภอและค่าตำบล ที่ได้บันทึกไว้ไปค้นข้อมูล เพื่อนำมาแสดงผล ว่าเคยเลือกอะไรไปแล้ว
ไปที่ 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 อย่างลืมส่งค่าไปให้ฟอร์มด้วย
<?= $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 ได้ทีนี่






