Yii PHP фреймворк: создаем поле с автозаполнением

16 мая, 2010
yii php framework autocomplete

Приветствую всех!

Сегодня я покажу небольшой пример использования виджета CAutoComplete из фреймворка Yii. Как несложно догадаться, он создаёт текстовое поле, под которым может появляться список с вариантами подстановок.

Принцип создания такого поля довольно прост. На странице нужно поместить обычное текстовое поле и назначить событию onKeyUp обработчик, который будет отправлять AJAX запросы серверу. В этих запросах нужно передавать введённый посетителем текст. Сервер ищет совпадения с этим текстом в БД и возвращает результат браузеру. JavaScript обработчик создаёт список с вариантами, полученными от сервера, и показывает его под полем.

Как видите, алгоритм несложный, но рутинной работы много.

Теперь, давайте разберёмся, что сделает за вас виджет, а что придётся делать вам.

Для работы виджет использует плагин Autocomplete библиотеки jQuery, т.е. писать JS код от вас не потребуется (если, конечно, вы не хотите изменить стандартное поведение плагина).

Кроме того, виджет создаст текстовое поле и подключит все необходимые JS и CSS файлы. Вам нужно будет только указать некоторые настройки.

Основная часть вашей работы будет заключаться в написании метода, выполняющего обработку запросов и поиск данных в базе.

Теперь рассмотрим пример.

Допустим, у нас есть база данных с названиями стран. Таблица называется countries, а поле, в котором хранятся названия – c_name.

Создаём для этой таблицы модель.

yiic shell
model countries

Примечание. Тут я предполагаю, что у вас создано веб приложение и настроено подключение к базе данных.

Теперь нужно создать текстовое поле. CAutoComplete – это обычный виджет, поэтому поместить его можно где угодно. Если хотите, чтобы поле выводилось на отдельной странице – добавляйте его в соответствующее представление, хотите показывать на каждой странице – добавляйте в макет (layout).

Код вставки виджета выглядит так.

$this->widget('CAutoComplete',
	array(
		'model'=>'countries',
		'name'=>'country',
		'url'=>array('countries/autocomplete'),
		'minChars'=>2,
	)
);

Во втором параметре необходимо передать массив с параметрами. Обязательными являются первые два.
model – имя модели.
name – атрибут name текстового поля.
url – адрес скрипта, который будет обрабатывать AJAX запросы.
minChars – минимальное количество символов, при котором выполняется отправка запроса.

Естественно, это не все параметры. Подробный их перечень вы найдете на странице документации.

По мере ввода текста серверному скрипту будут отправляться AJAX запросы вида:

index.php?r=countries/autocomplete&q=%D0%B0%D0%BB&limit=10&timestamp=1273944702297

В параметре q передаётся введённый посетителем текст, а в параметре limit – максимальное количество подстановок.

Рассмотрим метод, выполняющий обработку этого запроса.

public function actionAutoComplete() {

	if (isset($_GET['q'])) {

		$criteria = new CDbCriteria;
		$criteria->condition = 'c_name LIKE :country';
		$criteria->params = array(':country'=>$_GET['q'].'%');

		if (isset($_GET['limit']) && is_numeric($_GET['limit'])) {
			$criteria->limit = $_GET['limit'];
		}

		$countries = countries::model()->findAll($criteria);

		$resStr = '';
		foreach ($countries as $country) {
			$resStr .= $country->c_name."\n";
		}
		echo $resStr;
	}
}

Здесь мы проверяем, пришли ли параметры и формируем запрос.

Условие записываем с помощью класса CDbCriteria. В атрибуте condition указываем название поля и операцию сравнения (LIKE). В атрибуте params – текст, введенный пользователем. Обратите внимание, мы добавляем к нему знак %, т.е. найдены будут все страны, названия которых начинаются с указанных букв.

Затем добавляем параметр limit и выполняем запрос (findAll).

Из результатов поиска формируем строку с найденными названиями стран. Разделителем служит символ новой строки (это требование плагина). И отправляем результат браузеру.

Как видите, пользоваться виджетом совсем не сложно.

Все вопросы, советы и замечания пишите в комментариях.

Удачи!

Понравилась статья? Подписывайтесь на продолжение rss link !

Или на мой твиттер twitter link

]]>

Добавьте эту страницу в google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

]]>

Опубликовано в MySQL, PHP, Web разработка, Yii Комментарии (22) »

]]>

