This script will help display the results of a search by keyword instantly via an ajax call. It can be applied to various search types. From user point of view it creates a good user experience and efficient working flow.
For instance we apply this search in products and services module and payroll module to quickly find the data to be reviewed or edited.
1) create the form
The search form is very simple and is made from a text field and <div> to display the results. We do not need to "submit" the form as the search results are returned by an ajax call.
/**
* @file
* Contains \Drupal\MyModule\Form\SearchProductsForm.
*/
namespace Drupal\MyModule\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides a form to search items
*/
class SearchProductsForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'MyModule_products_search';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['name'] = array(
'#type' => 'textfield',
'#id' => t('product-search-form'),
'#size' => 50,
'#attributes' => array('placeholder'=>t('Enter item code, barcode or name')),
'#attached' => ['library' => array('MyModule/MyModule.autocomplete')],
);
$form['list_items'] = array(
'#type' => 'item',
'#markup' => "",
);
return $form;
}
The form is located in mymodule/src/From.
You can notice that the library MyModule.autocomplete is attached to the search box. Let's create the library script now.
2) Library and autocomplete script
The library is declared in mymodule.libraries.yml file at the root of our custom module:
MyModule.autocomplete:
version: 1
css:
theme:
css/MyModule.css: {}
js:
js/MyModule_autocomplete.js: {}
dependencies:
- core/jquery
- core/drupal
The main reference in the library is MyModule_autocomplete.js file that manage the ajax call and display of results. This file will contain the following script:
(function ($, Drupal, drupalSettings) {
Drupal.behaviors.ek_products_autocomplete = {
attach: function (context, settings) {
jQuery('#product-search-form').keyup(function() {
var term = jQuery('#product-search-form').val();
jQuery.ajax({
dataType: "json",
url: drupalSettings.path.baseUrl + "autocomplete_ajax" ,
data: { option: "image", q: term },
success: function (data) {
var content = '';
var i = 0;
for(;data[i];) {
var editUrl = "" + data[i]['picture'] + "";
content += "" + editUrl + " " + data[i]['name'] + "
";
i++;
}
jQuery('#product-search-result').html(content);
}
});
});
}
};
})(jQuery, Drupal, drupalSettings);
Few comments here.
First the URL is pointing to "autocomplete_ajax"; this route must exist in your routing file (i.e mymodule.routing.yml):
MyModule_autocomplete_ajax:
path: '/autocomplete_ajax'
defaults:
_controller: '\Drupal\mymodule\Controller\ProductsController::autocomplete'
requirements:
_permission: 'view_products'
We include some class properties that will be defined in a file MyModule.css included in the library declaration above.
The result is returned as a json format from the controller but will be displayed as html format in the browser.
3) the Controller
The controller function (i.e autocomplete()) will query the database and return the results. In the simplified version below, we do not describe the actual database query that may vary from structure to structure. The result returned is pretty simple and in our case we return 3 elements when 'image' option is declared: picture, name (made of different information) and id.
public function autocomplete(Request $request) {
$term = $request->query->get('q');
$option = $request->query->get('option');
/*
* do the DB query here filtered by $term: $data
*/
$return = array();
while ($result = $data->fetchObject()) {
if (strlen($result->description) > 30) {
$desc = substr($result->description, 0, 30) . "...";
} else {
$desc = $result->description;
}
if($option == 'image') {
$line = [];
if ($result->uri) {
$pic = "";
} else {
$pic = '[]';
}
$line['picture'] = isset($pic) ? $pic : '';
$line['name'] = $result->id . " " . $result->itemcode . " " . $result->barcode . " " . $desc . " " .$result->supplier_code;
$line['id'] = $result->id;
$return[] = $line;
} else {
$return[] = $result->id . " " . $result->itemcode . " " . $result->barcode . " " . $desc . " " .$result->supplier_code;
}
}
return new JsonResponse($return);
}
4) Display
You can now create the routing to display your form and see the result in your browser. To call your search form, simply create a route to the form as in the example below (mymodule.routing.yml):
MyModule.searchForm:
path: '/mysearchform'
defaults:
_form: '\Drupal\mymodule\Form\SearchProductsForm'
requirements:
_access: 'TRUE'
Display can be customized within the css file. In our case, we define "thumbnail" properties to display the items images:
/* search display */
.product_thumbnail {
width: 40px;
height: 40px;
overflow: hidden;
vertical-align: middle;
margin-right: 10px;
border: solid 1px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
}
Feel free to add your comments or own experience.
Thank you.
Comments
D8 and ajax
Thank you, I wondered if you have any examples with a dropdown menu select.
thanks,
Add new comment