jQuery UI library provides different types of user interface widgets that are easy to implement on the page. One of the powerful widget is autocomplete.
Autocomplete simplifies user interaction by presenting a list of suggestions as users type into an input field. You can choose to pre-load this suggestion data on the client side during initialization or fetch it dynamically using AJAX.
In this tutorial, I show how you can add jQuery UI Autocomplete in CakePHP 4 and load MySQL database data using jQuery AJAX.
Table of Content
- Create a Table and Insert Data
- Update Database Configuration
- Creating the Model
- Creating the Controller
- Include jQuery and CSRF token
- Creating the Autocomplete Template
- Output
- Conclusion
1. Create a Table and Insert Data
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, `city` varchar(80) 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`, `city`) VALUES (1, 'yssyogesh', 'Yogesh singh', 'male', 'yogesh@makitweb.com', 'Bhopal'), (2, 'bsonarika', 'Sonarika Bhadoria', 'female', 'bsonarika@makitweb.com', 'Indore'), (3, 'sunil', 'Sunil singh', 'male', 'sunil@makitweb.com', 'Pune'), (4, 'vishal', 'Vishal Sahu', 'male', 'vishal@makitweb.com', 'Bhopal'), (5, 'jiten', 'jitendra singh', 'male', 'jitendra@makitweb.com', 'Delhi'), (6, 'shreya', 'Shreya joshi', 'female', 'shreya@makitweb.com', 'Indore'), (7, 'abhilash', 'Abhilash namdev', 'male', 'abhilash@makitweb.com', 'Pune'), (8, 'ekta', 'Ekta patidar', 'female', 'ekta@makitweb.com', 'Bhopal'), (9, 'deepak', 'Deepak singh', 'male', 'deepak@makitweb.com', 'Delhi'), (10, 'rohit', 'Rohit Kumar', 'male', 'rohit@makitweb.com', 'Bhopal'), (11, 'bhavna', 'Bhavna Mahajan', 'female', 'bhavna@makitweb.com', 'Indore'), (12, 'ajay', 'Ajay singh', 'male', 'ajay@makitweb.com', 'Delhi'), (13, 'mohit', 'Mohit', 'male', 'mohit@makitweb.com', 'Pune'), (14, 'akhilesh', 'Akhilesh Sahu', 'male', 'akhilesh@makitweb.com', 'Indore'), (15, 'ganesh', 'Ganesh', 'male', 'ganesh@makitweb.com', 'Pune'), (16, 'vijay', 'Vijay', 'male', 'vijay@makitweb.com', 'Delhi');
2. Update 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. Creating the Model
- To create the Users model, open your command line or terminal and navigate to your CakePHP application directory. Then, run the following command:
bin/cake bake model Users
- Executing this command will result in the creation of two files:
src/Model/Entity/User.php src/Model/Table/UsersTable.php
src/Model/Entity/User.php
This Entity class is where we define the fields that can be inserted or updated in the database. You have the flexibility to specify which fields are accessible for these operations. You can also choose to exclude certain fields by either removing them or setting them to ‘false’.
<?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, 'city' => true, ]; }
src/Model/Table/UsersTable.php
The Table class is crucial as it informs the ORM (Object-Relational Mapping) which database table to interact with and also defines validation rules for the fields.
<?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'); $validator ->scalar('city') ->maxLength('city', 80) ->requirePresence('city', 'create') ->notEmptyString('city'); 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. Creating the Controller
- Create a
AutcompleteController.php
file insrc/Controller/
folder. - Create
AutocompleteController
Class that extendsAppController
.
Create 2 method –
- index()
- getUserSuggestions() –
Managing jQuery UI AJAX requests and generating the autocomplete suggestion list using this method.
Extracting the search value from the POST request and assigning it to the $search
variable. By utilizing $this->getTableLocator()->get('Users')
, an instance of the Users
Table is created. If $search
is not empty, a condition is set to search the name
field using the LIKE operator.
It’s worth noting that a limit of 5 entries has been defined, although this value can be tailored to suit the specific requirements of your project.
To facilitate the response, an array named $data_arr
is established. The records retrieved from the query are looped through, and for each user, their ID is associated with the value
key, while their name is linked to the label
key within the $data_arr
array.
Return the formatted $data_arr
array in the JSON format.
<?php declare(strict_types=1); namespace App\Controller; class AutocompleteController extends AppController { public function index(){ } // Get Autocomplete Data public function getUserSuggestions(){ ## POST value $search = trim($this->request->getData()['search']); ## 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( 'value' => $user['id'], 'label' => $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 jQuery UI library in <head >
section –
<!-- jQuery UI CSS --> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/themes/smoothness/jquery-ui.css"> <!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <!-- jQuery UI JS --> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.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']) ?> <!-- jQuery UI CSS --> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/themes/smoothness/jquery-ui.css"> <!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <!-- jQuery UI JS --> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.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. Creating the Autocomplete Template
Create a directory named Autocomplete
within the templates/
location. Inside this directory, generate a file named index.php
at templates/Autocomplete/index.php
.
Create 2 input elements –
- The first input serves as the initializer for jQuery UI’s autocomplete functionality.
- The second input is designated to exhibit the value of the selected item, where in this case, the user ID is being showcased.
jQuery
- Extract the CSRF token from the
<meta>
tag and assign it to the variablecsrfToken
. - Initialize the autocomplete on
#searchuser
and configure three options:
These options are as follows:
- “source”: This option handles the data loading process.
- An AJAX POST request is send to the URL defined by
$this->Url->build(['controller' => 'Autocomplete','action' => 'getUserSuggestions'])
. - The “dataType” is set to ‘json’, and the typed input value is transmitted as data –
{ search: request.term }
. - The CSRF token is also included in the request headers –
{ 'X-CSRF-Token': csrfToken }
.
- An AJAX POST request is send to the URL defined by
- “select”: This event is triggered when an item is chosen from the suggestions list.
- The selected item’s label is stored in the
#searchuser
element. - The associated value (user ID) is stored in the
#userid
element.
- The selected item’s label is stored in the
- “focus”: This event activates when navigating through the list using keyboard arrow keys.
- Similar to “select”, the label and value of the chosen item are stored in the respective input elements.
<div class="row"> <div class="col-6"> <!-- --> <?php echo $this->Form->control('searchuser',['id'=>'searchuser','label'=>'Search User','class' => 'form-control']); echo $this->Form->control('userid',['id'=>'userid','label' => 'Selected User ID','class' => 'form-control']); ?> <!-- --> </div> </div> <!-- Script --> <script type="text/javascript"> // Read CSRF Token var csrfToken = $('meta[name="csrfToken"]').attr('content'); $(document).ready(function(){ // Initialize $( "#searchuser" ).autocomplete({ source: function( request, response ) { // Fetch data $.ajax({ url: "<?= $this->Url->build(['controller' => 'Autocomplete','action' => 'getUserSuggestions']) ?>", type: 'post', dataType: "json", data: { search: request.term }, headers:{ 'X-CSRF-Token': csrfToken }, success: function( data ) { response( data ); } }); }, select: function (event, ui) { // Set selection $('#searchuser').val(ui.item.label); // display the selected text $('#userid').val(ui.item.value); // save selected id to input return false; }, focus: function(event, ui){ $( "#searchuser" ).val( ui.item.label ); $( "#userid" ).val( ui.item.value ); return false; }, }); }); </script>
7. Output
8. Conclusion
jQuery UI autocomplete can greatly enhance the search functionality of your web pages it makes them more user-friendly and efficient. Users can easily find what they are looking for by simply typing a few characters, and the real-time search suggestions can significantly improve their experience.
I hope this tutorial has been helpful in getting you started.
You can also checkout this tutorial if you want to know auto-populate dropdown using jQuery AJAX in CakePHP 4.
If you found this tutorial helpful then don't forget to share.