Select2 is a popular jQuery plugin that makes the default HTML select element a lot more functional. With <select > element it is not possible to search on the list and add an image to an option, or customize the UI.
Select2 allows the loading of data dynamically from the server using AJAX when the user clicks on an element or search.
In this tutorial, I show how you can add select2 in CakePHP 4 and load data dynamically from the MySQL database using jQuery AJAX.
Table of Content
- Create a Table and Insert records
- Database Configuration
- Create a Model
- Create a Controller
- Include jQuery and CSRF token
- Create Template
- Output
- Conclusion
1. Create a Table and Insert records
In the example, I am using users
Tables. It has the following structure and data –
CREATE TABLE `users` ( `id` int(11) NOT NULL, `username` varchar(50) NOT NULL, `name` varchar(60) NOT NULL, `gender` varchar(10) NOT NULL, `email` varchar(60) NOT NULL ); ALTER TABLE `users` ADD PRIMARY KEY (`id`); ALTER TABLE `users` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; INSERT INTO `users` (`id`, `username`, `name`, `gender`, `email`) VALUES (1, 'yssyogesh', 'Yogesh singh', 'male', 'yogesh@makitweb.com'), (2, 'bsonarika', 'Sonarika Bhadoria', 'female', 'bsonarika@makitweb.com'), (3, 'sunil', 'Sunil singh', 'male', 'sunil@makitweb.com'), (4, 'vishal', 'Vishal Sahu', 'male', 'vishal@makitweb.com'), (5, 'jiten', 'jitendra singh', 'male', 'jitendra@makitweb.com'), (6, 'shreya', 'Shreya joshi', 'female', 'shreya@makitweb.com'), (7, 'abhilash', 'Abhilash namdev', 'male', 'abhilash@makitweb.com'), (8, 'ekta', 'Ekta patidar', 'female', 'ekta@makitweb.com'), (9, 'deepak', 'Deepak singh', 'male', 'deepak@makitweb.com'), (10, 'rohit', 'Rohit Kumar', 'male', 'rohit@makitweb.com'), (11, 'bhavna', 'Bhavna Mahajan', 'female', 'bhavna@makitweb.com'), (12, 'ajay', 'Ajay singh', 'male', 'ajay@makitweb.com'), (13, 'mohit', 'Mohit', 'male', 'mohit@makitweb.com'), (14, 'akhilesh', 'Akhilesh Sahu', 'male', 'akhilesh@makitweb.com'), (15, 'ganesh', 'Ganesh', 'male', 'ganesh@makitweb.com'), (16, 'vijay', 'Vijay', 'male', 'vijay@makitweb.com');
2. Database Configuration
- Open
config/app_local.php
file. - Specify your database configuration details in the
Datasources
default
.
'Datasources' => [ 'default' => [ 'host' => '127.0.0.1', /* * CakePHP will use the default DB port based on the driver selected * MySQL on MAMP uses port 8889, MAMP users will want to uncomment * the following line and set the port accordingly */ //'port' => 'non_standard_port_number', 'username' => 'root', 'password' => 'root', 'database' => 'cakephp4', /* * If not using the default 'public' schema with the PostgreSQL driver * set it here. */ //'schema' => 'myapp', /* * You can use a DSN string to set the entire configuration */ 'url' => env('DATABASE_URL', null), ], /* * The test connection is used during the test suite. */ 'test' => [ 'host' => 'localhost', //'port' => 'non_standard_port_number', 'username' => 'my_app', 'password' => 'secret', 'database' => 'test_myapp', //'schema' => 'myapp', 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'), ], ],
3. Create a Model
- Create
Users
Model.
bin/cake bake model Users
- This will create 2 files –
src/Model/Entity/User.php src/Model/Table/UsersTable.php
src/Model/Entity/User.php
In this Entity class specify field names that you want to allow insertion and updation. You can either remove the field name or set it to false
if you don’t want to allow.
Full Code
<?php declare(strict_types=1); namespace App\Model\Entity; use Cake\ORM\Entity; class User extends Entity { protected $_accessible = [ 'username' => true, 'name' => true, 'gender' => true, 'email' => true, ]; }
src/Model/Table/UsersTable.php
This Table class tells ORM which table needs to use and defines validation rules for the fields.
Full Code
<?php declare(strict_types=1); namespace App\Model\Table; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; class UsersTable extends Table { public function initialize(array $config): void { parent::initialize($config); $this->setTable('users'); $this->setDisplayField('name'); $this->setPrimaryKey('id'); } public function validationDefault(Validator $validator): Validator { $validator ->scalar('username') ->maxLength('username', 50) ->requirePresence('username', 'create') ->notEmptyString('username'); $validator ->scalar('name') ->maxLength('name', 60) ->requirePresence('name', 'create') ->notEmptyString('name'); $validator ->scalar('gender') ->maxLength('gender', 10) ->requirePresence('gender', 'create') ->notEmptyString('gender'); $validator ->email('email') ->requirePresence('email', 'create') ->notEmptyString('email'); return $validator; } public function buildRules(RulesChecker $rules): RulesChecker { $rules->add($rules->isUnique(['username']), ['errorField' => 'username']); $rules->add($rules->isUnique(['email']), ['errorField' => 'email']); return $rules; } }
4. Create a Controller
- Create a
Select2Controller.php
file insrc/Controller/
folder. - Create
Select2Controller
Class that extendsAppController
.
Create 2 method –
- index()
- getUserList() – Using this handle AJAX request and return select2 data.
If searchTerm
is POST then assign its value to $search
variable. Fetch records from the users
table and set the WHERE
clause to search on name
field if $search
value is not empty.
I set a limit of 5 that you either remove or adjust its value according to your requirement.
Loop on the fetched records and initialize $data_arr
Array. Store $user['id']
to id
key and $user['name']
to text
key.
NOTE – Key name must be
id
andtext
otherwise data will not get loaded properly in the select2 element.
Return $data_arr
Array in JSON format.
Full Code
<?php declare(strict_types=1); namespace App\Controller; class Select2Controller extends AppController { public function index(){ } // Get Select2 Data public function getUserList(){ // POST value $search = ""; if(isset($this->request->getData()['searchTerm'])){ $search = trim($this->request->getData()['searchTerm']); } ## Fetch users $USERS = $this->getTableLocator()->get('Users'); $query = $USERS->find('all'); // Search value if(!empty($search)){ $query->where(['name LIKE' => "%".$search."%"]); } $query->order(['name' => 'ASC']); $query->limit(5); $usersList = $query->toArray(); $data_arr = array(); foreach($usersList as $user){ $data_arr[] = array( 'id' => $user['id'], 'text' => $user['name'] ); } echo json_encode($data_arr); die; } }
5. Include jQuery and CSRF token
I am including JS libraries and CSRF token on templates/layout/default.php
file.
Stored CSRF token in <meta >
tag –
<?= $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken')); ?>
Include jQuery and Select2 library in <head >
section –
<!-- Select2 CSS --> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> <!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <!-- Select2 JS --> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
Full Code
<?php $cakeDescription = 'CakePHP: the rapid development php framework'; ?> <!DOCTYPE html> <html> <head> <?= $this->Html->charset() ?> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- CSRF Token --> <?= $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken')); ?> <title> <?= $cakeDescription ?>: <?= $this->fetch('title') ?> </title> <?= $this->Html->meta('icon') ?> <link href="https://fonts.googleapis.com/css?family=Raleway:400,700" rel="stylesheet"> <?= $this->Html->css(['normalize.min', 'milligram.min', 'cake']) ?> <!-- Select2 CSS --> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> <!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <!-- Select2 JS --> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> <?= $this->fetch('meta') ?> <?= $this->fetch('css') ?> <?= $this->fetch('script') ?> </head> <body> <nav class="top-nav"> <div class="top-nav-title"> <a href="<?= $this->Url->build('/') ?>"><span>Cake</span>PHP</a> </div> <div class="top-nav-links"> <a target="_blank" rel="noopener" href="https://book.cakephp.org/4/">Documentation</a> <a target="_blank" rel="noopener" href="https://api.cakephp.org/">API</a> </div> </nav> <main class="main"> <div class="container"> <?= $this->Flash->render() ?> <?= $this->fetch('content') ?> </div> </main> <footer> </footer> </body> </html>
6. Create Template
Create Select2
folder in templates/
location. In the Select2
folder create index.php
file – templates/Select2/index.php
.
Create 3 HTML elements –
<select >
element to initialize select2. Added no option.- A textbox to display selected item value.
- Button to read selected value when gets clicked.
jQuery
Read CSRF token from the <meta >
tag and assign it to csrfToken
variable.
Initialize Select2 –
Initialize select2()
on #seluser
, use ajax
option to load option list.
Send AJAX POST request to $this->Url->build(['controller' => 'Select2','action' => 'getUserList'])
, set dataType: 'json'
, pass CSRF token using headers – 'X-CSRF-Token': csrfToken
, pass the typed value as data – searchTerm: params.term
.
With processResults
handle AJAX successful callback response. Pass response
to results
and return.
Read selected value from Select2 –
Define click
event on #btnview
button. Read selected value using val()
on <select >
element. Pass selected value to #userid
textbox for displaying.
Full Code
<div class="row"> <div class="col-6"> <!-- User --> <div class="input" style="margin-bottom: 15px;"> <label for='seluser'>User</label> <?php echo $this->Form->select( 'seluser', [], [ 'id' => 'seluser', 'empty' => '-- Select User --', 'style' => 'width: 250px;' ] ); ?> </div> <!-- Selected User ID --> <?php echo $this->Form->control('userid',['id'=>'userid','label' => 'Selected User ID','class' => 'form-control']); echo $this->Form->button('view', ['type' => 'button','id'=>'btnview','value'=>"View Selected User ID"]); ?> <!-- --> </div> </div> <!-- Script --> <script type="text/javascript"> // Read CSRF Token var csrfToken = $('meta[name="csrfToken"]').attr('content'); $(document).ready(function(){ // Select2 $("#seluser").select2({ ajax: { url: "<?= $this->Url->build(['controller' => 'Select2','action' => 'getUserList']) ?>", type: "post", dataType: 'json', delay: 250, headers:{ 'X-CSRF-Token': csrfToken }, data: function (params) { return { searchTerm: params.term // search term }; }, processResults: function (response) { return { results: response }; }, cache: true } }); // Read selected value $('#btnview').click(function(){ var userid = $('#seluser').val(); $('#userid').val(userid); }); }); </script>
7. Output
8. Conclusion
You can easily implement select2 on your project by following the above steps and providing users with an improved user interface that is both efficient and user-friendly.
In the example, I only passed typed search value as data but you can also pass additional data with it.
You can also check other jQuery AJAX tutorials in CakePHP 4 –
If you found this tutorial helpful then don't forget to share.