Прикручиваем Autocomplete с изменяемой callback-функцией скрипта
Жил себе жил и тут вот резко захотелось прикрутить такую модно-прогрессивную штуку к нам в проект, как Autocomplete. И все бы хорошо, да вот есть у нас под строкой ввода поискослов два волшебных радиобатона. А переключают эти радиобатоны разные типы поиска. То-есть нажал на один, вводишь слово – выводится список слов выбранных с помощью одного скрипта, нажал другой и, о чудо, запрос убежал умчался к другому скрипту. Волшебство, магия и страшное колдунство, а делать-то надо, иначе не интересно жить:)
Поразмыслив решили сделать роут, куда будет обращаться скрипт, с передаваемым параметром. Для JS скрипта – это означало подменять все время адрес callback функции. По роуту мы передаем тип радиобатона, а потом в методе его разбираем. Соответственно value вышеозначенных radiobuttons должно быть названием типа.
Опишу, пожалуй, что ж я такого наделал, чтобы это все заработало. Есть такой замечательный виджет для Symfony, как sfWidgetFormJQueryAutocompleter. Вот от него и решил плясать. Понятно, что при каждом выборе радиобатона, должна меняться callback функция скрипта. Подменять адрес функции в стандартном автокомплитере не получалось, поэтому в панике и кипеше был срочно найден отличный аналог: Ajax Autocomplete for jQuery, от замечательного парня с не русской фамилией Tomas Kirda. Скачать можно не стесняясь прямо отсюда: http://www.devbridge.com/projects/autocomplete/jquery/.
Итак, мы скачали виджет, автокомплит, позакидывали по своим любимым папочкам. Ну, а теперь пора и начать писать кучу бесполезных символов. Сначала лезем в код самого autocomplete.js и внедряем в его недра, например после функции setOptions, нашу:
this.serviceUrl = option;
},
Первый шаг завершен, все радуются, девушки плачут, парни завидуют. Внезапно! Акт второй. Лезем в наш формфильтр и для генерации формы поиска приписываем нечто похожее:
{
$this->validatorSchema['search'] = new sfValidatorSchema(array(
'key_words' => new sfValidatorString(array('max_length' => 255, 'min_length' => '0', 'required' => false)),
'type' => new sfValidatorChoice(array('choices' => array('Type1' , 'Type2'), 'required' => false)),
));
$type_widget = new sfWidgetFormChoice(array(
'expanded' => true,
'choices' => array('Type1' => "Search first", 'Type2' => "Search second"),
'label' => ' '
), array('class' => 'search_type_checkbox'));
$this->setWidget('search', new nvWidgetFormSchema(
array(
'key_words' => new sfWidgetFormJQueryAutocompleterSimpleLsi(array(
'url' => $this->getOption('url'),
'config' => json_encode( array( 'multiple' => false)),
'class' => 'search_type_checkbox'
)),
'type' => $type_widget
),
array('validator_schema' => $this->validatorSchema['search'])
));
}
Надеюсь, тут все понятно. Не забываем при инициализации в action вашего фильтра, передать url на метод, который будет возвращать нам слова. Например это AjaxGetWords. И вот на него роут:
url: /words-ajax/:search_type
param: { module: publisher_search, action: AjaxGetWords, search_type:null }
Лезем в свой модуль и начинаем судорожно сотворять нужный метод:
{
$this->getResponse()->setContentType('application/json');
$q = $request->getParameter('query');
$limit = $request->getParameter('limit');
$stype = $request->getParameter('search_type');
$words = Doctrine_Core::getTable('Lexicon')->getAjaxWords($q, $limit, $stype);
return $this->renderText(json_encode($words));
}
Не забываем про модель. В нее мы передаем тип поиска (в зависимости от выбранного радиобатона), буквы, которые вбили (query) и количество возвращаемого результата.
Ну вот, осталось совсем немного. Еще чуть-чуть и будет вселенское счастье и поклеточный оргазм. Приведу целиком метод render класса sfWidgetFormJQueryAutocompleter :
{
$class = $this->getOption('class');
$url = $this->getOption('url');
return $this->renderTag('input', array_merge(array('type' => $this->getOption('type'), 'name' => $name, 'value' => $value), $attributes)).
sprintf(<<<EOF
<script type="text/javascript">
\$(document).ready(function()
{
top.type = '';
top.ac = '';
top.type = '%s/' + $('input.%s:checked').val();
top.ac = $('#%s').autocomplete(
{
serviceUrl:top.type,
noCache: false,
params: { limit:'10' } //aditional parameters
});
\$("input.%s").click(
function() {
top.type = '%s/' + $('input.%s:checked').val();
top.ac.disable();
top.ac.clearCache();
top.ac.setOptionsUrl(top.type);
top.ac.enable();
}
);
});
</script>
EOF
,
$url,
$class,
$this->generateId($name),
$class,
$url,
$class
);
die;
}
То-есть, при клике на один из радиобатонов вызываются функции автокомплитера в таком порядке: отключается, очищается кеш, устанавливаем урл (тот который мы передавали + тип), ну и, собственно, включаем обратно.
Вроде все, поставили, посмотрели, потыкали мышкой, порадовались. Самомнение подросло – можно идти довольным спать))