Skip to content

Instantly share code, notes, and snippets.

@chalasr
Last active March 24, 2022 11:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chalasr/5c27ae64dc596967f18a to your computer and use it in GitHub Desktop.
Save chalasr/5c27ae64dc596967f18a to your computer and use it in GitHub Desktop.
Autocompletion AJAX for SonataAdminBundle $datagridMapper filters
{% extends 'SonataAdminBundle:CRUD:base_list.html.twig' %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
$(document).ready(function(){
var MIN_LENGTH = 3;
var datalistFirst = $('<ul class="select2-results autoResults" role="listbox" id="datalist_filter_firstname_value"></ul>');
var datalistName = $('<ul class="select2-results autoResults" role="listbox" id="datalist_filter_name_value"></ul>');
$('#filter_name_value').after(datalistName);
$('#filter_firstname_value').after(datalistFirst);
var results = [];
$('input').keydown(function(event){
var idAttr = $(this).attr('id');
if((event.keyCode == 13) && (results.length > 0)) {
event.preventDefault();
var choice = $('.'+idAttr+'-selected').text();
if(choice != ''){
$('#'+idAttr).val(choice);
$('.select2-results').empty();
}
}else if((event.keyCode) == 40){
var chosen = $('.'+idAttr+'-selected').attr('data-item');
var next = Number(chosen)+1;
if(next < results.length){
var nextLi = $('#datalist_'+idAttr+' li[data-item="'+next+'"]');
$('.'+idAttr+'-selected').removeClass(idAttr+'-selected');
nextLi.addClass(idAttr+'-selected');
$("#datalist_"+idAttr).scrollTo($('.'+idAttr+'-selected'));
}
}else if((event.keyCode == 38)){
var chosen = $('.'+idAttr+'-selected').attr('data-item');
var next = Number(chosen)-1;
if(next >= 0){
var nextLi = $('#datalist_'+idAttr+' li[data-item="'+next+'"]');
$('.'+idAttr+'-selected').removeClass(idAttr+'-selected');
nextLi.addClass(idAttr+'-selected');
$("#datalist_"+idAttr).scrollTo($('.'+idAttr+'-selected'));
}
}
});
$("input").keyup(function(event) {
var idAttr = $(this).attr('id');
if(idAttr == 'filter_name_value' || idAttr == 'filter_firstname_value'){
var keyword = $(this).val();
if((event.keyCode != 40) && (event.keyCode != 38)){
results = [];
$('#datalist_'+idAttr).empty();
if (keyword.length >= MIN_LENGTH && (event.keyCode != 13)) {
var where = idAttr == 'filter_name_value' ? $('#filter_firstname_value').val() : $('#filter_name_value').val();
var dataObj = { keyword: keyword, field: idAttr, where: where };
$.post("/admin/application/personne/personne/autocomplete", dataObj)
.done(function(data) {
data.forEach(function(item){
var content = idAttr == 'filter_name_value' ? item.name : item.firstname;
if(results.indexOf(content) == -1){
results.push(content);
var indexItem = results.indexOf(content);
var option = '<li id="'+content+'" data-name="'+idAttr+'" data-item="'+indexItem+'" class="select2-no-results result">'+content+'</li>';
$('#datalist_'+idAttr).append(option);
$('#datalist_'+idAttr).show(); 
$('.result').click(function(){
var goodInput = $(this).attr('data-name');
var newName = $(this).attr('id');
$('#'+goodInput).val(newName);
$('.select2-results').empty();
results = [];
})
}
})
if(results.length > 0){
var firstChoice = $('#datalist_'+idAttr+' li:first');
firstChoice.addClass(idAttr+'-selected');
}
});
}else if(keyword.length < 3){
$('#datalist_'+idAttr).empty();
results = [];
}
}
}
});
});
</script>
{% endblock %}
#datalist_filter_name_value li:hover{
cursor: pointer;
}
#datalist_filter_name_value li{
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 1px solid #757575;
background: rgba(244, 244, 244, 0.9);
font-weight: 600;
}
#datalist_filter_firstname_value li:hover{
cursor: pointer;
}
#datalist_filter_firstname_value li{
padding-top: 5px;
padding-bottom: 5px;
background: rgba(244, 244, 244, 0.9);
font-weight: 600;
}
.autoResults{
z-index: 3;
position: absolute;
max-height: 125px;
width: 15%;
}
.filter_firstname_value-selected{
background: #757575!important;
}
.filter_name_value-selected{
background: #757575!important;
}
<?php
namespace Application\PersonneBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class PersonneAdminController extends Controller
{
public function autocompleteAction(){
$request = new Request();
$request = $request->createFromGlobals();
$keyword = $request->request->get('keyword');
$field = $request->request->get('field');
$where = $request->request->get('where');
$property = explode('_', $field)[1];
$whereProperty = $property == 'name' ? 'firstname' : 'name';
$repository = $this->getDoctrine()
->getRepository('ApplicationPersonneBundle:Personne');
$query = $repository->createQueryBuilder('p')
->select('p.'.$property)
->where('p.'.$property.' LIKE :word')
->andWhere('p.'.$whereProperty.' LIKE :where')
->setParameter('word', '%'.$keyword.'%')
->setParameter('where', '%'.$where.'%')
->getQuery();
$data = $query->getResult();
return new JsonResponse($data);
}
}

Autocompletion for SonataAdminBundle $datagridMapper filters

Full (php + javascript) method on admin class. Just an override of SonataAdminBundle:CRUD:list.html.twig with custom AJAX method for add autocompletion to filters on properties name and firstname of my Admin Class.

@webdevilopers
Copy link

Nice work! Though there is a lot of javascript code going on! ;) I guess it would have been easier to get some of the core select2 code from the autocompleter.

Maybe we're lucky and it will become a feature:
sonata-project/SonataAdminBundle#3172

Came from:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment