Наверх

Как сделать зависимые Ajax-списки

Данный пример покажет возможность создания зависимых выпадающих списков в форме поиска каталога.

Внимание!
Пример применим для небольшого массива данных. Если планируется большой список зависимых значений (скажем, больше 100), то лучше применить другое решение.

Рассматривать пример будем с использованием установленных демо-данных, а именно на примере «Бумажного зоопарка».

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

Добавим в каталоге новую характеристику с типом «выпадающий список» и внесем данные. В результате получаем следующее:

Материк

Добавим аналогичную характеристику для стран.

Зависимость характеристик будем хранить в дополнительном поле таблицы {shop_param_select}, которая содержит все значения выпадающих списков. Подробнее о структуре таблицы можно узнать в разделе Структура базы данных DIAFAN.CMS.

Выполним следующий SQL-запрос, например в phpMyAdmin:

Пример:

ALTER TABLE `diafan_shop_param_select` ADD `parent_param_id` INT(11) NOT NULL

Теперь откроем файл modules/shop/admin/shop.admin.param.php, который отвечает за вывод подробного описания характеристики в административной части.

Понадобится нам метод edit_variable_param_select(), отвечающий за редактирование характеристики.

Найдем в методе следующие строки:

if (in_array($this->diafan->values("type"), array('select', 'multiple')))
{

и после них добавим:

Пример:

if($this->diafan->id == 12)
{
    
$mainland = array();
    
$rows = DB::query_fetch_all("SELECT id, [name] FROM {shop_param_select} WHERE param_id=%d", 11);
    foreach(
$rows as $row)
    {
        
$mainland[$row['id']] = $row['name'];
    }
}

Здесь мы проверяем, что в данный момент открыта нужная характеристика. Нужная в нашем случае «Страна» с ID, равным 12.

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

Далее из таблицы {shop_param_select} выбираются все значения характеристики, они же значения выпадающего списка, с ID равным 11, т.е. материки. Полученные данные записываются в массив $mainland в виде id_значения => имя_значения.

Теперь выведем данный массив в виде выпадающего списка.

В этом же методе, в цикле, начинающемся с

foreach ($value as $row)
{

после строки

<input type="text" name="param_rewrite[]" size="20" value="'.$row["rewrite"].'">

напишем

Пример:

';
if($this->diafan->id == 12)
{
     $selected = DB::query_result("SELECT parent_param_id FROM {shop_param_select} WHERE id=%d AND param_id=%d", $row["id"], 12);
     echo '
<select name="mainland'.$row["id"].'">';                            
     foreach($mainland as $key=>$value)
     {
         echo '
<option value="'.$key.'" '
         .($selected == $key ? '
selected' : '')
         .'
>'.$value.'</option>';
     }
         echo '
</select>';
     }
echo '

Здесь мы опять проверяем, что находимся в нужной характеристике, а далее циклом формируем выпадающий список на основе полученного ранее массива $mainland.

Обратите внимание на имя списка "mainland".$row["id"]. Здесь $row["id"] — это значение ID текущего элемента, выпадающего списка «Страна».

При этом в каждой итерации делаем сравнение значения нового поля parent_param_id, которое хранится в $selected, с $key. В $key находится ID элемента выпадающего списка «Материки». Если значения совпали, то добавляем к текущему пункту атрибут selected, т.е. делаем его выбранным.

Теперь характеристика «Страна» примет такой вид.

Страна

Мы добились вывода списка материков, но не сделали их сохранение. За сохранение характеристик отвечает метод save_variable_param_select(). Немного его модифицируем. Перед

$ids[] = $id;

добавим

Пример:

if(!empty($_POST['mainland'.$id]))
{
    
DB::query("UPDATE {shop_param_select} SET parent_param_id=%d WHERE id=%d AND param_id=%d", $_POST['mainland'.$id], $id, 12);
}

В данном коде нет ничего сложного — проверяется наличие переменной mainland и выполняется обновление нового поля parent_param_id.

Административная часть теперь вполне функциональна и удобна.

Перейдем к пользовательской части.

Для начала выведем характеристики «Материк» и «Страна» в форме поиска в виде выпадающего списка.

Внимание!
По умолчанию все выпадающие списки выводятся в виде чекбоксов, чтобы дать пользователю возможность выбора сразу нескольких значений.

Для этого в файле modules/shop/views/shop.view.show_search.php код

Пример:

case 'select':
case
'multiple':
echo
'<span class="infofield">'.$row["name"].':</span>';
foreach (
$row["select_array"] as $key => $value)
{
    echo
'<input type="checkbox" name="p'.$row["id"].'[]" value="'.$key.'"'.(in_array($key, $row["value"]) ? " checked" : '').' class="inpcheckbox"> '.$value.'<br>';
}

заменим на

Пример:

case 'select':
case
'multiple':
if(
$row['id'] == 11 || $row['id'] == 12)
{
    echo
'<span '.($row['id'] == 12 ? 'style="display: none;" class="country"' : 'class="mainland"').'>
    <span class="infofield">'
.$row["name"].':</span>
    <select name="p'
.$row["id"].'[]">';
    echo
'<option value="0">-</option>';
    foreach (
$row["select_array"] as $key => $value)
    {
        echo
'<option value="'.$key.'"'.(in_array($key, $row["value"]) ? " selected" : '').'>'.$value.'</option>';
    }
    echo
'</select></span>';
}
else
{
    echo
'<span class="infofield">'.$row["name"].':</span>';
    foreach (
$row["select_array"] as $key => $value)
    {
        echo
'<input type="checkbox" name="p'.$row["id"].'[]" value="'.$key.'"'.(in_array($key, $row["value"]) ? " checked" : '').' class="inpcheckbox"> '.$value.'<br>';
    }
}

В данной части кода проверяются ID характеристик. Если это нужные нам 11 или 12, формируем выпадающий список, иначе выводим характеристику по умолчанию, т.е. чекбоксами.

При этом характеристику «Страна» делаем скрытой.

Следующим шагом будет создание метода отправки POST запроса при выборе значения характеристики «Материк».

Откроем файл modules/shop/js/shop.show_search.js и в самый конец добавим

Пример:

$(".mainland select").change(function(){
    var
selected = $(".mainland select option:selected").val();
    $(
'.country select option').remove();
    $.
ajax({
        
type: "POST",
        
url: "",
        
data: "module=shop&action=change_country&mainland=" + selected,
        
success: function (response, textStatus)
        {
            $(
".country select").append($(response));
            $(
".country").show();
        }
    });
});

Про метод ajax библиотеки jQuery написано очень много статей, поэтому найти его описание не составит труда. Мы же остановимся на переменных, которые передаются системе управления.

module=shop — сообщает, что обращаемся мы к файлу modules/shop/shop.action.php.

action=change_country — здесь в произвольной форме указываем имя метода, который будет обрабатывать запрос (создадим мы его чуть позже).

mainland= + selected — текущее значение выпадающего списка.

Перейдем к написанию обработчика.

Сначала в файле modules/shop/shop.php в метод action() добавим после

Пример:

switch ($_POST['action'])
{

добавим

Пример:

case 'change_country':
return
$this->action->change_country();

Теперь в файле modules/shop/shop.action.php добавим новый метод:

Пример:

public function change_country()
{
    
$text = '<option value="0">-</option>';
    
$rows = DB::query_fetch_all("SELECT id, [name] FROM {shop_param_select} WHERE parent_param_id=%d", $_POST['mainland']);
    foreach(
$rows as $row)
    {
        
$text .= '<option value="'.$row['id'].'">'.$row['name'].'</option>';
    }
    echo
$text;
}

В данном методе происходит выборка элементов выпадающего списка на основе полученного значения ID материка, которое хранится в $_POST['mainland'].

Далее формируется выпадающий список и происходит его вывод.

Список

Ваши комментарии и дополнения

В IE Может не работать этот момент, исправляем точный путь к сайту в параметре url в js-скрипте и всё работает!
И действительно, в IE не работает. Есть ли инфо, почему не работает в InternetExplorer-е?
Зарегистрируйтесь или авторизируйтесь для того, чтобы оставить комментарий.