Вы можете оставить комментарий. Трекбеки закрыты.

  • SamDark

    У CDbCriteria есть метод addSearchCondition. С ним будет немного чище.

  • test10

    demo?

  • http://www.simplecoding.org Владимир

    Спасибо!

    Получилось так

    $criteria->addSearchCondition('c_name', $_GET['q'].'%', false);

    если оставить с дефолтными настройками
    $criteria->addSearchCondition('c_name', $_GET['q']);
    то % будет добавлен с обоих сторон, а это не совсем то, что хотелось получить :)

  • http://www.simplecoding.org Владимир

    Не вижу смысла. Все-равно код придется переделывать под конкретную БД.

  • Michael

    Спасибо, очень нужная вещь

  • http://werewolf.name Werewolf

    По-моему из $_GET['q'] надо удалять %, иначе передадут % и будет ошибка.
    Вы еще не используете gii для кодогенерации?

  • http://www.simplecoding.org Владимир

    Согласен, проверять полученные данные нужно обязательно.
    gii попробовал, но особых преимуществ пока не почувствовал.

  • Storm

    Спасибо! Статья как раз вовремя :)
    Попутно возник вопрос:
    не подскажете как можно в ajax-запросе передать кроме содержимого поля, значение выпадающего списка, расположенного на той же форме, где поле с автодополнением?

    У CAutoComplete есть параметр extraParams (http://www.yiiframework.com/doc/api/CAutoComple…), который позволяет в ajax-запросе передавать дополнительные параметры. А вот как в него загрузить значение <select> что-то не соображу :|

  • http://newbisnes.ru Vetal

    Спасибо за интересный примерчик! Думаю, пригодится!

  • http://www.simplecoding.org Владимир

    Судя по всему, CAutoComplete немного урезает возможности плагина Autocomplete.

    В документации сказано, что параметру extraParams можно передавать функцию. Но если передать функцию в настройках CAutoComplete, то она будет взята в кавычки, т.е. станет обычной строкой.

    Поэтому решение такое.

    Написать свой js скрипт с кодом

    jQuery("#country").setOptions({
    'extraParams':{'mypar':function() {return $("#myselect").val();}}}
    );

    country – id поля с автозавершением,
    myselect – id выпадающего списка.

    Подключить этот скрипт с помощью registerClientScript()

  • Storm

    Большое спасибо! Если бы сам и додумался, то еще не скоро :)

  • Jay

    Конечно круто кодить только на PHP не пользуясь JavaScript, но посмотрите на то что пишет Yii в JavaScript. Иногда гораздо легче реализовать простые Ajax запросы методом jQuery – $('#element').load('?r=controller/action',{var:value});

  • http://www.simplecoding.org Владимир

    Я согласен. Но никто не запрещает использовать вместе с Yii свои скрипты, если код, который генерирует Yii вас не устраивает.

  • Pingback: Yii - CAutoComplete | Блог об интересах

  • Roe-ru

    Сходу, не получилось..
    Владимир, уточните пожалуйста, может не так понял:
    в виджете: 'name'=>'test1', – это название html input(а)
    тогда в методе:
    $criteria->condition = 'cat_name LIKE :test1';
    $criteria->params = array(':test1'=>$_GET['q'].'%');
    Спасибо.

    • Roe-ru

      прошу прощения, все работает.

  • Refresh-2004

    Всё работает, НО появилась следующая проблема:
    Вводим кусочек слова, выдало нормальный список с вариантами! вводим что-то другое, выдаёт предыдущий результат, причём даже до контролера не доходит запрос!!! Где-то каким-то образом кэшируются данные!! вопрос где и какого лешего?! Проходит, ну не знаю, минуты 2-5, не засекал, вводим поиск и опять выдаётся нормальный результат… и всё повторяется заново!! Помогите плиз!!!

    • http://www.simplecoding.org Владимир

      Попробуйте добавить GET параметр со случайным числом. На серверной стороне просто его игнорируйте.

  • Castortroy06

    у меня проблема. после того, как сработал autocomplete, yii ругается на незаполненное поле(то, которое работает с autocomplete)

    • http://www.simplecoding.org Владимир

      Проверьте firebug'ом уходят ли данные на сервер. Дело в том, что autocomplete просто вставляет текст в поле, а при отправке формы не играет роли каким образом было заполнено поле, с клавиатуры, копипастом или с помощью autocomplete.

  • http://www.facebook.com/miroslav.chandler Miroslav Demchun

    $criteria->limit = $_GET['limit'];
    А если я передам 1000?
    Лимит – нужно задать в скрипте.

    • http://www.simplecoding.org Владимир

      Наверное, лучше поставить ограничение по максимальному значению.
      $criteria->limit = ($_GET['limit'] < 100) ? $_GET['limit'] : 100;

]]>
Tweet